Шаблоны
14.7. Стилевые опции
Система шаблонов не имеет специальных стилевых усовершенствований, но и с существующими стилями можно использовать несколько удачных приемов.
Контент шаблона можно оформлять стилями, и в атрибутах style и class использовать переменные шаблона. Таким образом стилевая информация может предоставляться самими RDF данными, обрабатываемыми шаблоном. Это, однако, порождает архитектурную проблему, поскольку в таком случае данные и оформление смешиваются в одном и том же множестве RDF фактов. Если этот прием должен использоваться не как единичный случай, лучше иметь один набор фактов для данных и отличный от него - для стилевого оформления.
Стили можно применять, используя теги <rule> как селекторы, управляемые данными. Два правила могут порождать практически идентичный контент, но запросы при этом могут отличаться. Практически идентичный контент может, соответственно, иметь разное стилевое оформление.
Наконец, стили можно применить к порожденному контенту, используя операции JavaScript DOM. Если шаблон будет перестроен, это стилевое оформление может потеряться.
14.8. Практика: оживляем данные для Notetaker
Данный раздел "Практика" описывает использование шаблонов нашего приложения, работающих с реальными данными.
В этом разделе мы заменим часть нашего кода шаблоном и затем протестируем приложение на реальных данных.
Для начала, у нас есть модель RDF данных из "Оверлеи и Chrome" , "Оверлеи и Chrome". Позже мы поместим этот файл в профиль пользователя, где он и должен быть. А пока что мы поместим его в chrome вместе со всеми файлами нашего приложения. Он будет тут:
chrome://notetaker/contents/notetaker.rdf
Шаблоны нам понадобятся три раза:
- Поля формы на панели инструментов NoteTaker должны открываться с данными текущей заметки. Мы увидим, что для этого потребуется два шаблона.
- Список ключевых слов в диалоговом окне Edit также должен загружаться с существующими ключевыми словами текущей заметки.
- Дерево связанных ключевых слов в диалоговом окне Edit должно загружаться со всеми ключевыми словами, связанными с текущими ключевыми словами.
Последний пункт требует специальной техники; содержание дерева, грубо говоря, должно уточнять содержание списка, а это требует координирования их работы.
Данные также появляются в HTML-записи на текущей web-странице. HTML не поддерживает шаблонов, так что мы должны извлечь необходимые нам данные из RDF, используя отличный от шаблона механизм. Он описывается в "Объекты XPCOM" , "Объекты XPCOM".
14.8.1. Создаем тестовые данные
Для того чтобы построить шаблон, нам нужны некоторые данные. Создадим RDF документ с двумя записями и относящейся к ним информацией. Первая запись - о web-странице test1.html, имеющая четыре ключевых слова. Вторая - о test2.html, с двумя ключевыми словами.
В листинге 14.18 приведены данные для этих двух записей и связи ключевых слов.
<?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmnls:NT="http://www.mozilla.org/notetaker-rdf#"> <Description about="urn:notetaker:root"> <NT:notes> <Seq about="urn:notetaker:notes"> <li resource="http://saturn/test1.html"/> <li resource="http://saturn/test2.html"/> </Seq> </NT:notes> <NT:keywords> <Seq about="urn:notetaker:keywords"> <li resource="urn:notetaker:keyword:checkpointed"/> <li resource="urn:notetaker:keyword:reviewed"/> <li resource="urn:notetaker:keyword:fun"/> <li resource="urn:notetaker:keyword:visual"/> <li resource="urn:notetaker:keyword:cool"/> <li resource="urn:notetaker:keyword:test"/> <li resource="urn:notetaker:keyword:breakdown"/> <li resource="urn:notetaker:keyword:first draft"/> <li resource="urn:notetaker:keyword:final"/> <li resource="urn:notetaker:keyword:guru"/> <li resource="urn:notetaker:keyword:rubbish"/> </Seq> </NT:keywords> </Description> <!-- details for each note --> <Description about="http://saturn/test1.html"> <NT:summary>My Summary</NT:summary> <NT:details>My Details</NT:details> <NT:top>100</NT:top> <NT:left>90</NT:left> <NT:width>80</NT:width> <NT:height>70</NT:height> <NT:keyword resource="urn:notetaker:keyword:test"/> <NT:keyword resource="urn:notetaker:keyword:cool"/> </Description> <Description about="http://saturn/test2.html"> <NT:summary>Good place to list</NT:summary> <NT:details>Last time I had a website here, my page also appeared on Yahoo </NT:details> <NT:top>100</NT:top> <NT:left>300</NT:left> <NT:width>100</NT:width> <NT:height>200<NT:height> <NT:keyword resource="urn:notetaker:keyword:checkpointed"/> <NT:keyword resource="urn:notetaker:keyword:reviewed"/> <NT:keyword resource="urn:notetaker:keyword:fun"/> <NT:keyword resource="urn:notetaker:keyword:visual"/> </Description> <!-- values for each keyword --> <Description about="urn:notetaker:keyword:checkpointed" NT:label="checkpointed"/> <Description about="urn:notetaker:keyword:reviewed" NT:label="reviewed"/ > <Description about="urn:notetaker:keyword:fun" NT:label="fun"/> <Description about="urn:notetaker:keyword:visual" NT:label="visual"/> <Description about="urn:notetaker:keyword:breakdown" NT:label="breakdown"/> <Description about="urn:notetaker:keyword:first draft" NT:label="first draft"/> <Description about="urn:notetaker:keyword:final" NT:label="final"/> <Description about="urn:notetaker:keyword:guru" NT:label="guru"/> <Description about="urn:notetaker:keyword:rubbish" NT:label="rubbish"/> <Description about="urn:notetaker:keyword:test" NT:label="test"/> <Description about="urn:notetaker:keyword:cool" NT:label="cool"/> <!--sufficient related keyword pairings --> <Description about="urn:notetaker:keyword:checkpointed"> <NT:related resource="urn:notetaker:keyword:breakdown"/> <NT:related resource="urn:notetaker:keyword:first draft"/> <NT:related resource="urn:notetaker:keyword:final"/> </Description> <Description about="urn:notetaker:keyword:reviewed"> <NT:related resource="urn:notetaker:keyword:guru"/> <NT:related resource="urn:notetaker:keyword:rubbish"/> </Description> <Description about="urn:notetaker:keyword:fun"> <NT:related resource="urn:notetaker:keyword:cool"/> </Description> <!-- single example of a cycle --> <Description about="urn:notetaker:keyword:cool"> <NT:related resource="urn:notetaker:keyword:test"/> </Description> </Description> </RDF>Листинг 14.18. Тестовые данные для XUL-шаблона NoteTaker.
К сочетанию RDF документа и шаблона нужно относиться куда внимательнее, чем к вручную размечаемому дереву. Если хоть что-нибудь будет сделано некорректно, шаблон ничего не построит, без каких-либо указаний на причину. Начните с тестирования наших данных по советам из раздела "Отладка". Если у вас нет текстового редактора с автоматической подсветкой и проверкой XML синтаксиса, поступите следующим образом: загрузите RDF документ в браузер, чтобы найти синтаксические ошибки в XML. Затем измените расширение файла на .xml и вновь откройте в браузере, чтобы обнаружить проблемы, связанные с порядком тегов. Наконец, просмотрите файл визуально, вспомните рекомендации о формате из "RDF" , "RDF". Если все выглядит как надо, у нас есть некоторая, но совсем не полная, уверенность, что с нашими данными все в порядке.
14.8.2. Простые шаблоны для элементов формы
Сначала мы напишем шаблоны для панели инструментов NoteTaker. Для панели инструментов потребуется два значения, по одному для каждого поля ввода текста, и набор из нуля или более элементов выпадающего меню. Нужно использовать два шаблона, один для полей ввода и другой для выпадающего меню.
Выпадающее меню - самое простое. Из файла notetaker.rdf видно, что для конкретных ключевых слов нам нужно свойство label. Ключевые слова собираются вместе в RDF контейнере urn:notetaker:keywords, т.е. теге <Seq>. Это устройство соответствует стандартной организации фактов, так что можно использовать простой синтаксис запроса и, следовательно, создание шаблона не должно вызывать затруднений.
Сначала протестируем шаблон на простом документе, не будем добавлять его на панель инструментов сразу. Таким образом мы избежим сложностей с контентом выпадающего меню. Поскольку шаблоны и RDF дают нам очень мало диагностической информации, будем двигаться шаг за шагом. В листинге 14.19 приведен простой документ без какого-либо шаблона.
<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <!DOCTYPE window> <window xmlns="http://www.mozilla.org/keymaster/ gatekeeper/there.is.only.xul"> <vbox> <description value="Static content"/> <hbox> <description value="Repeated content"/> </hbox> </vbox> </window>Листинг 14.19. Простой XUL документ, подходящий как основа для тестирования шаблона.
Для шаблона нам необходимы следующие моменты:
Файл RDF: datasources="notetaker.rdf"
Стартовая точка запроса: ref="urn:notetaker:keywords"
Простая переменная требует повторяющегося контента: uri="rdf:*"
В качестве переменной запроса с простым синтаксисом используем:
rdf:http://www.mozilla.org/notetaker-rdf#label
Объединяя эту информацию с кодом листинга 14.18, получим листинг 14.20.
<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <!DOCTYPE window> <window xmlns="http://www.mozilla.org/keymaster/ gatekeeper/there.is.only.xul"> <vbox datasources="notetaker.rdf" ref="urn:notetaker:keywords"> <description value="Static content"/> <template> <hbox uri="rdf:*"> <description value="Repeated content"/> <description value="rdf:http://www.mozilla.org/ notetaker-rdf#label"/> </hbox> </template> </vbox> </window>Листинг 14.20. Простой документ XUL с шаблоном запроса для выпадающего меню.
Контент "Static content" находится вне тега <template>, так что мы увидим его в любом случае. Контент "Repeated content" появится один раз для каждого решения, найденного запросом. Третий тег description даст значение единственной переменной, обоснованной запросом. Результаты работы шаблона показаны на рисунке 14.6.
Теперь у нас есть работающий шаблон. Чтобы этого добиться, мы игнорировали некоторые мелочи; с системой шаблонов, однако, все в порядке, за исключением, может быть, нехватки отладочных инструментов.
Теперь мы можем модифицировать шаблон, встроив его в панель инструментов. В листинге 14.21 показано выпадающее меню до и после присоединения шаблона.
<?xml version="1.0"?> <menulist editable="true"> <menupopup> <!-- static menu items removed --> </menupopup> </menulist> <menulist id="notetaker-toolbar.keywords" editable="true"> <menupopup datasources="notetaker.rdf" ref="urn:notetaker:keywords"> <template> <menuitem uri="rdf:*" label="rdf: http://www.mozilla.org/notetaker-rdf#label"/> </template> </menupopup> </menulist>Листинг 14.21. Выпадающее меню со встроенным шаблоном для панели инструментов NoteTaker.
Результаты этих изменений видны на рисунке 14.7.
Если запрос не обнаружит ключевых слов, в меню не будет ни одного элемента, и на панели инструментов это будет выглядеть плохо. Чтобы исправить положение, мы добавили временный тег <menuitem> перед тегом <template>. Другой способ - сделать наверняка, чтобы в файле notetaker.rdf содержалось как минимум одно ключевое слово. Мы так поступим позже.
Второй шаблон на панели инструментов должен найти единственное решение для тега <textbox>. Чтобы представить себе, каким может быть этот запрос, снова посмотрим на файл notetaker.rdf. URL искомой записи является членом именованного RDF контейнера ( urn:notetaker:notes ), и имеет свойство summary. Таким образом стандартная организация фактов, требуемая для простого синтаксиса запроса, соблюдена. Наверное, мы можем использовать простой синтаксис.
Но на деле мы простой синтаксис использовать не можем, потому что мы привередливы - мы хотим выбирать, какие члены последовательности будут получены. Нам нужен единственный член, являющийся записью именно о текущем URL. Так что придется использовать расширенный синтаксис.
В расширенном синтаксисе мы не обязаны начинать запрос с вершины последовательности, так что мы можем быть более изобретательны. Мы можем начать его прямо с URL текущей записи. Если мы так сделаем, примером запроса может быть:
<- http://saturn/test1.html, http://www.mozilla.org/ notetakerrdf#summary, ?summary ->
Используя совет, данный в настоящей лекции, в разделе "Часто встречающиеся образцы запросов", создадим шаблон следующим образом:
<box datasources="notetaker.rdf" ref="http://saturn/test1.html"> <template> <rule> <conditions> <content uri="?uri"/> <triple subject="?uri" predicate="http://www.mozilla.org/notetaker-rdf#summary" object="?summary"/> </conditions> <action> <textbox id="notetaker-toolbar.summary" uri="?summary" value="?summary"/> </action> </rule> </template> </box>Листинг 14.22. Второй шаблон на панели инструментов NoteTaker.
Этот код заменит единственный тег <textbox/>, присутствующий на панели инструментов. Мы заключили textbox в невидимый тег <box>, чтобы привязать к нему шаблон.
Этот шаблон в качестве исходной точки запроса имеет фиксированный URL. В недалеком будущем мы сделаем данное значение динамическим, используя скрипт и метод setAttribute(). На этом изменения в XUL панели инструментов NoteTaker заканчиваются. Обратимся к шаблонам диалогового окна Edit. Оба тега этого окна, и <listbox>, и <tree>, требуют использования шаблонов.