Руководство по BlueBream (часть 1)

Браузерные ресурсы

Файловый ресурс

Конкретные отображения, такие как изображения, таблицы стилей не ассоциируются с другими компонентами, так что для них нельзя создать вид. Для решение этой проблемы были разработаны ресурсы, которые являются компонентами отображения, которые не требуют контекста. Этот раздел покажет, как создавать ресурсы и регистрировать их с помощью BlueBream.

Первое, что нужено сделать - зарегистрировать простой текстовый файл с именем resource.txt как браузерный ресурс. Первый шаг - создать в любом месте файл, и наполнить его неким содержанием. Если вы работаете на основе официального учебника, вы можете создать файл src/tc/main/resource.txt:

Hello, I am a BlueBream Resource Component!

Теперь просто зарегистрируйте ресурс в файле настроек ZCML, используя директиву resource из пространства имен browser. Если вы работаете на основе официального учебника, добавьте эти строчки в файл src/tc/main/configure.zcml:

   1 <browser:resource
   2     name="resource.txt"
   3     file="resource.txt"
   4     layer="default" />

Когда вы подключаете файл настроек в главный файл настроек и перезапускаете BlueBream, вы получите доступ к ресурсу их браузера по ссылке: http://localhost:8080/@@/resource.txt. Символы @@/ в ссылке указывают механизму траверсинга, что данный объект является ресурсом.

Ресурс изображения

Если у вас есть изображения, вам понадобится другая конфигурация. Создайте простое изображение с именем img.png и зарегистрируйте следующим образом:

   1 <browser:resource
   2     name="img.png"
   3     image="img.png"
   4     permission="zope.ManageContent" />

Папка ресурсов

Если вам необходимо зарегистрировать много файловых ресурсов, то использование отдельной директивы для регистрации каждого ресурса становится скучным. Для этих целей используется директива browser:resourceDirectory, которая просто декларирует целую директорию, включая ее содержимое, как ресурсы, а имена ресурсов будут такими же как и имена файлов. Предполагая, что вы создали два предыдущих ресурса в одной папке, вы можете использовать следующее:

   1 <browser:resourceDirectory
   2   name="resource"
   3   directory="resource"
   4   />

Изображение будет общедоступным по следующей ссылке http://localhost:8080/@@/resources/img.png.

Объект "папка с ресурсами" использует простой алгоритм распознавания типа ресурсов. Он смотрит на расширения файлов, и по ним определяет тип. Для шаблонов страниц, на данный момент, используется расширение pt, zpt и html, а для изображений - gif, png и jpg. Все другие расширения конвертируются в файловые ресурсы. Заметьте, что не нужно иметь список всех типов изображений, поскольку все изображения, которые могут отображаться в браузере, будут распознаны.

В BlueBream существует папка с ресурсами, зарегистрированная под именем static. Если вы работаете на основе учебника, вы увидите эту регистрацию в src/tc/main/configure.zcml. В начале файла вы увидите следующую регистрацию:

   1 <browser:resourceDirectory
   2    name="static"
   3    directory="static"
   4    />

Для файловых ресурса (style.css и logo.png) сразу будут доступны в папке src/tc/main/static.

Существует также пакет z3c.zrtresource, разрабатываемый и поддерживаемый сообществом, документацию по которому можно получить здесь: http://wiki.zope.org/bluebream/BrowserResource

Страница обозревателя

Введение

В последней главе вы увидели, как использовать HTML ресурсы. HTML ресурсов будет доступен только на уровне сайта с префиксом @@.

Браузерные страницы (или в общем случае - виды) - оторбажения объектов/компонентов.

Если у вас есть такой шаблон (helloworld.pt):

   1 Hello, World !

Вот как зарегистрировать страницу для интерфейса IFolder:

   1 <browser:page
   2   name="helloworld.html"
   3   for="zope.site.interfaces.IFolder"
   4   template="helloworld.pt"
   5   permission="zope.Public"
   6   />

Виды

В то время как шаблоны отображают данные, виды - подготавливают данные. Виды конвертируют данные в формат, удобный для вывода, а также подготавливают связанные с ними данными (мета-данные). Давайте создадим объектные структуры, дружественные языку шаблонов TAL (словари и списки). Виды знают следующее: компонент, для которого они создаются (контекст) и запрос (request), который хранит всю медиа информацию (request).

