Использование ПО с открытым исходным кодом для создания Web-сайта для совместной работы: Часть 7. Структурирование содержимого c XHTML

Исследуйте подходы группы разработчиков Web-сайта и ключевые методы структурирования содержимого, поставляемого Drupal.

Элистер Льюис-Боуэн, старший инженер-программист, IBM

Элистер Льюис-БоуэнЭлистер Льюис-Боуэн (Alister Lewis-Bowen) работает старшим инженером-программистом в IBM Internet Technology Group. Он занимается Интернет и web-технологиями как сотрудник IBM UK с 1993. Элистер был переведен в США для работы над Web-сайтами спортивных событий, спонсируемых IBM, а затем как старший Web-мастер ibm.com. В настоящее время он помогает создавать семантические Web-прототипы. Связаться с Элистером можно по адресу alister@us.ibm.com.



Стефен Эванчик, инженер-программист, IBM

Стефен ЭванчикСтефен Эванчик (Stephen Evanchik) работает инженером-программистом в IBM Internet Technology Group. Он принимает участие во многих проектах с открытыми исходными кодами, самым известным из которых является его IBM TrackPoint-драйвер в ядре Linux. Стефен в настоящее время работает с появляющимися семантическими Web-технологиями. Связаться с ним можно по адресу evanchik@us.ibm.com.



Луис Вайцман, старший инженер-программист, IBM

Луис ВайцманЛуис Вайцман (Louis Weitzman) работает старшим инженером-программистом в IBM Internet Technology Group. В течение 30 лет он работал на стыке дизайна и вычислений. Помогал разрабатывать XML, фрагментированную систему управления содержимым, используемую для ibm.com, а в настоящее время участвует в обеспечении процесса проектирования новых проектов. Связаться с ним можно по адресу louisw@us.ibm.com.



25.12.2006

Введение

Во второй части данной серии статей рассматривались технические приемы, использованные группой разработчиков для понимания природы аудитории Web-сайта вымышленной компании International Business Council (IBC). Используя различные методики, мы протестировали схемы страниц и взаимодействие с пользователями. Эти действия обеспечили основу для компоновки визуальных элементов с общей схемой, позволяя начать создавать основной стиль представления информации. В этой и следующей статье вы узнаете о нашем подходе к созданию специализированной темы для Web-сайта IBC.

В восьмой части данной серии статей будет рассмотрено, как применить этот стиль для оформления внешнего вида нашего Web-сайта.

Информация, приведенная в данной статье, должна рассматриваться не как строгий набор правил разработки, а лишь как справочная информация для создания структуры вашего собственного Web-сайта.

В данной статье проследите за тем, как мы создаем тему в Drupal, и обратите внимание на методы, которые помогли разрешить:

  • Шаблоны для фрагментов содержимого
  • Независимую схему домашней страницы
  • Идентификацию разделов Web-сайта
  • Динамически обновляемую навигацию
  • Обслуживание нетрадиционных браузеров
  • Контекстно-зависимые действия
  • Области выделенного содержимого

Хотя многие из этих идей базируются на имеющемся передовом опыте и основанном на стандартах Web-дизайне, мы надеемся, что данная статья подскажет вам идеи для улучшения подхода к структуре содержимого в контексте Drupal.

Эволюция через опыт

Начиная создавать специализированную тему, мы не знали о многих доступных функциональных возможностях. Мы часто начинали с быстрого и грубого решения, только впоследствии обнаруживая, что имелся намного лучший способ сделать то же самое. Мы учимся до сих пор. Это мощная концепция, так как в большинстве случаев можно скомпоновать "внешний вид" Web-сайта очень быстро и улучшать его по мере дальнейшего знакомства с Drupal.

После рассмотрения наших методов вы узнаете о причинах их использования по мере нашего продвижения от первоначальных решений к более удачным и систематизированным.

Основанный на стандартах Web-дизайн

Во многих книгах и на многих Web-сайтах говорится о текущих направлениях основанного на стандартах Web-дизайна. Существенной частью этой философии является правильное применение XHTML и CSS (cascading style sheets). Гибкая природа системы оформления внешнего вида (theming system) Drupal позволяет дизайнерам Web-сайтов легко адаптировать эти стандарты.

