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

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


limb3:ru:packages:wact:template_composition

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

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

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

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

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

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

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

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

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

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

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

Обворачивание (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>

В результате получим нечто:

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

Использование тега <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, на самом деле в откомпилированном шаблоне относятся именно к корневому контейнеру данных.

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

  • Вынести <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/ru/packages/wact/template_composition.txt · Последние изменения: 2010/11/10 10:02 (внешнее изменение)