Инструменты пользователя

Инструменты сайта


limb3_2007_2:ru:usage:wact:template_composition

Композиция шаблонов: включение(include) и обворачивание(wrap) шаблонов

Компиляция WACT шаблонов

WACT содержит различные средства, которые позволяют собирать конечные шаблоны из набора других шаблонов:

  • Включение (include) - включение одного шаблона в другой.
  • Обворачивание (wrap) - обворачивание одного шаблона другим.

Wact компилирует шаблоны только целиком! То есть сначала обрабатываются все include и wrap теги, и только затем создается откомпилированный шаблон. Именно поэтому разбиение шаблона на составляюще в WACT практически ничего не стоит (лишь увеличивается незначительно время компиляции). Это дает нам возможность выносить в отдельные шаблоны все, что повторяется в нескольких файлах.

Цель данной страницы - показать способы «снижения дублирования» в WACT-шаблонах, то есть как максимально эффективно использовать все возможности WACT по композиции шаблонов.

Сразу же обратим ваше внимание, что в WACT существует правило сбалансированности шаблонов, то есть каждый шаблон должен иметь закрывающий тег для каждого открывающего. Это наносит свой отпечаток на то, как шаблоны разбиваются на составляющие. Но справедливости ради отметим, что этот факт обычно никак не мешает в работе с шаблонизатором, даже напротив.

Включение (include). Использование тега <core:include>

Включение (include) одного шаблона в другой. Include в WACT осуществляется посредством тега <core:include file='path_to_file'/>. По-умолчанию, включаемый файл компилируется как обычный шаблон.

Если вы используете WACT совместно с пакетом WEB_APP, и в атрибуте file используется абсолютное значение (начинается с / или с c:/), тогда WACT подключает шаблон по абсолютному пути. В противном случае - пытается найти шаблон через механизм подключения шаблонов.

Компиляцию включаемого шаблона можно отключить, если использовать атрибут literal, например: <core:include file='path_to_file' literal='true'/>.

Из-за правила сбалансированности, вы не можете просто так применить любимый многими php-программистами прием - разбить шаблон на footer.html и header.html, то есть:

my_page.html

<html>
<head>
[...meta...]
</head>
<body>
[...content...]
</body>
</html>

Разбить на 2 шаблона: header.html

<html>
<head>
[...meta...]
</head>
<body>

footer.html

</body>
</html>

Вот так сделать в WACT не получится!!

my_page.html:

<core:include file='header.html'/>
[...content...]
<core:include file='footer.html'/>

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

Обворачивание (wrap)

Введение в обворачивание шаблонов

Обворачивание (wrap) - это вставка шаблона в определенное место другого шаблона.

С обворачиванием шаблонов связаны следующие термины:

  • Текущий шаблон - который содержит команды по обворачиванию (в нем содержатся теги <core:wrap>)
  • Базовый шаблон - в который осуществляется вставка текущего шаблона.
  • Контейнер вставки (placeholder) - находится в базовом шаблоне и помечает места вставки.

Обворачивание производится при помощи тега <core:wrap file='file_to_wrap_into'>. Контейнер обычно помечается тегом <core:placeholder id='some_id'/>.

Вот как будет выглядеть результат нашего предыдущего примера:

page.html - базовый шаблон

<html>
<head>
[...meta...]
</head>
<body>
 <core:placeholder id='content'/>
</body>
</html>

my_page.html - текущий шаблон

<core:wrap file='page.html' as='content'>
[...content...]
</core:wrap>

Использование тега <core:wrap>. Множественныое обворачивание

Разберем подробнее, как работает тег <core:wrap>.

<core:wrap> требует закрывающего тега. Обворачиваемой считается та часть текущего шаблона, что обрамлена в рамки тега <core:wrap>.

Если тег <core:wrap> не содержит атрибута file, тогда обворачивание производится в шаблон, который был указан родительским тегом <core:wrap>. Таким образом мы можем как бы указать сначала целевой файл, а затем только указать какие части и куда обвернуть.

Поясним это все на примере:

Допустим есть базовый шаблон страницы page.html:

<html>
<body>
  <core:placeholder id='content'/>
</body>
</html>

Также шаблон дополнительного дизайна layout.html с двумя местами для вставки (как бы второй базовый шаблон):

 <div id='header'><core:placeholder id='header'/></div>
 <div id='main'><core:placeholder id='main'/></div>

И теперь текущий шаблон display.html:

<core:wrap file='page.html' as='content'>
 
<core:wrap file='layout.html'>
 <core:wrap as='header'>My Header</core:wrap>
 <core:wrap as='main'>My Complex content</core:wrap>
</core:wrap>
 
</core:wrap>

На выходе получим:

<html>
<body>
  <div id='header'>My Header</div>
  <div id='main'>My Complex content</div>
</body>
</html>

Необходимо пояснить, как именно компилируется шаблон в данном случае. Сначала обрабатывается первый <core:wrap> и мы получаем на 1-м шаге компиляции следующий шаблон:

<html>
<body>
  <core:wrap file='layout.html'>
   <core:wrap as='header'>My Header</core:wrap>
   <core:wrap as='main'>My Complex content</core:wrap>
  </core:wrap>