Использование основанного на стандартах подхода к структуре и стилю Web-сайта IBC позволяет нам создать прочный дизайн, который:

  • Работает для современных Web-браузеров, считывающих устройств и беспроводных устройств.
  • Уменьшает время загрузки страницы и ее визуализации браузером.
  • Позволяет применить гибкую схему, дающую пользователям возможность увеличивать или уменьшать размер окна браузера или размер шрифта.
  • Создает приемлемый формат для распечатки на принтере для любого содержимого Web-сайта.
  • Позволяет элегантно ухудшить содержимое для отображения в старых браузерах.

При создании Web-сайта IBC мы придерживались основанных на стандартах принципов Web-дизайна, но объяснение этих стандартов не является целью данной статьи. А теперь, перейдем к созданию новой специализированной темы.

Создание новой темы

Начиная создание новой темы, мы скопировали подкаталог Bluemarine каталога themes и переименовали его в ibc. Это схема по умолчанию для механизма phptemplate, поставляемая с Drupal и содержащая основу, на которой вы можете создать вашу собственную тему. Новый каталог показан в нашей среде Eclipse на рисунке 1.

Рисунок 1. Вид Navigator, новый каталог темы IBC
Рисунок 1. Вид Navigator, новый каталог темы IBC

Доступны и другие механизмы поддержки тем. По определению, если вы используете файлы .tpl.php в вашем каталоге theme, Drupal будет знать, что нужно использовать механизм phptemplate. Если вы используете файлы .xtmpl, Drupal будет знать, что нужно использовать механизм xtemplate. Вы могли бы также использовать файл .theme, в котором вы можете переопределить любую PHP-функцию темы. Дополнительная информация по данному вопросу приведена в обзоре систем оформления внешнего вида в Drupal.

Для того чтобы сделать эту тему активной для Web-сайта, разрешите ее на странице admin/themes. Drupal перечисляет все темы, обнаруженные в каталоге Themes. Тема ibc может быть разрешена и выбрана темой по умолчанию, как показано на рисунке 2.

Рисунок 2. Выбор темы для IBC
Рисунок 2. Выбор темы для IBC

Пиктограмма, представляющая уменьшенную копию экрана внешнего вида темы, управляется файлом screenshot.png, расположенным внутри каталога themes. Вы можете создать собственное изображение для вашей темы, но, по-видимому, только после того, как будете готовы представить ее внешний вид.

Закладка Configure на рисунке 2 позволяет администратору изменять общие настройки для тем или настройки для конкретной темы. Для отдельной темы могут быть запрещены или разрешены определенные элементы содержимого, предоставляемые Drupal для использования темой.

На рисунке 3 перечислено несколько элементов содержимого на закладке Configure в группе Toggle display, которые могут быть разрешены или запрещены. Mission statement - это один из элементов, который определяется администратором в разделе General Settings страницы admin/settings. Механизм поддержки тем будет передавать эту строку текста (если разрешено) в виде переменной ($mission) в шаблон страницы (описанный в листинге 1). Дизайнер темы решает, как визуализировать эти элементы (либо вообще не делать этого) при создании специализированной темы.

Рисунок 3. Страница настройки для темы IBC
Рисунок 3. Страница настройки для темы IBC

Структура содержимого

В нашем случае, подобно покраске стен, большая часть работы заключается в подготовке к ней. Чем лучше вы заделаете дыры и трещины, а затем зачистите их, тем легче будет красить, а комната лучше будет выглядеть. Поэтому, перед оформлением Web-сайта мы хотим иметь гарантию, что содержимое хорошо структурировано. В оставшейся части данной статьи описывается, как мы создавали XHTML-код в нашей теме так, чтобы оформление при помощи CSS было относительно простым.

Базовая схема

Базовая схема Web-сайта управляется файлом page.tpl.php, расположенном в каталоге темы, указанном вами в настройках страницы (рисунок 1). Здесь мы можем начать определять скелетную структуру, которая будет заключать в себе фрагменты нашего содержимого, определенные рассмотренными ранее файлами шаблонов узла. В листинге 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 вы должны были иметь возможность идентифицировать контейнеры для заголовка, содержимого, боковой панели и сноски.

Идентификаторы и классы