Реализация

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

Вот простой вид:

   1 from zope.formlib import !DisplayForm
   2 from zope.site.interfaces import IFolder
   3 
   4 class !HelloWorld(!DisplayForm):
   5 
   6     def subFolderIds(self):
   7         for name, subobj in self.context.items():
   8             if IFolder.providedBy(subobj):
   9                 yield name

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

Виды - интеграция

Шаблоны страниц Zope

Введение

Шаблоны Страниц - инструмент для генерации веб страниц. Они помогают программистам и дизайнерам работать вместе над созданием динамических веб страниц и веб приложений. Дизайнеры могут использовать их для управления страницами вместе со своими привычными инструментами для разработки.

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

Цель шаблонов страниц - позволить дизайнерам и разработчикам работать вместе легко. Дизайнер может использовать WYSIWYG HTML редактор для создания габлона, а программист уже отредактирует его и сделает частью приложения. Если нужно, дизайнер может загрузить шаблон обратно и делать дальнейшие изменение в его структуре и внешнем виде.

Шаблоны страниц опираются на три принципа:

Шаблон страницы - это модель страниц, которые он сгенерирует. В особенности, он может быть проанализирован большинством HTML инструментов.

Как работают шаблоны страниц

Шаблоны страниц используют Язык Атрибутов Шаблона (TAL). TAL состоит из специальных атрибутов тега. Например, динамический заголовок страницы может выглядеть следующим образом:

   1 <h1 tal:content="context/title">Sample Page Title</h1>

Атрибут tal:content - это выражение языка TAL. Поскольку этот атрибут использует пространство имен XML (часть "tal:"), большниство инструментов для редактирования не будут жаловатьсяна него, и не будут удалять его. Он не поменяет структуры или внешнего вида шаблона, когда будет загружен в WYSIWYG редактор или веб обозреватель. Имя content и значение context/title обозначает, что текст, который содержится в теге h1, - будет заменен на результат выполнения выражения. В данном случае текст, который указан через context/title превратится в "Susan Jones Home Page", а сгенерированный HTML код будет выглядеть следующим образом:

   1 <h1>Susan Jones Home Page</h1>

Все выражения TAL - это атрибуты тегов, чью имена начинаются с tal:, а все их значения явно установлены. Значения выражения языка TAL показано внутри кавычек.

Для HTML дизайнера, который использует WYSIWYG инструменты, пример с динамическим заголовком выше - прекрасно анаолизируемый HTML, который паоказывается в редакторе так, как и должен выглядеть заголовок. Другими словами, Шаблоны страниц отлично работают вместе с инструментами редактирования.

Этот пример также демонстрирует принцип “То что вы видите - очень похоже на то, что вы получите”. Когда вы просматриваете шаблон в редакторе, текст заголовка будет вести себя как заполнитель для динамического содержимого. Этот шаблон приведен в качестве примера того, как будет выглядеть конечный документ.

Когда этот шаблон обрабатывается в Zope и предоставляется пользователю, фреймворк заменяет указанное содержимое на динамическое, заменяя текст “Sample Page Title” на тот, который хранится в атрибуте ‘context/title’. В этом случае, ‘context/title’ превратится в заголовок объекта, к которому применен шаблон. Эта замена производится динамически, когда шаблон просматривается.

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

Язык шаблонов умышленно не сделан таким мощным, чтобы с помощью него решать любые задачи. Это значит, что внутри фреймворка (как, например, в BlueBream) шаблоны отвечают только за вывод страниц, а не за логику приложения.

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

Выражения TALES

Выражение template/title в простом шаблоне - это выражение пути, которое является наиболее используемым типом выражений. Есть несколько типов выражений, которые определяются в спецификации синтаксиса выражений TAL. Для получения более полной информации, обратитесь к приложению C, Справочник по шаблонам страниц Zope.

Выражения путей (path expressions)

Выражение пути template/title берет атрибут title шаблона. Вот несколько наиболее общих выражений пути:

Из последней части вы должны были узнать о переменной context, которая доступна из Python скриптов, а также об атрибуте objectValues, который определяет метод API. Другие два примера приведены для того, чтобы осветить шаблон написания таких выражений. Вы узнаете о них чуть попозже в процессе прочтения этой книги.

Для того, чтобы увидеть, что именно возвращают эти примеры, просто скопируйте следующие строки в шаблон страницы и выберите закладку Test. Вы заметите, что context/objectValues возвращает список, который будет полезен только при последующей обработке. Мы вернемся к нему позже в этой главе:

   1 <p tal:content="context/objectValues"></p>
   2 <p tal:content="request/URL"></p>
   3 <p tal:content="user/getUserName"></p>

Каждое выражение пути начинается с имени переменной. Доступные переменные относятся либо к объектам, как context, request, user, и присутствуют во всех шаблонах, либо определены внутри шаблона с помощью TAL.

Небольшой набор встроенных переменных, таких как request и user описан в разделе Подробно о шаблонах страниц. В этом разделе вы также узнаете, как определять собственные переменные внутри шаблона.

Если переменная сама по себе возвращает то значение, которое вам нужно, тогда вам с ней больше ничего делать не надо. В другом случае, необходимо добавить слэш (‘/’) и имя вложенного объекта или атрибута. Вы можете проходить путь по дереву объектов столь глубоко, сколько понадобится для получения нужного объекта.

Выражения Python

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

В этом разделе у нас был пример:

   1 <h1 tal:content="context/title">Sample Page Title</h1>

Давайте попытаемся переписать его с помощью выражения Python:

   1 <h1 tal:content="python: context.title">Sample Page Title</h1>

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

Вот несколько простых вещей, которые вы не сможете сделать выражениями пути. Наиболее используемые - сравнение значений:

   1 "python: variable1 == variable2"

... или передавать аргументы в методы, например:

   1 "python: context.objectValues(['Folder'])"

Атрибуты TAL

Шаблоны страниц являются, фактически, примерами. Выражения TAL определяют, как их обрабатывать для получения динамического содержимого. В зависимости от того, какой атрибут TAL использовать, можно заменять содержимое тега или его атрибутов, удалять или повторять теги.

Вставка текста

В шаблоне simple_page мы использовали выражение tal:content на теге выделения текста жирным. При тестировании, Zope заменял содержимое HTML тега на заголовок шаблона.

Это просто в том случае, когда нужно заменить все содержимое элемента HTML. Но что если нужно заменить только несколько слов из всего текста?

Для того, чтобы вставить динамический текст внутрь другого текста, вам следует использовать tal:replace вместе с дополнительным тегом span. Например, добавьте следующие строки в пример:

   1 <p>The URL is
   2   <span tal:replace="request/URL">
   3     http://www.example.com</span>.</p>

Тег span является структурным, а не визуальным, так что выглядит как The URL is http://www.example.com., когда вы просматриваете исходный код шаблона в редакторе или обозревателе. Когда вы просматриваете обработанную версию, он будет выглядеть примерно так:

   1 The URL is http://localhost:8080/template_test/simple_page.

Если вы посмотрите в исходный код обработанной версии, то увидите что теги span отсутствуют.

Чтобы увидеть разницу между tal:replace и tal:content, создать шаблон страницы и включите следующее в его тело:

   1 <b tal:content="template/title"></b>
   2 <b tal:content="request/URL"></b>
   3 <b tal:content="user/getUserName"></b>
   4 <b tal:replace="template/title"></b>
   5 <b tal:replace="request/URL"></b>
   6 <b tal:replace="user/getUserName"></b>

Есть два других пути добавления элементов, которые нужны только для атрибутов TAL и удаляются в обработанной версии:

   1 <p>The URL is
   2   <span tal:content="request/URL" tal:omit-tag="">
   3     http://www.example.com</span>.</p>
   4 ... which is more useful in other situations and will be discussed there and:
   5 
   6 <p>The URL is
   7   <tal:span tal:content="request/URL">
   8     http://www.example.com</tal:span>.</p>

Хотя вы и можете выполнить большинство задач используя tal:replace или tal:omit-tag, некоторые разработчики предпочитают использовать TAL только для добавления TAL атрибутов. TAL - это язык атрибутов и он не определяет никаких элементов, типа tal:span, но в то же время использует пространства имен XML и разрешает использовать любое имя элемента: все равно эти элементы будут удалены после обработки шаблона.