</body>
</html>

Затем обрабатывается второй <core:wrap> и условно получается:

<html>
<body>
 
 <!-- Дочерние <core:wrap> теги могут искать контейнеры вставки только в этих рамках -->
 <div id='header'><core:placeholder id='header'/></div>
 <div id='main'><core:placeholder id='main'/></div>
 
 <core:wrap as='header'>My Header</core:wrap>
 <core:wrap as='main'>My Complex content</core:wrap>
 <!-- ...... -->
 
</body>
</html>

Обратите внимание, что дочерние <core:wrap> теги (без атрибута file) могут найти контейнеры вставки только в отмеченной зоне (только внутри шаблона, указанного родительским <core:wrap>).

В результате работы дочерних <core:wrap> получается конечный результат.

Произвольные контейнеры вставки

Контейнер вставки не обязательно должен быть реализован при помощи тега <core:placeholder>. Для этих целей можно использовать вообще любой тег, например <div>. Необходимо будет лишь указать, что этот тег должен обрабатываться как тег с активным компонентом и дать ему идентификатор. Это можно сделать при помощи одного атрибута: wact:id, например:

 <div wact:id='content'>Content will be placed here</div>

<core:wrap> можно использовать по-разному:

  • вставлять контент в конец содержимого контейнера.
  • заменять весь контент контейнера .

Для этого теперь есть 2 атрибута:

  • in, например <core:wrap in='placeholder'>…</core:wrap>
  • as, например <core:wrap as='placeholder'>…</core:wrap>

В первом случае содержимое между <core:wrap> будет вставлено сразу же после содержимого контейнера вставки, во втором - полностью заменит контент внутри контейнера.

Контейнеры данных и множественное обворачивание

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

Разберем небольшой пример (предупреждаем, он может показаться весьма нетривильным для понимания).

Путь у нас есть базовый шаблон page.html, в котором есть 2 контейнера вставки:

<html>
<body>
<h1><core:placeholder id='title'/></h1>
<div wact:id='content'></div>
</body>
</html>

Предположим, что у нас есть такой текущий шаблон:

<core:wrap file='page.html'>
 
<core:datasource id='my_data'>
 
  <core:wrap in='title'>{$title}</core:wrap>
  <core:wrap in='content'>{$content}</core:wrap>
 
</core:datasource>
 
</core:wrap>

На первый взгляд все нормально, мы должны получить конечный шаблон, где из контейнера данных my_data будут выводиться переменные $title и $content. Однако это вовсе не так.

На самом деле шаблон откомпилируется схематично следующим образом:

<html>
<body>
<h1>{$title}</h1>
<div id='content'>{$content}</div>
 
</body>
</html>
 
<core:datasource id='my_data'>
</core:datasource>

То есть по сути внутри контейнера данных ничего нет! А переменные, которые в исходном шаблоне как бы относились к контейнеру данных my_data, на самом деле в откомпилированном шаблоне относятся именно к корневому контейнеру данных.

Здесь есть 2 решения:

  • Вынести <core:datasource> наверх, до тега <core:wrap>
  • Создать отдельный шаблон (например, layout.html), который будет содержать разметку, а обворачивание в этот шаблон сделать уже внутри <core:datasource>

Первый вариант будет выглядеть сдедующим образом (изменится только текущий шаблон):

<core:datasource id='my_data'>
 
<core:wrap file='page.html'>
 
  <core:wrap in='title'>{$title}</core:wrap>
  <core:wrap in='content'>{$content}</core:wrap>
 
</core:wrap>
 
</core:datasource>

Самый большой недостаток этого подхода - это то, что теперь весь шаблон заключен в активный компонент тега <core:datasource id='my_data'>, то есть мы как бы имеем теперь 2 корневых шаблона. Это может повлять на работу некоторых шаблонов, которые выводили некоторые переменные, считая что текущий контейнер будет глобальным, например, {$meta_keywords} вместо {$#meta_keywords}.

Второй способ более правильный, но требует выделения еще одного шаблона. Вот как будут выглядеть все наши шаблоны:

Базовый шаблон page.html

<html>
<body>
 
<core:placeholder id='content'/>
 
</body>
</html>

Шаблон layout.html

<h1>{$title}</h1>
 
<div wact:id='content'>{$content}</div>

И наш текущий шаблон:

<core:wrap file='page.html' in='content'>
 
<core:datasource id='my_data'>
 
<core:wrap file='layout.html'>
  <core:wrap in='title'>{$title}</core:wrap>
  <core:wrap in='content'>{$content}</core:wrap>
</core:wrap>
 
</core:datasource>
 
</core:wrap>

Теперь все будет работать как ожидается.

Обсуждение

Ваш комментарий. Вики-синтаксис разрешён:
   ___    __  ___  _____   __ __  _   __
  / _ \  /  |/  / / ___/  / //_/ | | / /
 / // / / /|_/ / / (_ /  / ,<    | |/ / 
/____/ /_/  /_/  \___/  /_/|_|   |___/
 
limb3_2007_2/ru/usage/wact/template_composition.txt · Последние изменения: 2010/11/10 10:02 (внешнее изменение)