Мы используем атрибуты ID главным образом для атрибутов layout и class, для повторяющихся элементов, или элементов, о которых нам известно, что их будет тяжело идентифицировать при помощи CSS-селекторов. В листинге 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 и разрешены (запрещены) в конфигурации темы, что было рассмотрено ранее. Доступные переменные могут быть вставлены в подходящие места шаблона.

Зоны (regions) являются областями, в которых оформленные блоки и содержимое узла визуализируются системой Drupal. $sidebar_$left, $sidebar_right, $content, $header и $footer_message являются переменными с содержимым для стандартных зон. Специализированные зоны могут также быть определены при помощи ловушки theme _regions. Эти наборы оформленного содержимого предоставляют удобные контейнеры, которые могут быть размещены в схеме страницы дизайнером темы.

Структура для домашней страницы

Как и на большинстве Web-сайтов, домашняя страница обычно использует схему, отличную от других страниц. Используя переменную $is_front в файле page.tpl.php, мы можем принимать решения (об отличиях в отображаемых элементах), такие как небольшое изменение элемента title, как показано в листинге 2.

Листинг 2. Изменение заголовка страницы на основе переменной $is_front
<title><?php print ( $is_front ? "Home | International Business Council (IBC)"
       : $head_title ); ?></title>

Для Web-сайта IBC нам нужно показать суммарный список уведомлений и самые свежие записи на форуме. Для того, чтобы отличать схемы этого содержимого от других схем, мы использовали условный оператор в теле страницы (листинг 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, мы вызываем корректные функции модуля, аналогичные функциям модуля announcements, для отображения суммарного списка уведомлений. Если значение $is_front равно false, отображается переменная $content, которая содержит набор оформленных узлов, которые скомпоновал Drupal на основе последовательности построения узлов, описанной в одной из предыдущих статей.

Страница login

Одним из требований к Web-сайту IBC является обязательная аутентификация пользователей перед возможностью отображения какого-либо содержимого. Обычно подобные сайты закрытого сообщества или экстранет-сайты отображают не аутентифицированному пользователю вместо домашней страницы страницу входа в систему (login page).

Поскольку мы рассматриваем файл page.tpl.php, может быть полезным объяснить наше первоначальное решение этой проблемы. Оно не использует функцию завершения сессии и не является особенно элегантным, но оно работает (мы рассмотрим более удачный метод в будущей статье, но здесь может быть интересно показать первоначальное решение).

Код из листинга 4 помещается перед элементом DOCTYPE в файле page.tpl.php (листинг 1). Переменная $user->uid устанавливается только тогда, когда выполняется аутентификация текущего пользователя. Мы использовали это для определения того, включать ли другой файл шаблона для визуализации страницы входа на сайт и для последующего выхода из файла page.tpl.php. Файл login.tpl.php визуализирует страницу входа на сайт, содержащую форму входа, скопированную из пользовательского блока login.

Листинг 4. Проверка для аутентификации пользователя или отображения страницы входа на сайт
<?php
global $user;
if (!$user->uid) {
	include('login.tpl.php');
	return;
}
?>

Ощущение места

Управление базовой схемой страницы вашего Web-сайта из одного файла полезно, но что произойдет, если вы захотите идентифицировать различные разделы вашего сайта? Например, вы можете захотеть предоставлять пользователю визуальные разметки текущего раздела. Мы использовали URL для установки значения атрибута class в элементе body так, чтобы можно было соответствующим образом оформить внешний вид страницы. Одним из способов сделать это является вывод функции Drupal arg прямо в значение атрибута class, что показано в листинге 5. Однако это не даст нам необходимого уровня управления.

Листинг 5. Добавление значения атрибута class к элементу body
<body class="<?php print arg(0); ?>" >

Мы прибегли к использованию простого оператора switch, для того чтобы определить значение атрибута class с более гибким управлением. В листинге 6 оператор switch определяет значение для использования на основе первой части URL-пути. Это обеспечивает нас CSS-классом, который мы могли бы использовать для изменения представления страницы на основе отображаемого раздела Web-сайта.

Листинг 6. Добавление определенного значения атрибута class в элемент body
<?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); ?>" >