Это очень полезно, так как предоставляет возможность использовать наглядные имена, как tal:loop, tal:case или tal:span, и не добавлять дополнительные элементы, какие HTML не разрешает. И даже если обозреватель или редактор игнорирует эти теги, дизайнер будет иметь меньше неприятностей с элементами TAL, нежели с дополнительными элементами HTML.

Циклические структуры

Давайте начнем с простого:

   1 <p tal:repeat="number python: range(4)" tal:content="number">
   2   999
   3 </p>

number - переменная повторения, а range(4) - выражение Python, которое возвращает список [0, 1, 2, 3]. Если этот код отработает, выражение repeat повторит добавление в документ элемента p для каждого значения из последовательности, изменяя значение переменной number очередным значением из последовательности. Так что обработанная страница будет показывать не номер 999, а 4 тега p, содержащие номера из нашего списка.

В большинстве случаев потребуется проход по более сложным структурам. Наш следующий пример показывает, как использовать последовательности объектов (ссылок на объекты). Шаблон simple_page может быть усовершенствован путем добавления списка элементов в форме списка объектов, что находятся в папке, которая является контекстом для шаблона. Давайте создадим таблицу, в которой строчки отражают информацию об объектах, а колонки содержат id, мета-тип и заголовок. Добавьте следующие строчки вниз шаблона:

   1 <table border="1" width="100%">
   2   <tr>
   3     <th>Id</th>
   4     <th>Meta-Type</th>
   5     <th>Title</th>
   6   </tr>
   7   <tr tal:repeat="item context/objectValues">
   8     <td tal:content="item/getId">Id</td>
   9     <td tal:content="item/meta_type">Meta-Type</td>
  10     <td tal:content="item/title">Title</td>
  11   </tr>
  12 </table>

Выражение tal:repeat примененное к строчке таблицы значит: повторить эту строчку для каждого элемента в моем списке объектов. Выражение repeat кладет по очереди объекты из списка в переменную (она называется переменной повторения), и создает копию строки, используя эту переменную. Значение item/getId в каждой строке - это идентификатор объекта, информация о котором содержится в строке в виде item/meta_type и item/title.

Переменная повторения может иметь любое имя(item - это только пример), но может начинаться только с латинской буквы и содержать латинские буквы, цифры и подчеркивания(‘_’). Переменная повторения определена только внутри тега с атрибутом repeat. Если вы попытаетесь использовать ее вне этого тега, то получите ошибку.

Вы также можете использовать переменную повторения для получения информации о текущей итерации.

Теперь посмотрите страницу и заметьте, как строится список всех объектов в папке-контексте шаблона. Попробуйте добавлять или удалять объекты из папки, и увидите изменения в странице.

Условные конструкции

Используя шаблоны страниц вы можете динамически опрашивать свою среду и выборочно вставлять текст в зависимости от определенных условий. Например, вы можете отобразить специальную информацию в ответе на установку cookie:

   1 <p tal:condition="request/cookies/verbose | nothing">
   2   Here's the extra information you requested.
   3 </p>

Этот параграф будет включен в вывод только тога, когда установлена cookie с именем verbose. Выражение request/cookies/verbose | nothing истинно только тогда, когда cookie с именем verbose установлена. Вы узнаете больше об этом выражении из раздела с названием Advanced Page Templates.

Используя tal:condition вы можете проверять любые условия. Выражение tal:condition оставляет тег и его содержимое на месте, если выражение в условии возвращает значение true, и удаляет этот тег, если значение - false. Zope считает число 0, пустую строку, пустой список и встроенную переменную nothing равными false. Соответственно почти каждое другое значение - true, включая ненулевые числа и строки с любым содержимым (даже если они состоят только из пробелов!).

Другое широкое применение условных конструкций - проверка последовательностей на наличие содержимого перед выполнением по ним итераций. Например, в последнем разделе вы увидели как можно нарисовать таблицу, пройдясь по коллекции объектов. Вот как добавить на страницу проверку, будет ли таблица пустая.

