级别: 中级 Alister Lewis-Bowen, 高级软件工程师, IBM Stephen Evanchik, 软件工程师, IBM Louis Weitzman, 高级软件工程师, IBM
2007 年 5 月 10 日 在这个 系列 中,IBM® Internet Technology Group 团队要使用一套可免费获得的软件来设计、开发和部署一个完整的社区 Web 站点。在前面的文章中,讨论了如何扩展和配置 Drupal 来满足新的 Web 站点的需要。随着内容的增加,就需要对信息结构进行正规化。在本文中,讨论这个团队对 Drupal 提交的内容进行结构化的方式和关键方法。
简介
本系列的 第 2 部分 描述了这个团队使用什么技术来了解虚构的 International Business Council(IBC)公司 Web 站点的受众的本质。通过使用纸上原型等技术,我们测试了页面布局和用户交互。这个阶段为将可视元素组合成布局提供了基础知识,使我们可以开始创建显示信息所用的基本样式。在本文和下一篇文章中,您将了解我们如何为 IBC Web 站点构造定制的主题。
 | | 在第 8 部分中,将讲解如何应用样式来完成 Web 站点的主题化。 |
|
本文中的信息不应该解释为严格的开发规则,而是应该作为创建 Web 站点结构时的起点。
在本文中,请跟着我们在 Drupal 中创建一个主题,关注的重点是帮助实现以下特性的方法:
- 内容片段的模板
- 独立的主页布局
- Web 站点部分标识
- 动态地更新导航
- 适应非传统浏览器
- 按照上下文放置的操作
- 突出显示的内容区域
尽管许多这些概念基于现有的实践和当前的基于标准的 Web 设计,但是我们希望本文能够让您对在 Drupal 上下文中改进内容结构的方法有所了解。
通过体验进行改进
在开始创建定制的主题时,我们还不了解许多可用的特性。我们常常先快速创建一个并不完善的解决方案,以后再寻找更好的方式。我们仍然在不断地研究。这是一个重要的概念,常常可以非常快地组装出 Web 站点的 “外观”,并随着您越来越熟悉 Drupal,逐渐调整它。
在讨论了我们的方法之后,您将了解我们如何从最初的解决方案发展到更好、更系统化的方法。
基于标准的 Web 设计
许多图书和 Web 站点讨论了基于标准的 Web 设计的当前趋势。这种方法学的一个基本部分是恰当地 应用 XHTML 和 CSS。Drupal 主题系统具有的灵活性使 Web 站点设计人员可以轻松地适应这些标准。
对 IBC Web 站点的结构和样式使用基于标准的方式,这使我们能够创建具有以下性质的健壮的设计:
- 能够跨现代 Web 浏览器、屏幕阅读器和无线设备工作
- 减少浏览器下载并显示页面所花费的时间
- 支持灵活的布局,用户可以增加或减小浏览器窗口的大小或字体大小
- 为 Web 站点上的任何内容创建可接受的打印形式
- 在老式浏览器中显示时,允许内容平稳地退化
我们创建 IBC Web 站点的方式符合基于标准的 Web 设计,但本文的意图并不是解释这些标准,而是要创建一个新的定制主题。
创建新的主题
为了开始创建新的主题,团队复制了主题目录中的 Bluemarine 目录并将它重命名为 ibc。这是 Drupal 附带的默认的 phptemplate 引擎主题,可以以它为基础创建自己的定制主题。这个新目录显示在 Eclipse 环境中,见 图 1。
图 1. Navigator 视图,新的 IBC 主题目录
还可以使用其他主题引擎。根据定义,如果在主题目录中使用 .tpl.php 文件,Drupal 就知道应该使用 phptemplate 引擎。如果使用 .xtmpl 文件,Drupal 就会使用 xtemplate 引擎。还可以使用 .theme 文件,在其中可以覆盖任何 PHP 主题函数。关于这个领域的更多信息,请参考 Drupal theming overview。
为了让这个主题在 Web 站点上生效,需要通过 admin/themes 页面启用它。Drupal 会列出在 Themes 目录中找到的所有主题。可以启用并默认选择 ibc 主题,如 图 2 所示。
图 2. 选择 IBC 主题
缩略图表示主题外观的屏幕图,这由主题目录中的 screenshot.png 文件控制。可以为自己的主题创建图像,但是只有在建立所需的外观之后才可以。
图 2 中的 Configure 选项卡使管理员能够修改所有主题的设置或特定主题的设置。对于特定的主题,可以启用或禁用 Drupal 提供给主题使用的内容元素。
在 Configure 选项卡中的 Toggle display 组中列出了许多可以启用或禁用的内容元素,如 图 3 所示。mission statement 是管理员在 admin/settings 页面的 General Settings 中定义的一个元素。如果启用了它的话,主题引擎将把这个文本字符串作为变量($mission)传递给页面模板(见 清单 1)。在创建定制主题时,由主题设计人员决定如何显示以及是否显示这些页面元素。
图 3. IBC 主题的 Configuration 选项卡
内容结构
就像粉刷房间一样,许多工作都是在准备阶段完成的。开始粉刷之前,需要填补各处的窟窿和缝隙,然后打磨平整。这些工作做得越完善,刷漆就越容易,房间就会越漂亮。所以,在对 Web 站点应用样式之前,希望确保内容具有良好的结构。本文的其余部分描述如何在主题中构建 XHTML,使 CSS 样式化过程更加容易。
基本布局
Web 站点的基本布局由 图 1 中创建的主题目录中的 page.tpl.php 文件控制。可以在这里开始定义基本结构,这个结构将包围节点模板文件定义的内容片段。清单 1 展示了我们如何在 page.tpl.php 文件中开始建立布局。在详细讨论 IBC 主题的基本内容结构时,我们会回顾这个文件。
清单 1. page.tpl.php 中的基本页面布局
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
lang="<?php print $language ?>;"
xml:lang="<?php print $language ?>">
<head>
<title><?php print ( $is_front ? "Home | International Business Council (IBC)"
: $head_title ); ?></title>
<?php print $head ?>
<link rel="stylesheet" type="text/css" media="screen"
href="themes/ibc/c/screen.css" />
</head>
<body>
<div id="wrap">
<div id="header">
<div id="banner">
<h1>International Business Council</h1>
</div>
<div id="nav_bar">
</div>
</div>
<div id="content">
<div class="tabs"><?php print $tabs ?></div>
<?php print $help ?>
<?php print $messages ?>
<?php if ($is_front) { : ?>
<?php print announcement_all(); ?>
<?php print discussions_all(); ?>
<?php else : ?>
<?php print $content; ?>
<?php endif; ?>
</div>
<div id="sidebar">
<?php print $sidebar_right; ?>
</div>
<div id="footer">
</div>
</div>
<?php print $closure;?>
</body>
</html>
|
有效的容器
最好确保 XHTML 具有良好的结构,使希望应用样式的所有元素都可以通过使用 CSS 选择器访问到。当然,这并不意味着应该将所有东西都包围在 DIV 或 SPAN 元素中。按照语义标记的思想,我们尽可能使用与内容的用途相适应的恰当的 XHTML 元素。只在需要在内容中定义逻辑分隔时,才会使用 DIV 和 SPAN 元素。在 清单 1 中,应该能够看出 header、content、sidebar 和 footer 的容器。
标识符和类
对于布局,我们主要使用 ID 属性;对于重复的元素或者使用 CSS 选择器难以识别出的元素,使用 class 属性。在 清单 1 中可以看出,内容的主要逻辑块使用标识符表明它们在布局中的用途;例如,<div id="content">。<div class="tab"> 使用 class 属性,而这里似乎应该使用 ID 属性。这是来自 Bluemarine 主题的一个现有样式值,我们决定保留它。
为了标识特定模板文件生成的内容区块,我们在包含它的元素中使用一个描述内容片段的 class 属性。例如,我们决定将 announcement_compact.tpl.php 定义的内容包围在一个 DIV 元素中,这个元素的 class 属性值是 announcement_summary。这种方式有助于进行调试,因为很容易看出哪个模板控制哪块内容。在后面讨论主题中的特定模板时将会看到这一点。
变量和区域
在 清单 1 中,可以看到具有 $language、$is_front、$title_head 等名称的变量。当 phptemplate 引擎调用模板文件时,它向模板提供变量,这些变量可以在 Drupal 设置页面中定义,在主题配置中启用和禁用。可用变量 可以插入模板中的适当位置。
区域(Region)
是 Drupal 显示主题化区块和节点内容的地方。$sidebar_$left、$sidebar_right、$content、$header 和 $footer_message 是包含标准区域的内容的变量。还可以使用主题的 _regions 钩子定义定制的区域。这些主题化内容的集合提供了方便的容器,主题设计人员可以将它们定位在页面布局中。
主页的结构
与大多数 Web 站点一样,主页(即首页)常常具有与其他页面不同的布局。通过在 page.tpl.php 文件中使用 $is_front 变量,可以控制要显示的各种元素,比如对 title 元素进行修改,见 清单 2。
清单 2. 使用 $is_front 变量修改主页的标题
<title><?php print ( $is_front ? "Home | International Business Council (IBC)"
: $head_title ); ?></title>
|
对于 IBC Web 站点,我们需要显示公告的列表和论坛中最近的文章。为了区分主页的布局和其他页面的布局,我们在页面的主体中使用一个条件语句,见 清单 3。
清单 3. 使用 $is_front 变量修改主页的内容
<?php if ($is_front) { : ?>
<?php print announcement_all(); ?>
<?php print discussions_all (); ?>
<?php else : ?>
<?php print $content ?>
<?php endif; ?>
|
这样,就可以根据页面模板是否用于主页来控制显示哪些内容。如果 $is_front 是 true,那么就调用正确的模块函数,比如调用 announcement 模块中的函数显示公告的列表。如果 $is_front 是 false,就显示 $content 变量,这个变量中包含 Drupal 在节点构建序列中组装好的主题化节点集合。
登录页面
IBC 站点的需求之一是要求对用户进行身份验证,然后才能显示内容。通常,完整的社区站点或外部网站点会向未经过身份验证的用户显示一个登录页面,而不是主页。
因为我们正在讨论 page.tpl.php 文件,所以解释我们对这个问题最初的解决方案可能是有帮助的。这个解决方案没有考虑到会话过期,而且不太优雅,但是能够起作用。(在以后的一篇文章中将描述一个更好的方法,但是在这里给出最初解决方案可能更有意思。)
清单 4 中的代码放在 清单 1 所示的 page.tpl.php 文件中 DOCTYPE 元素的前面。只有在当前用户已经通过身份验证时,才会设置 $user->uid 变量。我们通过这个检查决定是否包含另一个模板文件,从而显示登录页面,然后跳出 page.tpl.php 文件。login.tpl.php 文件显示登录页面,其中包含一个从用户登录区块复制的登录表单。
清单 4. 检查用户是否通过了身份验证,否则显示登录页面
<?php
global $user;
if (!$user->uid) {
include('login.tpl.php');
return;
}
?>
|
位置标识
在一个文件中维护 Web 站点页面的基本布局是有好处的,但是如果希望标识 Web 站点的不同部分,该怎么办?例如,您可能希望向用户提供当前部分的可视线索。我们使用 URL 在 body 元素中设置 class 值,这样就可以适当地对页面应用样式。一种实现方法是直接在 class 属性值中输出 Drupal arg 函数的值,见 清单 5。但是,这没有提供我们需要的控制能力。
清单 5. 在 body 元素中添加 class 值
<body class="<?php print arg(0); ?>" >
|
我们使用一个简单的 switch 语句,以更强的控制能力定义 class 值。在 清单 6 中,switch 语句根据 URL 路径的第一部分决定要使用的值。这会提供一个 CSS 类,我们可以使用它根据显示的 Web 站点部分改变页面的显示方式。
清单 6. 在 body 元素中添加定义的 class 值
<?php
switch(arg(0)) {
case 'workgroups':
$page_type = 'workgroups';
break;
case 'action_items':
$page_type = 'workgroups';
break;
case 'conferences':
$page_type = 'conferences';
break;
case 'agenda_items':
$page_type = 'conferences';
break;
case 'members':
$page_type = 'members';
break;
default:
$page_type = 'home';
}
?>
<body class="<?php print $page_type; ?> <?php print arg(0); ?>" >
|
当然,我们在 admin/settings 页面中配置了 clean URLS,而且 Web 站点每个部分的模块向 Drupal 菜单系统注册了 URL,这样就可以可靠地从 URL 探测站点部分。另一种实现方法是使用 taxonomy 模块判断要显示哪一部分,这将在以后的一篇文章中讨论。
动态导航
我们的主导航结构需要根据 Web 站点的数据库内容而变化。例如,在 Workgroups 部分下面,我们需要列出活跃的工作组;但是在 Conferences 部分下面,需要列出最近两年的研讨会。清单 7 显示一个无序列表,它根据这些需求创建主导航内容的结构。这个列表放在 nav_bar DIV 中,见 清单 1。在清单 7 中可以看到,对于 Workgroups 和 Conferences 部分,workgroups 和 conference 模块中的一个函数提供一个条目列表,这些条目会显示为列表项。
清单 7. 建立主导航的结构
<ul id="pri_nav">
<li id="t_home"><a href="" accesskey="1"
title="The IBC home page">Home</a></li>
<li id="t_workgroups"><a href="workgroups"
title="IBC Workgroups and status">Workgroups</a>
<ul>
<li><a href="workgroups" title="View all Workgroups">All Workgroups</a></li>
<?php
$workgroups = workgroup_nav_list();
foreach ($workgroups as $wg) : ?>
<li><a href="workgroups/<?php print $wg->nid; ?>"
title="Jump to $wg->title"><?php print $wg->title; ?></a></li>
<?php endforeach; ?>
</ul>
</li>
<li id="t_conferences"><a href="conferences/" title="IBC Conference
information">Conferences</a>
<ul>
<li><a href="conferences/" title="View all Conferences">All Conferences</a></li>
<?php
$conferences = conference_nav_list();
foreach ($conferences as $c) : ?>
<li><a href="conferences/<?php print $c->nid; ?>"
title="Jump to $c->title"><?php print $c->title; ?></a></li>
<?php endforeach; ?>
</ul>
</li>
<li id="t_members"><a href="members" title="IBC Members and contact
information">Members</a>
<ul>
<li><a href="members" title="All Members">All Members</a></li>
<li><a href="members/bycompany" title="By Company">By Company</a></li>
<li><a href="members/byconference" title="By Conference">By Conference</a></li>
<li><a href="members/byworkgroup" title="By Workgroup">By Workgroup</a></li>
<li><a href="members/workgroupleaders" title="Workgroup Leaders">Workgroup
Leaders</a></li>
<li><a href="members/abcstaff" title="IBC Staff">IBC Staff</a></li>
</ul>
</li>
</ul>
|
正如在 清单 7 中看到的,额外的嵌套列表被嵌入 Workgroups 和 Conferences 的列表项元素。这些列表包含由一些 PHP 生成的动态内容。下一篇文章将解释如何对这个结构应用样式,从而为主导航生成下拉菜单。
适用于非传统浏览器的内容
由于用户可能通过非传统浏览器查看 IBC 内容,为了适应这种情况,我们包含了额外的内容结构以便提供更广泛的可访问性。我们添加了访问键、到内容布局的某些主要部分的链接以及标识这些主要部分的标题。
为了向用户说明在 Web 站点页面布局中使用的访问键,我们在页面顶部添加一个解释性文本的容器,就放在 清单 1 中 BODY 元素后面。下面的 清单 8 显示这块额外的内容结构。
清单 8. ALT 键的解释性文本放在 BODY 元素后面
<div id="access-info">
<p class="access" >The access keys for this page are:</p>
<ul class="access">
<li>ALT plus 1 links to the IBC home page.</li>
<li>ALT plus 2 links to the site map for the IBC web site.</li>
<li>ALT plus 3 skips to the start of the content on this page.</li>
<li>ALT plus 9 links to the contact page.</li>
</ul>
</div>
|
使用 accesskey 属性在相关联的链接中实现访问键。清单 9 显示几个示例。
清单 9. 页面模板中访问键的示例
<li><a href="sitemap" accesskey="2"
title="An index to the whole of this web site">Site map</a></li>
<li><a href="contact" accesskey="9"
title="Contact information for the IBC web site">Contact</a></li>
|
清单 10 用几个示例展示如何插入额外的内容结构,从而标识页面布局的主要部分并添加到页面内容开头的链接。注意 class 值 access,它使 CSS 能够对传统浏览器隐藏这些额外的内容结构。
清单 10. 用来标识页面模板中的部分的标题
<div class="access">
<p><a href="<?php print request_uri(); ?>#page-content"
accesskey="3">Jump to the start of the content on this page</a></p>
</div>
.
.
.
<h2 class="access">Start of main page navigation</h2>
.
.
.
<div id="content">
<h2 id="page-content" class="access">Start of the main page content</h2>
.
.
.
|
当然,还应该使用其他结构化技术,比如在 IMG 元素中包含 alt 属性以帮助解释图像的用途。在锚元素(<A>)中放置 title 属性也可以在 Drupal 中实现,方法是将它包含在 l 函数的属性数组中,见 清单 11。
清单 11. 在链接中添加 title 属性
$links[] = l(t('Edit'),
"announcement/$node->nid/edit",
array('title' => t('Display the edit form for this announcement')));
|
为了保证表单的可访问性,Drupal 在使用 form API 时会在表单元素前面加上 LABEL 元素。
那么,我们如何定制在页面模板中插入的这些内容片段的结构呢?使用内容片段模板(content fragment template)。
内容片段模板
phptemplate 引擎使用 node.tpl.php 作为一般性模板,主题设计人员可以使用它将任何生成的节点数据放进内容片段。对于使用多种节点类型的站点,主题设计人员可以使用 node-<node-type>.tpl.php 模板文件控制特定节点类型的数据的显示。
在这个系列的 第 6 部分 中,您了解了 IBC Web 站点的定制模块如何支持在三个不同的上下文中显示数据:详细的布局、总结和区块。图 4 和 图 5 显示这些上下文的示例,这些内容可以插入页面模板中。当节点构建序列从 URL 得知需要构建公告页面(见 图 4)时,Drupal 就会组装这个页面中需要的各个节点片段并进行主题化,然后将它们放进页面模板中。
在图 4 中,标有字母 A 的框中的内容片段是由节点系统使用 node-announcement.tpl.php 模板(见 清单 14)构建的,用来建立公告数据的结构。标有字母 C 的区域中的内容是由 announcement 模块的 block 钩子使用 announcement_block_list.tpl.php 模板构建的,用来建立区块数据的结构。
图 4. 公告页面上下文,包含详细布局和公告区块
在 图 5 中,标有字母 B 的内容区域显示公告总结内容片段,这是由 announcement 模块中的 announcement_all 函数使用 announcement_compact.tpl.php 模板构建的。
图 5. 主页上下文,包含总结布局和公告区块布局
如 图 5 所示,我们使用模板将这些上下文的结构和样式与创建数据的模块分隔开。为了显示详细视图,我们使用了 node-<node-type>.tpl.php 模板文件。但是,为了在每个节点类型自己的模板文件中创建一个模板对总结和区块上下文进行主题化,我们使用了 第 6 部分 中描述的一个方法。
在对 Drupal 中的数据进行主题化时,要使用 theme(<theme_function_name>, <data>) 函数,这里的 theme_function_name 是一个用来标识主题函数的字符串。Drupal 使用一个排除过程决定应该使用哪个函数传递这一数据,从而生成主题化的输出。图 6 显示这个过程。
图 6. Drupal 寻找主题函数的方法
因此,模块开发人员可以使用一个 phptemplate 特有的函数覆盖默认的主题函数。现在,在这个 phptemplate 主题函数中,我们使用 _phptemplate_callback 函数指示 Drupal 主题系统使用一个用 theme_function_name 构造的模板文件。因此,清单 12 这样的主题调用将使用模板文件 announcement_compact.tpl.php。
清单 12. 在 announcement.module 中对公告总结进行主题化
$page_content[] = theme('announcement_compact', $announcement);
|
在 第 6 部分 的 hook_nodeapi 小节中,我们讨论了模块开发人员如何为任何 theme_function_name 创建 <theme_function_name>-<node-type>.tpl.php。按照这种方法,可以使用希望使用的任何 block-<node-type>.tpl.php 文件。
公告的模板
我们来看看使用 第 6 部分 描述的 announcement 模块的三个上下文所用的模板。
公告细节
我们使用 node-announcement.tpl.php 模板文件为完整公告的内容片段建立结构。这个内容片段出现在显示单一公告的页面上(图 4 中的 A 部分)。Drupal 节点构建系统将 节点对象 传递给这个模板,从而提供可以插入 XHTML 结构的变量。
要检查这些变量的内容,可以在模板中使用 print_r 函数,见 清单 13。保存模板文件,然后查看包含这个模板的 Web 页面。将显示 $node 的内容。在编写 PHP 时,这个函数是一个简单但很有帮助的调试工具。
清单 13. 显示节点对象的内容
<?php print print_r($node); ?>
|
在 清单 14 中可以看到如何构建完整的公告。模板中的 PHP 代码专门用来将数据转换为结构良好的 XHTML 内容片段,从而可以使用 CSS 轻松地应用样式。(本系列中的下一篇文章将详细描述样式化过程。)
清单 14. node-announcement.tpl.php 模板
<?php
global $user;
$published = format_date($node->publish_date,'custom','j M, Y');
$expires = format_date($node->expiration_date,'custom','j M, Y');
?>
<?php if ($page or $page == 0): ?>
<h2 class='category'>Announcement</h2>
<?php endif; ?>
<div class="announcement_detail">
<h3><?php print $title ?><?php print $links ?></h3>
<p class="date">Posted on <?php print $published; ?>
<?php
if ($user->uid == $node->uid or user_access('edit announcement')) {
if ($node->expiration_date < time()) print " and expired on ".$expires;
else print " and going to expire on ".$expires;
}
?>
</p>
<?php if ($node->abstract) : ?>
<div class="abstract"><?php print $node->abstract ?></div>
<?php endif; ?>
<?php if ($node->body) : ?>
<div><?php print $node->body ?></div>
<?php endif; ?>
<?php
if ($node->attachments != NULL) {
print filegallery_attachments_display($node);
}
?>
</div>
|
这段代码首先对发布日期和过期日期进行转换,以便在模板中使用。然后,输出 <h2 class='category'>Announcement</h2>,这是这部分内容的介绍性标题。
接下来,生成一个 DIV 元素,它作为内容片段的有效容器,并由 class 属性值 announcement_detail 标识。这提供了一个类名,可以利用它对片段中的内容应用样式。
 | 根据 drupal.org 的建议,要想获得一个完整填充的 $user,应该使用 user_load() 函数。 |
|
然后,输出标题和 announcement_link 函数生成的 $links 内容。这会在公告标题旁边显示我们所说的 “操作链接”。Drupal 的默认选项卡式界面可以向用户提供操作节点的方法。但是,我们不采用这个界面,而是希望将这些操作(比如 Add、Eedit 和 Delete)放在它们影响的内容旁边,见 图 7 中的红色链接。
图 7. 公告标题旁边的操作链接
您可能会注意到,我们在
Posted on
行上显示了一些额外的信息。在 清单 14 中,使用一个条件语句显示这些额外的过期信息。它检查当前用户是否是公告的作者或者具有编辑访问特权。这需要使用全局的用户数据对象($user)和 user_access 函数。我们以此为例说明如何在模板文件中使用不同的数据对象和辅助函数。
这个清单的其余部分输出公告的摘要、主体和任何附件。构造 XHTML 的方式使它在语义和结构上都是有效的。如果某段数据不可用,那么就从产生的内容片段中去掉包含它的整个 XHTML 元素。例如,将包含摘要文本的 DIV 元素放在 PHP 条件语句 <?php if ($node->abstract) : ?> 中,这确保只有当 $node->abstract 存在时才会显示这一内容。
公告总结
我们使用 announcement_compact.tpl.php 模板文件为公告总结的内容片段建立结构。当列出多个公告时会使用这个内容片段,比如在主页或公告页面上,见 图 5 中的 B 部分。
在 清单 15 中,我们为这个对象建立一个有效容器,并用 class 属性值 announcement_summary 标识它。您会注意到,这里还有另外两个可能包含的 class 属性值:sticky 和 hl_yellow。
清单 15. announcement_compact.tpl.php 模板
<?php global $user; ?>
<div class="announcement_summary<?php print ($node->sticky) ? " sticky" : ""; ?>
<?php print ($user->uid == $node->uid) ? " hl_yellow" : ""; ?>">
<h3>
<a href="<?php print $node->url ?>"
title="Read more about this announcement"><?php print $title ?></a>
<?php print $links ?>
</h3>
<p class="date">Posted on <?php print $published; ?>
<?php
if ($user->uid == $node->uid or user_access('edit announcement')) {
if ($node->expiration_date < time()) print " and expired on ".$expires;
else print " and going to expire on ".$expires;
}
?>
</p>
<?php if ($abstract) : ?>
<div class="abstract">
<?php print $abstract ?>
<a class="more" href="<?php print request_uri(); ?>/<?php print $node->nid ?>"
title="Read more">more »</a>
</div>
<?php endif; ?>
</div>
|
在编辑公告时,表单的 Publishing options 部分允许管理员在节点上设置 sticky 标志。公告在默认情况下是按照时间次序排列的,通过在 announcement 模块中使用这个标志,我们可以覆盖这个次序并将一些公告置顶。在这里,我们用 DIV 元素中的一个 class 属性值标识出置顶的公告。$node->sticky 变量是在 phptemplate_announcement_compact 函数中传递给这个模板的(见 第 6 部分)。
如果当前用户的 ID 与公告的关联用户 ID 相同,那么就包含 hl_yellow 类。这样就可以突出显示当前用户所编写的任何公告。
公告区块
我们使用 announcement_block_list.tpl.php 模板文件为公告区块的内容片段建立结构。当在每个页面的右边栏中列出最近的几个公告时,会使用这个内容片段,见 图 4 中的 C 部分和 图 5 中的 C 部分。
清单 16 中的模板对 announcement_block 函数中创建的数据进行定制。它构建一个表格式的公告列表,这将用在公告区块内容变量中。公告区块使用默认的区块布局,还可以使用 block.tpl.php 模板修改布局。
清单 16. announcement_block_list.tpl.php 模板
<?php global $user; ?>
<?php $i = 1; ?>
<table cellspacing="0">
<tbody>
<?php foreach($announcements as $a): ?>
<tr class="<?php print ($i%2) ? "" : " alt"; ?>
<?php print ($a->uid == $user->uid) ? " hl_yellow" : "" ; ?>">
<td class="col1"><a href="/announcements/<?php print $a->nid; ?>"
title="Read more about '<?php print $a->title ?>'">
<?php print $a->title; ?></a></td>
<td class="col2">
<?php print format_date($a->publish_date,'custom','j M y'); ?></td>
</tr>
<?php $i++; ?>
<?php endforeach; ?>
</tbody>
</table>
<p class="more"><a href="announcements/">View all the Announcements »</a></p>
|
这个清单中的代码稍微有点儿复杂,因为它要为每个公告构造一个表格行。每行包含两列。第一列包含公告标题,这构造成一个链接到公告的细节页面的 XHTML 锚元素。第二列包含公告的发布日期。在表格后面构造另一个锚元素,让用户能够转到列出所有公告的页面。与总结布局一样,当公告属于当前用户时,要包含 class 属性值 hl_yellow。
在 第 6 部分中,我们描述了如何使用 $announcement_block_max_list_count 变量控制在这个区块中显示的公告数量。这一逻辑包含在 announcement_block 函数中,所以只向这个模板传递适当数量的公告。
template.php 文件
在 第 5 部分 中,我们提到了 template.php 文件。这个文件可以包含覆盖现有主题函数的主题函数,它们应用于整个主题,而不是仅限于特定的节点类型。例如,需要用一个容器包围操作链接,从而帮助对这些锚元素应用特殊的样式,让它们与其他内容有所区别。
Drupal 发布版提供的 /inc/theme.inc 文件定义了 theme_links 函数。这个函数用来对 phptemplate 引擎传递给模板文件的 $links 变量进行主题化。所以,通过使用 图 6 所示的流程,我们应该能够使用 phptemplate_links 函数覆盖它。清单 17 显示这个函数,它被放在 template.php 文件中。
清单 17. 在 template.php 文件中覆盖默认的 theme_links 函数
function phptemplate_links($links, $delimiter = " ") {
return '<span class="action">'.implode($delimiter, $links).'</span>';
}
|
可以看到,这个函数仅仅用一个 SPAN 元素包围链接,并用一个 class 属性标识它。
结束语
在本文中,您学习了如何开始创建新的主题,以及在主题中为 Web 站点构造结构化 XHTML 的方法。我们描述了几种为 Web 站点内容建立结构的方法,包括总体页面布局、主页内容、主导航和标识 Web 站点部分。
在下一篇文章中,将讨论我们的团队如何使用 CSS 对结构化的 IBC Web 站点应用样式。
参考资料 学习
讨论
作者简介  | 
|  | Alister Lewis-Bowen 是 IBM 的 Internet Technology Group 的高级软件工程师。他从 1993 年开始作为 IBM 英国职员从事互联网和 Web 技术方面的工作。Alister 后来到美国为 IBM 赞助的体育活动的 Web 站点工作,之后成为 ibm.com 的高级网管。他当前正在帮助创建语义 Web 原型。可以通过 alister@us.ibm.com 联系 Alister。 |
 | 
|  | Stephen Evanchik 是 IBM 的 Internet Technology Group 的软件工程师。他是许多开放源码软件项目的代码贡献者,其中最著名的是 Linux 内核中的 IBM TrackPoint 驱动程序。Stephen 当前从事语义 Web 技术。可以通过 evanchik@us.ibm.com 联系 Stephen。 |
 | 
|  | Louis Weitzman 是 IBM 的 Internet Technology Group 的高级软件工程师。他从事设计和计算已经有 30 年了。他曾经帮助开发 ibm.com 使用的基于 XML 片段的内容管理系统,当前正在从事将设计过程融入新项目的工作。可以通过 louisw@us.ibm.com 联系 Louis。 |
对本文的评价
|