Конечно же, мы очищаем URL, настроенные на странице admin/settings, и модули для каждого раздела Web-сайта, которые зарегистрировали URLs в системе меню Drupal, а потому можем надежно обнаруживать разделы сайта из URL. Другим способом сделать это (о котором мы поговорим в следующих статьях) является использование таксономии модуля для определения отображаемого раздела.

Динамическая навигация

Структура нашей основной навигации должна меняться в зависимости от содержимого базы данных 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 в элементы list item для Workgroups и Conferences встроены дополнительные вложенные списки. Они формируют динамическое содержимое, генерируемое при помощи некоторого PHP-кода. В следующей статье будет рассмотрено, как оформить внешний вид этой структуры для создания ниспадающего меню для основной навигации.

Содержимое для нетрадиционных браузеров

Для адаптации к ситуациям, в которых IBC может быть не виден через традиционные браузеры, мы включили дополнительную структуру содержимого. Мы добавили клавиши доступа, ссылки на определенные главные разделы схемы содержимого и заголовки для идентификации этих разделов.

Для документирования ключей доступа, используемых внутри схемы страницы Web-сайта, мы добавили контейнер пояснительного текста в верхней части страницы сразу после элемента BODY в листинге 1. В листинге 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 показаны примеры вставки структуры дополнительного содержимого для идентификации основных разделов схемы страницы и добавления ссылки в начало содержимого страницы. Обратите внимание на значение класса 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>
.
.
.

Естественно, могли бы использоваться и другие технические приемы, такие как включение атрибутов alt в элемент IMG для пояснения использования изображения. Поместить атрибут title внутрь элемента anchor (<A>) в Drupal можно включением его в массив атрибутов функции l, что показано в листинге 11.

Листинг 11. Добавление атрибута title к ссылке
$links[] = l(t('Edit'),
             "announcement/$node->nid/edit",
             array('title' => t('Display the edit form for this announcement')));

Что касается доступности в формах, то Drupal указывает в элементах формы элементы LABEL при использовании form API.

Итак, как же мы настроили структуру содержимого, отображаемого для этих фрагментов содержимого, вставляемого в шаблон страницы? Мы использовали шаблоны фрагментов содержимого.

Шаблоны фрагментов содержимого

Механизм phptemplate использует файл node.tpl.php как общий шаблон для формирования дизайнером темы любых сгенерированных данных узла во фрагмент содержимого. Для сайтов, использующих несколько типов узлов, дизайнеры тем могут управлять визуализацией данных для конкретного типа узла, используя файл шаблона node-<node-type>.tpl.php.

В шестой части данной серии статей вы узнали, что для наших специализированных модулей Web-сайта IBC (согласно выбранной схеме) данные визуализируются в трех различных контекстах: подробная схема, краткое представление и блок. На рисунках 4 и 5 показаны примеры этих контекстов, вставляемые в шаблон страницы. Когда последовательность создания узла формирует страницу announcement из URL, как показано на рисунке 4, системой Drupal компонуются и оформляются различные необходимые на странице фрагменты узла, которые затем помещаются в шаблон страницы.

На рисунке 4 область, отмеченная буквой A, выделяет фрагмент содержимого, созданный с использованием шаблона node-announcement.tpl.php (приведенного в листинге 14) для структурирования данных уведомления. Область C выделяет содержимое, созданное ловушкой block модуля announcement с использованием шаблона announcement_block_list.tpl.php для структурирования данных блока.

Рисунок 4. Контекст страницы уведомлений, содержащий подробную схему и схему блока announcement
Рисунок 4. Контекст страницы уведомлений, содержащий подробную схему и схему блока announcement

На рисунке 5 выделенные области содержимого, отмеченные буквой B, показывают фрагменты содержимого краткого представления уведомления, созданные функцией announcement_all модуля announcement с использованием шаблона announcement_compact.tpl.php.

Рисунок 5. Контекст домашней страницы, содержащий краткие схемы и схему блока announcement
Рисунок 5. Контекст домашней страницы, содержащий краткие схемы и схему блока announcement

Как показано на рисунке 5, мы использовали шаблоны для отделения структуры и оформления этих контекстов от модулей, создающих данные. Для визуализации подробной схемы мы использовали файл шаблона node-<node-type>.tpl.php. Однако при создании шаблонов оформления для контекстов краткого представления и представления в блоке в своих собственных файлах шаблонов мы использовали методику, описанную в шестой части данной серии статей.