Для того, чтобы увидеть изменения, сначала изменим немножко пример, показывая только объекты в Folder из папки-контекста. Поскольку мы не можем указать параметры используя выражения пути, как context/objectValues, сначала нужно превратить это выражение в выражение языка Python context.objectValues(), а потом добавить аргумент, который указывает методу objectValues возвращать только подпапки:

   1 <tr tal:repeat="item python: context.objectValues(['Folder'])">

Если вы еще не добавили подпапок в папку template_test, вы заметите, что при использовании закладки Test, заголовок таблицы все еще показывается, хотя таблица пуста. Для того, чтобы избежать этого, мы добавляем выражение tal:condition в тег table. Полная таблица будет выглядеть следующим образом:

   1 <table tal:condition="python: context.objectValues(['Folder'])"
   2        border="1" width="100%">
   3   <tr>
   4     <th>Id</th>
   5     <th>Meta-Type</th>
   6     <th>Title</th>
   7   </tr>
   8   <tr tal:repeat="item python: context.objectValues(['Folder'])">
   9     <td tal:content="item/getId">Id</td>
  10     <td tal:content="item/meta_type">Meta-Type</td>
  11     <td tal:content="item/title">Title</td>
  12   </tr>
  13 </table>

Если список подпапок пустой, условие примет значение false и таблица не отобразится вообще. Вы можете убедится в этом, используя закладку Test еще раз.

Давайте добавим три объекта Folder с именами 1, 2, и 3 в папку template_test, в которой живет шаблон simple_page. Перезайдите на шаблон simple_page и просмотрите его вывод через закладку Test. Вы увидите таблицу, которая выглядит следующим образом:

   1 Id          Meta-Type          Title
   2 1           Folder
   3 2           Folder
   4 3           Folder

Изменение значений атрибутов

Большинство, если не все, объектов, которые используются в вашем шаблоне имеют атрибут, содержащий путь к иконке, отражающей тип этого объекта. Для того, чтобы отобразить эту иконку в колонке meta-type, вам следует вставить путь к ней в атрибут src тега img. Отредактируйте ячейку таблицы в колонке meta-type из примера, поданного выше, приведя его к такому виду:

   1 <td><img src="file_icon.gif"
   2          tal:attributes="src item/icon" />
   3   <span tal:replace="item/meta_type">Meta-Type</span></td>

Выражение tal:attributes замещает значение атрибута src тега img значением item/icon. Атрибут src в шаблоне (чье значение - file_icon.gif) добавлен в качестве заполнителя.

Заметьте, что мы заменили атрибут tal:content в ячейке таблицы на tal:replace тега span. Это изменение позволяет содержать и текст и изображение в ячейке таблицы.

XML шаблоны страниц

Создание XML с помощью механизма шаблонов происходит точно также, как и создание HTML. Вы переключаетесь в режим XML устанавливая в поле content-type значение text/xml или любой другой контент-тип, который нужен для вашего XML документа.

В режиме XML не разрешена невалидная разметка. Zope предполагает, что ваш шаблон - правильный XML документ. Zope также требует явных объявлений пространств имен TAL и METAL при обработке XML. Например, если вы хотите отдавать клиентам XHTML, вам следует добавить обявления пространств имен в тег html:

   1 <html xmlns:tal="http://xml.zope.org/namespaces/tal"
   2   xmlns:metal="http://xml.zope.org/namespaces/metal">

Для того, чтобы просмотреть исходники XML шаблонов, лучше переходить к source.xml, нежели к source.html.

Отладка и тестирование

Zope помогает в поиске и исправлении ошибок в шаблонах страниц. Zope отлавливает ошибки на двух этапах: когда вы редактируете шаблон страницы, и когда вы его просматриваете.

Вы уже могли видеть комментарии, которые Zope вставляет в шаблоны страниц, когда возникают ошибки. Эти комментарии указывают вам на ошибки, которые находит Zope во время редактирования шаблонов. Ошибки, которые Zope находит на этапе редактирования, обычно связаны с выражениями TAL. Например:

<!-- Page Template Diagnostics
 Compilation failed
 TAL.TALDefs.TALError: bad TAL attribute: 'contents', at line 10, column 1