При оформлении внешнего вида данных в Drupal используется функция <theme(theme_function_name>, <data>), где theme_function_name представляет собой строку, используемую для идентификации функции theme. Drupal использует процесс исключения при решении, какую функцию нужно использовать для передачи этих данных, чтобы можно было сгенерировать вывод оформленных данных. Этот процесс показан на рисунке 6.

Рисунок 6. Метод поиска функции theme в Drupal
Рисунок 6. Метод поиска функции theme в Drupal

Разработчик модуля может, таким образом, переопределять функцию theme по умолчанию функцией, специализированной для механизма. Теперь в этой phptemplate-функции theme мы используем функцию _phptemplate_callback для указания системе поддержки тем Drupal использовать файл шаблона, сформированный с использованием theme_function_name. Следовательно, вызов theme (как, например, в листинге 12) будет использовать файл шаблона announcement_compact.tpl.php.

Листинг 12. Оформление внешнего вида краткого представления уведомления в announcement.module
$page_content[] = theme('announcement_compact', $announcement);

В шестой части данной серии статей (в разделе hook_nodeapi) мы обсудили, как разрешить разработчикам модулей создать <theme_function_name>-<node-type>.tpl.php для любой theme_function_name. При помощи этого метода вы могли бы использовать файлы block-<node-type>.tpl.php, если бы захотели.


Шаблоны для уведомлений

Давайте посмотрим на то, как могут выглядеть эти шаблоны для трех наших контекстов при использовании модуля announcements, описанного в шестой части.

Подробности уведомления

Мы используем файл шаблона node-announcement.tpl.php для структурирования получаемого фрагмента содержимого для полного уведомления. Этот фрагмент содержимого появляется на странице, отображающей одно уведомление (рисунок 4, область A). Система формирования узла в Drupal передает объект node в этот шаблон, предоставляя переменные, которые могут быть вставлены в XHTML-структуру.

Для исследования этих переменных вы можете использовать функцию print_r в шаблоне, как показано в листинге 13. Сохраните файл шаблона и затем просмотрите Web-страницу, содержащую шаблон. Будет отображаться содержимое $node. Эта функция является элементарным, но полезным средством отладки при работе с PHP.

Листинг 13. Отображение содержимого объекта node
<?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, как упоминалось ранее. Это дает нам имя класса, используя которое оформляется стиль содержимого внутри фрагмента.

Для получения полностью заполненного объекта $userdrupal.org рекомендует использовать функцию user_load().

Затем выводится заголовок вместе с содержимым $links, сгенерированным функцией announcement_link. Это отображает так называемые "ссылки на действия" рядом с заголовком уведомления. Вместо использования интерфейса закладок Drupal, предоставляющего пользователям способ применения действий к узлу, мы хотели иметь способ помещения этих действий (таких как Add, Edit и Delete) рядом с содержимым, на которое они воздействуют, как показано красным цветом на рисунке 7.

Рисунок 7. Ссылки на действия рядом с заголовком уведомления
Рисунок 7. Ссылки на действия рядом с заголовком уведомления

Вы можете заметить, что мы предоставляем некоторую дополнительную информацию в строке Posted on. В листинге 14 для отображения дополнительной информации о сроке истечения действия используется оператор условия. Он проверяет, является ли текущий пользователь автором уведомления, или имеет ли он права доступа для редактирования. Для выполнения проверки используется глобальный объект данных о пользователе ($user) и функция user_access. Мы включили это в качестве примера того, как использовать различные объекты данных и вспомогательные функции в файле шаблона.

Оставшаяся часть листинга выводит обзор, тело и все вложения (attachments) для уведомления. XHTML структурирован таким образом, чтобы быть корректным как семантически, так и структурно. Если часть данных недоступна, весь содержащий их XHTML-элемент исключается из получаемого фрагмента содержимого. Например, использование элемента DIV, содержащего текст обзора внутри условного PHP-оператора (<?php if ($node->abstract) : ?>), гарантирует, что это содержимое будет отображаться только при существовании $node->abstract.

Краткий обзор уведомления

Мы используем файл шаблона announcement_compact.tpl.php для структурирования получаемого фрагмента содержимого для краткого обзора уведомления. Этот фрагмент содержимого используется при выводе списка нескольких уведомлений, например, на домашней странице или странице уведомлений, как показано на рисунке 5 в области B.

В листинге 15 мы используем эффективный контейнер для объектов, идентифицируемых значением атрибута класса 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&nbsp;&raquo;</a>
  </div>
  <?php endif; ?>

</div>

При редактировании уведомления раздел Publishing options формы позволяет администратору установить флажок sticky (прикрепить) для узла. Используя это в модуле announcement, мы можем переопределить хронологический порядок перечисленных уведомлений и прикрепить сверху некоторые из них. Здесь мы идентифицируем прикрепленные уведомления по значению атрибута class содержащего их элемента DIV. Переменная $node->sticky передается в этот шаблон в функции phptemplate_announcement_compact (см. часть 6).

Класс hl_yellow включается, если ID текущего пользователя аналогичен присвоенному уведомлению ID пользователя. Это позволяет нам выделить все уведомления, автором которых является текущий пользователь.

Блок announcement

Мы используем файл шаблона announcement_block_list.tpl.php для структурирования фрагмента содержимого для блока announcement. Этот фрагмент содержимого используется при перечислении нескольких последних уведомлений в правой панели на каждой странице, как показано на рисунке 4 в области C и на рисунке 5 в области C.

Шаблон в листинге 16 настраивает данные, созданные в функции announcement_block. Он создает табличный список уведомлений для использования в переменной содержимого блока announcement. Поскольку блок announcement использует схему блока по умолчанию, он тоже может быть изменен при помощи шаблона 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 &raquo;</a></p>

Код в этой таблице немного более сложен, потому что он формирует строку таблицы для каждого уведомления. Каждая строка содержит два столбца. Первый столбец содержит заголовок уведомления, который формируется как XHTML-элемент anchor, ссылающийся на страницу подробной информации об уведомлении. Второй столбец содержит дату публикации уведомления. Еще один элемент anchor создается после таблицы, для того чтобы позволить пользователю сослаться на страницу с полным списком уведомлений. Как и в схеме краткого обзора уведомления, если владельцем уведомления является текущий пользователь, указывается значение атрибута class hl_yellow.

В шестой части данной серии статей мы рассмотрели, как используется переменная $announcement_block_max_list_count для управления количеством уведомлений, отображаемым в блоке. Эта логика содержится в функции announcement_block, поэтому нужное количество уведомлений передается в этот шаблон.

Файл template.php

В пятой части мы упоминали об использовании файла template.php. Этот файл может содержать функции theme, переопределяющие существующие функции theme, которые применяются глобально ко всей теме, а не только для конкретных типов узлов. Простым примером этого является необходимость окружить ссылки на действия (описанные ранее) контейнером, помогающим нам оформить стиль этих элементов anchor для отделения их визуально от остального содержимого.

Файл /inc/theme.inc, поставляемый с установочными файлами Drupal, определяет функцию theme_links function. Эта функция используется для оформления переменной $links, которую механизм phpengine передает в файлы шаблона. То есть, используя последовательность, описанную на рисунке 6, мы должны иметь возможность переопределить ее при помощи функции phptemplate_links. В листинге 17 показана эта функция, которая помещается в файл template.php.

Листинг 17. Переопределение функции theme_links по умолчанию в файле template.php
function phptemplate_links($links, $delimiter = " ") {
  return '<span class="action">'.implode($delimiter, $links).'</span>';
}

Как вы можете заметить, эта функция просто окружает ссылки элементом SPAN, идентифицированным атрибутом class.


Резюме

В данной статье вы узнали, как приступить к созданию новой темы, а также познакомились с методами создания структурированного XHTML в теме для нашего Web-сайта. Мы рассмотрели несколько методов структуризации содержимого Web-сайта, к которым относятся общая схема страниц, содержимое домашней страницы, основная навигация и идентификация разделов Web-сайта.

Не пропустите следующую статью, в которой вы можете узнать, как наша команда оформила стиль структурированного Web-сайта IBC при помощи CSS.

Ресурсы

Научиться

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=185533
ArticleTitle=Использование ПО с открытым исходным кодом для создания Web-сайта для совместной работы: Часть 7. Структурирование содержимого c XHTML
publish-date=12252006