-->

Это диагностическое сообщение показывает, что вы ошиблись при использовании tal:contents, в то время как правильным значением является tal:content в строке 10 шаблона. Другие диагностические сообщения указывают на ошибки в выражениях и макросах.

Когда вы используете интерфейс управления Zope (management interface) для редактирования шаблонов страниц, диагностические сообщения оказываются очень полезными, так как появляются они в заголовке Errors страницы интерфейса управления после попытки сохранить шаблон.

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

   1 Error Type: PTRuntimeError
   2 Error Value: Page Template hello.html has errors.

Это есть не что иное, как сигнал для проверки шаблона на правильность.

Вдобавок к диагностическим сообщением при редактирования, вы время от времени можете получать обычные ошибки Zope при просмотре шаблона. Эти ошибки возникают в связи с ошибками в выражениях. Например, вы можете получить ошибку, если в выражении использовалось неверное имя переменной:

   1 Error Type: KeyError
   2 Error Value: 'unicorn'

Это сообщение об ошибке уведомляет вам, что переменная unicorn не найдена. Чтобы помочь вам, Zope включает информацию об ошибке и окружении в трейсбек. Получить доступ к этой информации можно через файл error_log (в корневой папке Zope). Трейсбек будет содержать информацию о месте, где возникла ошибка и об окружении (environment):

   1 URL: /sandbox/demo
   2 Line 1, Column 14
   3 Expression: standard:'context/unicorn'
   4 Names:
   5   {'container': <Folder instance at 019AC4D0>,
   6    'context': <Application instance at 01736F78>,
   7    'default': <Products.PageTemplates.TALES.Default instance at 0x012F9D00>,
   8    ...
   9    'root': <Application instance at 01736F78>,
  10    'template': <ZopePageTemplate at /sandbox/demo>,
  11    'traverse_subpath': [],
  12    'user': admin}

Эта информация сложна к восприятию, но, просмотрев ее внимательно, вы обнаружите ошибку. В данном случае, журнал ошибок сообщает о том, что переменная context - это Application instance (экземпляр приложения). Это значит, что она хранит папку верхнего уровня Zope (также как и переменная root в этом же Application instance). Возможно, ошибка заключается в том, что вы питались вызвать шаблон для папки, которая имеет свойствj unicorn, но корневая папка этого свойства не имеет.

Макросы

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

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

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

Использование макросов

Макросы определяются посредством атрибутов, схожих с выражениями TAL. Атрибуты тегов, которые работают с макросами называются выражениями Macro Expansion Tag Attribute Language (METAL), то есть TAL с макросами. Вот пример определения макроса:

   1 <p metal:define-macro="copyright">
   2   Copyright 2009, <em>Foo, Bar, and Associates</em> Inc.
   3 </p>

Тут выражение metal:define-macro определяет макрос с именем copyright. Макрос состоит из тега p (включая все его содержимое, заканчивая закрывающим тегом p).

Макрос определен в шаблоне страницы и хранится в атрибуте macros. Вы можете использовать макрос из любого другого шаблона, обращаясь к нему через атрибут macros шаблона, в котором он определен. Например, представим себе макрос copyright в шаблоне страницы с именем master_page. Вот как можно использовать этот макрос из другого шаблона:

   1 <hr />
   2 <b metal:use-macro="container/master_page/macros/copyright">
   3   Macro goes here
   4 </b>

В этом шаблоне, тег b будет полностью заменен макросом при отображении шаблона:

   1 <hr />
   2 <p>
   3   Copyright 2009, <em>Foo, Bar, and Associates</em> Inc.
   4 </p>

Если вы измените макрос (например, если изменится правообладатель), то все шаблоны, которые используют этот макрос автоматически отразят изменения.

Заметьте, как определяется макрос по выражению пути при использовании выражения metal:use-macro. Выражение metal:use-macro заменяет тег, в котором оно используется на тело макроса.

Подробнее о макросах

Выражения metal:define-macro и metal:use-macro достаточно простые. Но есть несколько моментов в использовании макросов, которые следует осветить.

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

Обычно вы будете обращаться к макросу посредством выражения metal:use-macro вместе с выражением пути. Но вы также можете использовать любое другое выражение, главное чтобы возвращаемым значением являлся макрос. Например:

   1 <p metal:use-macro="python:context.getMacro()">
   2   Replaced with a dynamically determined macro,
   3   which is located by the getMacro script.
   4 </p>

В этом случае выражение пути возвращает макрос, который определен динамически с помощью скрипта getMacro. Используя выражения Python для обнаружения макросов, вы можете динамически определять, какой макрос использовать в шаблоне. Вот пример скрипта getMacro (Python) :

   1 return container.ptMacros.macros['amacroname']

Вы можете использовать переменную default внутри выражения metal:use-macro:

   1 <p metal:use-macro="default">
   2   This content remains - no macro is used
   3 </p>

Полученный результат тот же, что и при использовании tal:content и tal:replace. Содержимое по умолчанию в теге не изменится при отображении шаблона. Это очень удобно, если вам нужно использовать макрос при наступлении определенных условий или отображать содержимое по умолчанию, в случае если такой не существует.

Если вы попытаетесь использовать переменную nothing вместе с metal:use-macro, то получите ошибку, так как nothing не является макросом. Если вы хотите использовать nothing для построения условия включения макроса, вам следует заключить выражение metal:use-macro в выражение tal:condition.

Zope обрабатывает макросы при первом отображении шаблонов. Zope выполняет выражения TAL. Например, предположим существование следующего макроса:

   1 <p metal:define-macro="title"
   2    tal:content="template/title">
   3   template's title
   4 </p>

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

Если вы поставите галочку Expand macros when editing в виде для редактирования шаблона, то любой макрос, который вы будете использовать будет вставлен в исходник шаблона.

Использование слотов

Макросы становятся намного полезнее, если имеется возможность переопределять их части при использовании. Вы можете сделать это благодаря механизму слотов (slots), которые вы определяете и заполняете внутри макроса при использовании шаблона. Например, представим макрос для боковой панели страницы:

   1 <div metal:define-macro="sidebar">
   2   Links
   3   <ul>
   4     <li><a href="/">Home</a></li>
   5     <li><a href="/products">Products</a></li>
   6     <li><a href="/support">Support</a></li>
   7     <li><a href="/contact">Contact Us</a></li>
   8   </ul>
   9 </div>

Этот макрос хорош, но представьте себе, что вам нужно на некоторых страницах добавлять некоторую дополнительную информацию к той, которая предоставляется макросом. Один из путей решения этой задачи - использование слотов:

   1 <div metal:define-macro="sidebar">
   2   Links
   3   <ul>
   4     <li><a href="/">Home</a></li>
   5     <li><a href="/products">Products</a></li>
   6     <li><a href="/support">Support</a></li>
   7     <li><a href="/contact">Contact Us</a></li>
   8   </ul>
   9   <span metal:define-slot="additional_info"></span>
  10 </div>

Когда вы используете макрос, вы можете заполнить слот информацией следующим образом:

   1 <p metal:use-macro="container/master.html/macros/sidebar">
   2   <b metal:fill-slot="additional_info">
   3     Make sure to check out our <a href="/specials">specials</a>.
   4   </b>
   5 </p>

При отображении шаблона боковая панель будет включать дополнительную информацию, которую вы передали в слот:

   1 <div>
   2   Links
   3   <ul>
   4     <li><a href="/">Home</a></li>
   5     <li><a href="/products">Products</a></li>
   6     <li><a href="/support">Support</a></li>
   7     <li><a href="/contact">Contact Us</a></li>
   8   </ul>
   9   <b>
  10     Make sure to check out our <a href="/specials">specials</a>.
  11   </b>
  12 </div>

Заметьте, что тег span, который определяет слот заменен на тег b, который заполняет слот.

Настройка отображения по умолчанию

Наиболее распространенное использование слотов связано с настройкой отображения страниц. В примере из последней главы, определение слота состояло из одного пустого тега span, но вы можете заложить отображение слота по умолчанию. Например, представим пересмотренный вариант предыдущего макроса:

   1 <div metal:define-macro="sidebar">
   2   <div metal:define-slot="links">
   3   Links
   4   <ul>
   5     <li><a href="/">Home</a></li>
   6     <li><a href="/products">Products</a></li>
   7     <li><a href="/support">Support</a></li>
   8     <li><a href="/contact">Contact Us</a></li>
   9   </ul>
  10   </div>
  11   <span metal:define-slot="additional_info"></span>
  12 </div>

Теперь боковая панель полностью настраиваемая. Вы можете заполнить слот links, чтобы переопределить ссылки в боковой панели, хотя, если вы не заполните этот слот, то получите ссылки по умолчанию, которые присутствуют в определении слота.

Эту технику можно использовать впредь для определения слотов внутри слотов. Такое решение позволяет переопределять отображение по умолчанию с очень хорошим уровнем точности. Вот макрос боковой панели, который определяет слоты в слотах:

   1 <div metal:define-macro="sidebar">
   2   <div metal:define-slot="links">
   3   Links
   4   <ul>
   5     <li><a href="/">Home</a></li>
   6     <li><a href="/products">Products</a></li>
   7     <li><a href="/support">Support</a></li>
   8     <li><a href="/contact">Contact Us</a></li>
   9     <span metal:define-slot="additional_links"></span>
  10   </ul>
  11   </div>
  12   <span metal:define-slot="additional_info"></span>
  13 </div>

Если вы желаете настроить ссылки в боковой панели, вы можете заполнить как слот links, который полностью переопределит все ссылки, так и заполнить слот additional_links, который добавит несколько дополнительных ссылок после тех, которые указаны в определении. Встраивать слоты можно сколько угодно глубоко.

TAL и METAL вместе

Вы можете использовать выражения METAL и TAL в одном и том же теге. Например:

   1 <ul metal:define-macro="links"
   2     tal:repeat="link context/getLinks">
   3   <li>
   4     <a href="link url"
   5        tal:attributes="href link/url"
   6        tal:content="link/name">link name</a>
   7   </li>
   8 </ul>

В этом случае, getLinks - (воображаемый) скрипт, который собирает список объектов-ссылок, возможно, используя запрос к утилите Каталог.

Так как выражения METAL выполняются перед выражениями TAL, не возникнет никаких конфликтов. Этот пример также интересен тем, что делает макрос настриваемым даже без использование слотов. Этот макрос вызывает скрипт getLinks для получения ссылок. Все же вы можете настроить ссылки на вашем сайте путем переопределения скрипта getLinks в разных местах внутри сайта.

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

Макрос как целая страница

Вместо того, чтобы использовать макросы для представления кусков информации, разнесенных между страницами, их можно использовать для определения целых страниц. Слоты делают такое решение возможным. Вот пример макроса, который определяет целую страницу:

   1 <html metal:define-macro="page">
   2   <head>
   3     <title tal:content="context/title">The title</title>
   4   </head>
   5 
   6   <body>
   7     <h1 metal:define-slot="headline"
   8         tal:content="context/title">title</h1>
   9 
  10     <p metal:define-slot="body">
  11       This is the body.
  12     </p>
  13 
  14     <span metal:define-slot="footer">
  15       <p>Copyright 2010 Fluffy Enterprises</p>
  16     </span>
  17 
  18   </body>
  19 </html>

Этот макрос определяет страницу с тремя слотами: headline, body, и footer. Заметьте, как слот headline включает выражение TAL для динамического определения заголовка содержимого.

Вы можете использовать этот макрос в шаблонах для многих типов содержимого и разных частей сайта. Например, вот шаблон для отображения новостей, который может использовать данный макрос:

   1 <html metal:use-macro="container/master.html/macros/page">
   2 
   3   <h1 metal:fill-slot="headline">
   4     Press Release:
   5     <span tal:replace="context/getHeadline">Headline</span>
   6   </h1>
   7 
   8   <p metal:fill-slot="body"
   9      tal:content="context/getBody">
  10     News item body goes here
  11   </p>
  12 
  13 </html>

Этот шаблон переопределяет слот headline, включая слова Press Release и вызывает метод getHeadline текущего объекта. Он также переопределяет слот body для вызова метода getBody текущего объекта.

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

Перевод: Ростислав Дзинько

Документации/Bluebream/Руководство (последним исправлял пользователь RostislavDzinko 2010-07-09 11:35:42)