В этой лекции объясняется, как улучшить язык XUL с помощью новых
тегов и новых свойств, используя XBL (XML
XBL - основанный на XML язык, позволяющий конструировать новые
мощные теги для XUL, HTML и XML. Это
Простой XUL позволяет пользователю создавать собственные теги,
наподобие <mytag>, но они не слишком полезны. Их можно оформить
стилями, но они остаются простыми <box> -подобными тегами. С
помощью же XBL, напротив, можно создавать целые виджеты с уникальным
поведением и обликом. Контент XBL-виджетов комбинируется из XUL, HTML
и других XBL-тегов. XBL не столь гибок как Java-
XBL не создает новых тегов, с его помощью создаются лишь новые
связки (-moz-.
После того как это сделано, говорят, что тег и связка - связаны.
Простейшая связка приведена в листинге 15.1. Это фрагмент документа
XBL, реализующий виджет "улыбочку".
<binding id="smiley">
<content>
<xul:image src="face.png"/>
</content>
<handlers>
<handler event="click" action="alert('have a day')"/>
</handlers>
</binding>
Эту связку можно привязать к тегу с именем < с
помощью следующей строки CSS:
smiley { -moz-binding: url("smiley.xml#smiley"); }
Теперь тег < всегда будет отображать улыбку в
документе XUL. Если по нему кликнуть, появится окошко с приветствием.
Это несложный виджет со своей простейшей интерактивностью. Ни в XUL,
ни в HTML тега < нет.
Система XBL встроена в C/C++ код платформы Mozilla, но сами
пользовательские связки пишутся на JavaScript и XML. Эта
интерпретируемая среда позволяет создавать связки так же легко, как
XUL или HTML. Простота применения интенсивно используется в Mozilla.
Множество XBL-связок вносят свой вклад в приложения Mozilla, такие как
классический
На протяжении всей этой книги мы часто ссылались на файлы .xml в
архиве <tabbrowser> и <colorpicker>, которые определены полностью средствами XBL. Даже
простые теги, например, <button>, имеют XBL-связки.
За пределами мира Mozilla технология, подобная XBL - это язык
Связки XBL имеют ясно определенный интерфейс и уникальность, что
делает XBL небольшой компонентной системой. Как XPCOM предназначен для
компонентов
Поскольку связки XBL создаются с помощью XML и JavaScript, их можно свободно перемешивать с HTML или XUL. HTML используется нечасто, потому что группа тегов, применяемых как HTML, фиксирована и стандартна. Гораздо чаще можно увидеть XBL в приложениях XUL.
На картинке в начале этой лекции показано место XBL в платформе
Mozilla. Несмотря на свой статус компонентной системы, XBL - одна из
главных технологий в Mozilla. Во время загрузки документа XUL связки
XBL идентифицируются и встраиваются в содержание конечного документа.
Это немного похоже на работу системы оверлеев. После того как теги,
используемые в связках XBL, загрузятся, они отображают свой контент
так же, как любой другой тег XUL. Система XBL также имеет поддержку
обработки событий, создаваемых пользователем при вводе. Она использует
систему практически такую же, как система обработки тега <key>.
Здесь мы продолжим общее
XBL расширяет XML так же, как C++ расширяет C. Он добавляет объектно-ориентированные возможности системе, у которой средств для работы с объектами не было.
Каждый документ XBL - это просто список связок (<. Конструирование связки
подобно конструированию класса объектов. В Листинге 15.2 показана
простая связка XBL, являющаяся вариантом тега-связки <.
<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" >
<binding id="checkbox" extends="general.xml#basetext">
<resources>
<stylesheet src="chrome://global/skin/checkbox.css"/>
</resources>
<content>
<xul:image class="checkbox-check"
xbl:inherits="checked,disabled"/>
<xul:hbox>
<xul:image class="checkbox-icon" xbl:inherits="src"/>
<xul:label xbl:inherits="xbl:text=label,accesskey,crop"/>
</xul:hbox>
</content>
<implementation implements="nsIDOMXULCheckboxElement">
<method name="check" action="this.checked = true"/>
<property name="checked" onset="if (val)
this.setAttribute('checked','true');"
onget="return this.getAttribute('checked') == 'true';" />
</implementation>
<handlers>
<handler event="click" button="0"
action="if (!this.disabled) this.checked = !
this.checked;"/>
<handler event="keypress" key=" ">
<![CDATA[ this.checked = !this.checked; ]]>
</handler>
</handlers>
</binding>
</bindings>
Листинг 15.2 демонстрирует многие стандартные черты связок. Разделы <resource> и <content> описывают данные в форме стилей,
изображений, тегов и других простых элементов XUL. Эти разделы
содержат контент XML. Разделы < и < описывают свойства, методы и связанные с событиями
хуки. Эти секции существуют в форме
Рекомендуем изучать связки, созданные другими людьми. В разделе "Чтение чужого кода" лекции 16, "Объекты XPCOM", и в Таблице 16.1 приведены некоторые советы, облегчающие изучение связок, созданных командой mozilla.org.
XBL - это приложение XML. Его XML-определение можно найти по адресу http://www.mozilla.org/xbl. Mozilla не грузит этот URL, он используется лишь как идентификатор. Стандартным суффиксом для XBL-файлов является .xml.
Стандартный тип application/xml.
Связки XBL идентифицируются с помощью URL. Специальной http: и :. Так же, как
для #id, идентифицирующий каждую
связку внутри документа XBL. Как и в случае с #id, рассматривается как целый ресурс, а не
фрагмент ресурса. Пример:
chrome://global/content/bindings/button.xml#button.
XBL был принят консорциумом
Реализация XBL в Mozilla отличается от предложенной в
Стандарты, конкурирующие с XBL, это
XBL имеет более широкую область применения, чем любой иной стандарт
Чтобы связки XBL можно было использовать, они должны быть
предварительно встроены в иерархию
Перед тем, как связка будет использована, ее нужно связать с
существующими XML-тегами документа. Эти теги называются граничными
тегами (<content>, то теги внутри него
называются
Когда мы вызываем XBL-связку, иерархия
Шаги 1 и 2 повторяются для каждого граничного тега. Процесс порождения контента очень похож на такой же процесс для оверлеев и шаблонов. Так же как в оверлеях, контент добавляется в целевой документ в определенной точке. Так же как в шаблонах, добавочный контент порождается повторным копированием определенного набора тегов. Платформа Mozilla автоматически выполняет эти шаги.
Исходное XBL-определение связки недоступно в целевом документе.
Если необходимо, его можно загрузить и исследовать как любой иной
Эти принципы подробно рассматриваются в разделе "Как обрабатываются связки".
Систему XBL можно использовать для реализации действий, выполнения которых требуют HTML и XUL-теги.
Такое действие по умолчанию можно видеть на примере тега HTML <input type="submit">. Когда мы
Ответ состоит в том, что действие по умолчанию можно встроить в
XBL-связку. Связка дает способ связать вместе событие
Данный виджет может иметь различное действие по умолчанию для
каждого порождаемого пользователем события. В случае тега <input
type="submit"> нажатие клавиш Return или Enter или
Разработчик приложения может изменить действие по умолчанию,
используя обычный обработчик событий. К этой задачке, однако, нужно
подходить аккуратно. Если обработчик события установлен в форме
значения атрибута (как, например, onclick ), то будет использован
именно он, а не обработчик XBL. Если обработчик события установлен с
помощью функции addEventListener(), то этот обработчик должен быть
установлен до того, как обработчик XBL будет включен в тег. Это
требование ставит обработчики приложения перед обработчиками XBL в
списке обработчиков события. См. замечания в разделе
"Скриптинг".
Система XBL не ответственна за обнаружение события и процесс "всплытия" события. Она не отвечает также за состояние фокуса и состояние фокусного кольца. Это вещи, обрабатываемые глубоко внутри C/С++-части кода платформы. Поддержка специальных функций (для людей с ограниченными возможностями) выполнена на XBL, но система ввода, которая осуществляет первую реакцию на команды этого типа, есть часть ядра системы.
Связки XBL имеют объектно-ориентированные свойства и могут
рассматриваться как объекты с точки зрения JavaScript или
XBL поддерживает традиционные концепции объектно-ориентированного подхода. В таблице 15.1 приведено описание поддержки ОО в XBL.
| Концепция | Поддержка в XBL |
|---|---|
| Теги XBL собирают контент (включая контент граничного тега) и код JavaScript в единую связку, сливая эксплицитный и |
|
| Локализация | Граничный тег хранит логику всего контента и JavaScript. XBL-связка может содержать другой граничный тег, и, следовательно, следующую связку |
| Граничный тег содержит всю полезную информацию о связке, хотя некоторая полезная информация может быть получена из JavaScript-объекта document | |
| Наследование | XBL имеет атрибут inherits, для наследования XBL-атрибутов, и атрибут extends, для наследования целых связок |
| Скрытие информации | Код подключенной связки скрыт и недоступен из граничного тега. Доступен только соответствующий интерфейс |
| Интерфейсы | Связка, предоставляющая интерфейс, может быть наследована другой связкой с помощью атрибута extends. Связка может поддерживать интерфейсы XPCOM с помощью атрибута |
| Позднее связывание | Связки подгружаются в граничный документ независимо и асинхронно. Связка может быть подгружена и выгружена в любое время с помощью правил |
| Объектность | Граничная связка с точки зрения JavaScript является объектом |
| Объектно-ориентированность | Атрибут extends позволяет XBL-связке быть основанной на ряде (цепочке наследования) других связок. См. Последующее обсуждение |
| Не поддерживается | |
| Определение типов | Не поддерживается. Можно использовать лишь интерфейс nsIClassInfo |
XBL-связка может наследовать другую связку. Та, в свою очередь,
может наследовать следующую. Множество унаследованных связок образует
упорядоченный список, называемый цепочкой наследования. Когда данный
граничный тег встраивается в документ, он является началом (головным
элементом) цепочки наследования. Он также называется первичной
связкой. Таким образом цепочка наследования всегда имеет длину не
меньше единицы. Если
На рисунке 15.1 приведен пример цепочки наследования, которую имеет
тег <button>.
(рис 15.1) Иерархия наследования для XUL-тега <button>.В примере показаны цепочки наследования трех элементов. Связка "button" привязана к тегу <button>. Эта связка -
начало цепочки наследования. Две другие связки - это связки общего
назначения, наследуемые во множестве мест в XUL. Связка button-base
используется во всех (или почти всех) кнопкоподобных виджетах, а
связка basetext используется во всех виджетах, имеющих дело с текстом.
Связки button и button-base определены в одном и том же XBL-документе,
(button.xml), а basetext в другом, general.xml. Все три связки
добавляют некоторое содержание в <button>.
Две связки могут наследовать одну базовую связку, так что полный граф цепочек наследования может выглядеть как дерево (или "роща" деревьев). Эта древоподобная структура может быть полезной в процессе проектирования, но ее нельзя исследовать или передвигаться по ней из скриптов.
В Таблице 15.2 описано, как наследуются различные свойства связок XBL.
| Свойство XBL | Наследуется? |
|---|---|
<resources> |
Все связки цепочки наследования загружают свои ресурсы. Все стилевые таблицы имеют по умолчанию одинаковый вес, но правила у начала цепочки подгружаются позже, и, следовательно, отменяют ранее загруженные правила |
<content> |
Нет наследования. Используется единственная связка из начала цепочки наследования. Если граничные теги содержатся в теге <content>, а не наследуются, используются их связки |
<field>, <property>, <method> |
Свойства и методы наследуются. Если имя составной связки совпадает с именем элементарной, составная замещает основную, и последняя становится недоступна из скриптов составной |
< и < |
Оба свойства наследуются. Конструкторы запускаются по одному, начиная с первой основной связки и заканчивая последней составной. |
< |
Обработчики событий наследуются. Обработчики событий составной связки отменяют действие обработчика базовой связки, если речь идет об одном и том же событии |
Атрибут display |
Нет наследования. Используется атрибут последней составной связки |
Система XBL - это очень простой набор компонентов. Он позволяет стандартизированным компонентам взаимодействовать удобным образом.
Компонентная система, подобная XBL - система модулей Perl,
доступных с помощью ключевых слов use и require. Обе системы
достаточно примитивны. К связкам XBL можно получить доступ через
Имена компонентов в системе XBL - это URLs в форме Resource#Id, где Resource - это web-адрес документа, а id - значение атрибута id тега <. Так же как id как ресурс, а
не как сдвиг (offset) в существующем ресурсе.
XBL не имеет регистра компонентов или их службы имен, и не имеет возможности доступа к внутреннему устройству связок. Вместо этого документ XUL или HTML имеет простой внутренний список активных связок, используемых данным документом.
Компонентная система XBL является распределенной системой, поскольку связка может быть получена по URL откуда угодно. Связки не имеют доступа к серверу, с которого были загружены, если только не содержат кода именно для этой цели.
Система XBL не имеет свойств, подобных сложным компонентным
системам, таким как COM от Microsoft, XPCOM самой платформы Mozilla,
Связка XBL может реализовывать один или несколько интерфейсов
XPCOM. Это позволяет объекту
Связки не могут вести себя как компоненты XPCOM до тех пор, пока они не привязаны.
Этот раздел описывает конкретные теги и атрибуты XBL.
Некоторые теги XBL имеют имена, совпадающие с именами, используемыми в Mozilla где-нибудь еще. При проектировании связки всегда неплохо указать полную ссылку на соответствующее пространство имен, чтобы избежать двусмысленности. Вот имена тегов XBL, используемые в другом значении:
<bindings> <body> <children> <content> <image>
Имена атрибутов, используемых в ином значении:
method action command modifiers charcode keycode key name readonly text
Большинство тегов XUL и HTML могут быть граничными в XBL. Чтобы тег мог быть граничным, он должен иметь фрейм - прямоугольную оформляемую стилями зону, в которой он высвечивается.
Тег со следующим атрибутом не имеет фрейма и не может быть граничным.
{ display: none; }
Тег, получающий этот атрибут, потеряет те связки, которые имел.
Поэтому граничный тег XUL должен иметь атрибут , а не ,
если нужно его спрятать.
Связываются в связки конкретные теги, а не имена тегов. Каждое
стилевое правило, содержащее -moz-, связывает набор конкретных
тегов. В листинге 15.3 приведен ряд примеров.
box { -moz-binding: url("binding.xml#sample"); }
#id { -moz-binding: url("binding.xml#sample"); }
.class { -moz-binding: url("binding.xml#sample"); }
box[X="here"] { -moz-binding: url("binding.xml#sample"); }
box,vbox,hbox { -moz-binding: url("binding.xml#sample"); }
box vbox { -moz-binding: url("binding.xml#sample"); }
Первая строка кода присоединит каждый конкретный тег <box> к
одной и той же связке. Каждый конкретный тег имеет собственный
интерфейс и свое class. Четверная строка – подмножество тегов <box>, имеющих атрибут X="here". Пятая строка – теги <box>, <, <hbox> и т.д. Если два правила
присоединяют один и тот же конкретный тег (а это очень неудачный
вариант), используется более конкретное правило, либо более позднее
правило, если селекторы одинаковы. То есть обычные правила выполнения
инструкций
Такая обработка стилевых правил используется в XUL для тегов,
имеющих различные варианты, наподобие тега <button>. Каждый
вариант использует различные связки. Их можно посмотреть в файле
xul.css архива
Можно явно указать отсутствие связок:
{ -moz-binding : none; }
Mozilla (по крайней мере, до версии 1.4) требует специальных приемов для добавления и уничтожения связок; следуйте советам, данным в разделе "Скриптинг", а не применяйте стилевые правила "в лоб".
Наконец, заметим, что есть одна давно известная ошибка (по крайней мере до версии 1.4). Тег со следующим стилем не будет работать корректно:
{ display: block; }
Потому что block не является частью XUL, это -moz-.
Тег < является верхним тегом в документе XBL. У него
нет специального значения и специальных атрибутов. Он может содержать
только теги <.
Декларация <!DOCTYPE> не обязательна для документов XBL. Если
такая декларация есть, необходимым минимумом является следующее:
<!DOCTYPE bindings>
Тег < содержит описание одной XBL-связки. Он может
иметь до четырех вложенных тегов. Каждый из следующих тегов может
появиться максимум один раз:
<resources> <content> <implementation> <handlers>
Все четыре тега опциональны. Рекомендуется, чтобы они были описаны
именно в данном порядке, но это не обязательно. Тег <
без контента бесполезен, за исключением того случая, когда он убирает
весь контент и все действия по умолчанию из граничного тега. Эффект
подобен действию стиля "-moz-.
Тег < имеет следующие специальные атрибуты:
id display extends inheritstyle
Атрибут id идентифицирует связку. Связка не имеет имени, а только
идентифицирующий ее URL. Если часть #id в этом URL отсутствует, будет
использован атрибут id первой связки в документе XBL.
Атрибут extends - это механизм наследования в XBL. Его можно
установить в URL следующей связки. Последовательность связок,
определяемых атрибутом extends, формирует цепочку наследования; это
обсуждалось в разделе "Объектные свойства связок".
Атрибут extends может иметь сокращенное значение. Его можно
использовать также для атрибута display. Оно состоит из префикса xul:
и имени тега XUL. Оно утверждает, что связка основывается на
существующем теге и должна использовать его свойства. В случае
атрибута extends, этот тег дает базовую реализацию связки. Пример:
extends="xul:box"
Атрибут display может иметь только сокращенное значение,
используемое для атрибута extends. Оно указывает, какой объект box
применяется в данной связке. Указанный объект box - один из тех,
которые обычно используются указанным тегом XUL. Пример:
display="xul:button"
Эта запись означает, что связка приобретет объект box, который
имеет XUL тег <button>.
Атрибут inheritstyle может иметь значение false. Его значение по
умолчанию true. Если его установить в false, граничный тег не
приобретет тех стилей, с помощью которых оформлялся до того, как к
нему была присоединена связка.
В теге <resources> указывается, какие еще документы требуются
данной связке. Он подобен HTML тегу <LINK>. Тег <resources> не имеет специальных атрибутов и может содержать
только следующие теги:
<image> <stylesheet>
Можно указать ноль или более этих тегов. Последовательность не
имеет значения, за исключением того, что более поздние теги <stylesheet> будут применены после более ранних. Система XBL
обходится не слишком интеллектуально с содержанием тега <resources>, как описывается далее.
Тег <image> идентичен одноименному XUL-тегу, кроме того, что
здесь единственным используемым атрибутом является src. Так же, как в
XUL, src определяет URL изображения. <image src="
XBL ничего не делает с этим тегом, лишь предписывает платформе
Mozilla получить это изображение и кэширует его. Это подсказка
платформе, что данное изображение важно и может понадобиться позже.
Оно может понадобиться в XUL теге <image>, HTML теге <img>, liststyle-image, или в контентной части
XBL-определения. Указание этого тега - лишь оптимизация
выполнения.
Тег <stylesheet> идентичен HTML тегу <style src=>. Он
не может иметь иного собственного контента.
<stylesheet src="chrome://global/skin/button.css"/>
Стилевые таблицы используются в XBL, чтобы хранить все детали
визуализации виджета. Это позволяет виджетам быть зависящими от темы.
Это также дает возможность сконструировать стилевые правила так, чтобы
они применялись лишь к <button>
(основанного на XBL связке с id="button" ) сохранялись по
зависящему от темы URL.
Можно использовать более одного тега <stylesheet> на связку,
но это делается редко. Если такое случается, стили прикладываются в
порядке их появления.
Если связка имеет цепочку наследования других связок, и они также
имеют теги <stylesheet>, все стилевые таблицы будут
использованы. Они прикладываются в порядке от конца цепочки к ее
началу, так что первичная стилевая таблица имеет преимущество.
Все стандартные связки тегов, хранимые в
Тег <content> содержит весь <children>,
специфичный для XBL. <script>, не работают в анонимном контенте.
Тег <content> имеет два специальных атрибута:
includes excludes
Оба атрибута считаются устаревшими, их следует избегать.
Используйте вместо них в анонимном контенте тег <children>. Если
в теге <content> появляются любые другие атрибуты, они будут
скопированы в граничный тег.
Атрибуты граничного тега могут быть добавлены тегам внутри тега <content> с помощью атрибута inherits. Эксплицитный контент
граничного тега может быть слит с тегами внутри тега <content> с
помощью тега <children>.
Если связка использует атрибут extends, так что строится на основе
другой связки, тег <content> в этой другой связке
игнорируется.
Если тег <content> связки пуст, граничный тег также не будет
иметь контента.
<content> может быть фрагментом
документа любого типа и любого размера. Тег <children> может
появиться в любом месте этого фрагмента.
Отличные от XBL теги в контенте могут использовать один атрибут
XBL, а именно inherits. Этот атрибут служит для того, чтобы передать
параметры и их значения из граничного тега
Этот механизм дает пользователю возможность управлять inherits в
Атрибут inherits содержит разделенный запятыми или пробелами список
соответствий атрибутов. В списке соответствий указывается, какой
атрибут
att1 att1=att2 xbl:text=att2 att1=xbl:text
att1 и att2 - любые правильные имена атрибутов XML.
Первая запись утверждает, что атрибут граничного тега att1 и его
значение должны быть просто скопированы в
Вторая форма записи говорит о том, что атрибут att1 att2 граничного тега.
Третья форма использует специальное зарезервированное имя xbl:text.
Она говорит, что <текстовое> содержание att2 граничного тега. Это
дает тот же эффект, что и использование тега <textnode> в
шаблонах XUL.
Четвертая форма говорит, что атрибут att1
Поскольку атрибут inherits является атрибутом XBL, он не может
появиться в не-XBL теге. Он должен быть полностью определен, включая
его пространство имен XML. Это достигается благодаря префиксу xbl:
(или подобному) и добавлению полной декларации пространства имен в
начале документа XML. В силу этих причин XBL документы часто имеют две
ссылки на пространство имен XBL:
<bindings id="test" xmlns="http://www.mozilla.org/xbl" xmlns:xbl="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" >
Первое пространство имен XBL обычное по умолчанию, второе
указывается специально для атрибута inherits.
Если все это соединить, получится следующий пример атрибута inherits:
<xul:label dir="ltr" xbl:inherits="xbl:text=value,style,align=justify"/>
Если граничный тег был таким:
<mytag value="Test" style="color:red" justify="start"/>
то после замены <xul:label> будет заменен на:
<xul:label dir="ltr" style="color:red" align="start"> Test </xul:label>
Атрибут inherits может быть использован в любом месте dir=". Если специальный атрибут xbl:text использован более
одного раза, все определенные значения появятся в текстовой ноде
Тег <children> управляет слиянием эксплицитного контента
граничного тега (если он есть) с <content>. Тег <children> может появиться в любом
месте
includes
Атрибут includes может содержать разделенный запятыми список имен
тегов. Определения пространства имен не требуется. Этот атрибут
изменяет процесс слияния контентов. Вот обзор возможностей:
<children> в
анонимном контенте игнорируются. Это все равно что удалить все теги <children> из секции <content>, но оставить остальные теги
нетронутыми. Финальный контент является копией оставшегося <children>. Если это условие выполняется, финальным
контентом будет объединенная копия эксплицитного и <children> в анонимном контенте использовались некорректно, либо
в граничном теге есть некоторый неучтенный эксплицитный контент. В
этом случае результат объединения непредсказуем.Последние два случая требуют дальнейшего уточнения. Процесс слияния
контента целиком определяется тегом <children>. Этот тег создает
иллюзию, будто эксплицитный контент добавляется к
Если у тега <children> нет атрибута includes, эксплицитным
контентом будет замещен и сам тег <children>, и <children>.
Если атрибут includes есть, тег <children> будет замещен лишь
частью эксплицитного контента. Будут размещены все непосредственные
дочерние теги граничного тега, чьи имена совпадают со списком в
атрибуте includes. Они будут помещены в той точке <children>. Они будут размещены в том же
порядке, в каком были в граничном теге.
3. Если пункт 2 повторяется аккуратно, то окажется достаточно тегов <children includes=>, чтобы разместить весь эксплицитный
контент. В этом случае весь эксплицитный и
4. Если пункт 2 не повторяется достаточное количество раз,
некоторые непосредственные дочерние теги граничного тега не найдут для
себя соответствующего тега <children includes=>. Это неполный
охват эксплицитных тегов. Mozilla сама добавит весь эксплицитный
контент в финальный контент, а весь
Если пункт 2 реализован небрежно, некоторые дочерние теги
граничного тега могут соответствовать более чем одному тегу <children>. Это непорядок, в таком случае результат может быть
непредсказуем. В итоге разработчик связки должен либо (a) не делать
никаких предположений об эксплицитном контенте граничного тега и
избегать использовать includes, либо (b) полностью предвидеть, что
граничный тег будет размещать в анонимном контенте и использовать includes везде; или (c) делать обоснованные догадки и положиться на
то, что система XBL придумает здесь что-то более или менее
рациональное.
Листинг 15.4 демонстрирует корректный пример этой системы в действии.
<!-- tag to be bound -->
<mytag>
<image src="face.png"/>
<description label="Smile"/>
<image src="face.png"/>
</mytag>
<!-- Example 1: unknown explicit content -->
<content>
<box>
<children/>
</box>
</content>
<!-- Example 2: known explicit content -->
<content>
<children includes="description"/>
<box>
<children includes="image"/>
</box>
</content>
<!-- Example 3: known but optional explicit content -->
<content>
<children includes="image|description">
<label value="No emoticon supplied"/>
</children>
</content>
В данном листинге тег <mytag> - граничный. Остальные
фрагменты принадлежат трем разным связкам. Пример 1 добавляет весь,
неважно какой, эксплицитный контент. Пример 2 корректно добавит каждый
тип эксплицитного контента в соответствующем месте. Пример 3 также
добавит эксплицитный контент, но если его нет, вместо него будет
использоваться тег <label>. В листинге 15.5. приведен финальный
контент для всех этих случаев.
<!-- Example 1: unknown explicit content -->
<mytag>
<box>
<image src="face.png"/>
<description label="Smile"/>
<image src="face.png"/>
</box>
</mytag>
<!-- Example 2: known explicit content -->
<mytag>
<description label="Smile"/>
<box>
<image src="face.png"/>
<image src="face.png"/>
</box>
</mytag>
<!-- Example 3: known but optional explicit content -->
<mytag>
<image src="face.png"/>
<description label="Smile"/>
<image src="face.png"/>
</mytag>
Если исходный контент тега <mytag> сильно изменить, пример 1
останется работающим, в то время как 2 и 3 могут дать неожиданные
результаты.
В примере листинга 15.6 приведена конструкция, которая никогда не
будет работать надежно, потому что теги <image> эксплицитного
контента не соответствуют ни одному из двух тегов контента
<content>
<children/>
<box>
<children includes="image"/>
</box>
</content>
<content> сам, в свою очередь,
может включать граничные теги для некоторой XBL связки. Это вполне
допустимо, поскольку большинство XUL-тегов - граничные теги.
XBL автоматически поддерживает граничные теги как
Можно сконструировать циклы вложения, но этого следует избегать.
Тег <content> не должен содержать свой собственный граничный
тег.
Тег < - это простой тег-контейнер. Он
реализует объектоподобный интерфейс связки. Этот интерфейс реализуется
на JavaScript. Впоследствии он будет доступен скриптам JavaScript,
работающим вне граничного тега. Созданный интерфейс доступен, как
свойства и методы граничного тега.
Тег < имеет один специальный атрибут:
implements
Этому атрибуту можно присвоить список (разделенный пробелами или
запятыми) имен интерфейсов XPCOM, таких как nsISimpleEnumerator или nsIDOMEventListener. Может быть использовано любое имя интерфейса.
Платформа Mozilla посчитает связку как соединенный через XPConnect
компонент XPCOM и использует эти имена, чтобы определить, что связка
должна делать. Тогда уж заботой разработчика связки будет, чтобы она
выполняла то, что обещает. Система XBL автоматически добавляет
функциональность, эквивалентную интерфейсу nsISupports.
Если любой из этих интерфейсов реализован и объявлен, они появляются как интерфейсы граничного тега.
Атрибут type не поддерживается тегом < или его
подтегами. Подразумевается, что используется язык JavaScript.
Рекомендуется задействовать синтаксис XML <![, если
ваши скрипты имеют заметный размер.
Тег < может содержать в качестве дочерних
любые из следующих тегов, в любом порядке:
<field> <property> <method>
Тег < также может содержать один из следующих
тегов:
<constructor> <destructor>
Все эти пять тегов содержат скрипты на языке JavaScript. Эти скрипты имеют доступ к некоторым хорошо известным свойствам JavaScript:
this window document event
Свойства window и document - те же самые, что используются в XUL и
HTML и относятся к свойствам window и document граничного тега.
Свойство this относится к объекту getAttribute(). Свойство event существует только для тега < и содержит объект
Имейте в виду, что в секции < свойство this
имеет особенность. Все простые значения, присваиваемые свойствам
объекта this, автоматически конвертируются в тип "строка".
Согласно этому правилу, следующий код вернет строку
"1213":
this.dozen = 12; alert(dozen + 13);
Это преобразование заметно только при использовании оператора "+". В других математических операторах строки будут автоматически конвертированы в числа, и мы не заметим преобразования в строку. Простая подсказка - храните значения в объектах. Следующая строка кода вернет 25:
this.d = {}; d.dozen = 12; alert(d.dozen + 13);
Связка без тега < также полезна. Она может
отображать контент и обрабатывать события.
В листинге 15.7 дан пример некоторого XBL-объекта. Он реализует экспериментальную осветительную лампу. Каждый раз, когда лампа включается, ее возраст слегка увеличивается, а мощность слегка падает. Наверное, пытаться включать и выключать ее не слишком эффективно.
<implementation>
<field name="rating" readonly="true">60</field>
<field name="lit">true</field>
<field name="age">0</field>
<property name="power"
onget="age++; return rating-age/1000;"
onset="age=(rating-val)*1000;" >
<method name="toggle">
<body>
if ( this.power > 30 ) this.lit = !this.lit;
</body>
</method>
</implementation>
Этот объект имеет четыре свойства: (значение мощности,
здесь, видимо, в ваттах), lit (булева константа) age (целое) и power
(динамически вычисляемое значение). Он имеет один метод: .
Имена свойств появляются и в значениях атрибутов XBL-тегов, и в коде
JavaScript. Например, метод использует свойства power и lit,
чьи имена также появляются как значения атрибута name тега <field>.
Интерфейс в листинге 15.7 эквивалентен объекту JavaScript в листинге 15.8.
var bulb = {
const rating : 60,
lit : true,
age : 0,
get power() { age++; return rating-age/1000; },
set power(val) { age=(rating-val)*1000; },
toggle : function () {
if ( this.power > 30 ) this.lit = !this.lit;
}
};
Очевидно, оба листинга очень похожи. Почему же не использовать простой объект JavaScript и не отказаться от XBL? Такой объект придется вручную указывать для каждого тега, где это будет нужно, используя скрипты. При использовании XBL объект появится автоматически везде, где ему будет предписано появиться правилами CSS связки XBL.
Тег <field> - самая простая часть интерфейса связки. Он
предназначен для сохранения значения простой переменной. Используется
для хранения информации о состоянии, указываемой программистом, для
каждого граничного тега. Тег <property> - более гибкая версия
тега <field>.
<field> имеет два специальных атрибута:
name readonly
Атрибут name хранит имя свойства JavaScript. Это должно быть
правильное значение имени переменной JavaScript.
Атрибут readonly может иметь значение true, в этом случае значение field нельзя изменить скриптом.
<field> имеет следующий синтаксис:
<field>JavaScript expression</field>
Обратите внимание, что содержание тега есть выражение, а не утверждение (statement). Поскольку выражение вычисляется лишь один раз, обычно это простое выражение, но оно может быть, если потребуется, и сложным. Примеры:
<field name="count">3+2</field> <field name="address" readonly="true">"12 High St"</field> <field name="phonelist">[]</field>
Примеры выглядят странно, поскольку нет явного присваивания. Вместо этого система XBL определяет значения выражений и использует результат. Эти теги подобны следующим утверждениям JavaScript:
Однажды созданные теги fields являются свойствами объекта
граничного тега, (т.е. то же самое, что this ), и их далее можно
использовать обычным образом.
Тег <property> предназначен для сохранения простой
переменной, как и тег <field>. Эта переменная доступна как
свойство JavaScript объекта граничного тега.
Разница между <property> и <field> состоит в том, что
переменная тега <property> ведет себя как интерфейс, в то время
как переменная тега <field> - как простое значение.
Значение переменной <property> может динамически вычисляться,
когда она читается или записывается, и обе операции могут иметь
вторичные эффекты. Это значит, что скрипт, использующий property,
может вызывать иные процессы, получая или устанавливая ее
значение.
Вспомним лекцию 5, "Сценарии". Свойство property
JavaScript может быть определено с функциями __defineGetter__ и __defineSetter__.
Тег <property> работает точно таким же образом, за
исключением того, что свойство property прописывается здесь тегами < и < или сокращенно, атрибутами onget и onset.
Тег <property> имеет четыре специальных атрибута:
name readonly onget onset
name - имя свойства JavaScript, которое это свойство определяет.
Оно должно быть правильным именем JavaScript.
readonly означает, что property ведет себя как неизменяемая
переменная JavaScript. Переменная может быть прочитана, но не
изменена.
onget - сокращенная запись тега <, она содержит в
качестве значения скрипт. Если присутствуют и onget, и <,
используется onget.
onset - сокращенная запись тега <, она содержит в
качестве значения скрипт. Если присутствуют и onset, и <, используется onset. onset бесполезен, если указано readonly="true".
Тег <property> может иметь ноль или более тегов < и <. Контент этих тегов - функции
JavaScript.
Тег < и атрибут onget должны содержать
последовательность сообщений JavaScript. Возвращается результат этой
последовательности.
Тег < и атрибут onset также должны содержать
последовательность сообщений JavaScript, но возвращается значение
переменной . Специальная переменная содержит устанавливаемое
значение.
В листинге 15.7 приведен простой пример onget и onset.
Эквивалентный синтаксис с тегами < и <
приведен в листинге 15.9. Секцию в данном примере можно не
использовать, поскольку код тривиален. Повсюду, для ясности,
применяется ключевое слово this - это рекомендуемая практика.
<property name="power">
<getter>
<![CDATA[ this.age++; return this.rating - this.age/1000; ]]>
</getter>
<setter>
<![CDATA[ this.age = (this.rating - val) * 1000; return val; ]]>
</setter>
</property>
Если < и onset не определены, и делается попытка
присвоить значение с помощью этого свойства, на консоли JavaScript
появится сообщение об ошибке (или генерируется исключение). Если
предпринимается попытка получить значение данного свойства, когда ни <, ни onget не определены, будет возвращено значение .
Тег <method> используется для определения метода интерфейса.
Он содержит ноль или более тегов <, за которыми
следует в точности один тег <body>. Тег <method> имеет
один специальный атрибут:
name
Атрибут name указывает имя свойства JavaScript, содержащего объект Function, так что оно должно быть правильным идентификатором
JavaScript. Тег <method> не поддерживает атрибут action, и
Mozilla может упасть, если его использовать.
Если должны применяться цепочки наследования, не получится
использовать тег <method>, если он был перезаписан
унаследованным тегом <method> с тем же именем. Нельзя работать с
методом, который был перезаписан.
Тег < имеет тот же синтаксис, что и тег <method>. Его единственный атрибут name определяет одно имя
переменной, передаваемой методу. Порядок тегов < тот
же самый, что и порядок передаваемых переменных.
Теги <method> и < не используются для
создания полностью типизированных функций-сигнатур. Они используются
просто как имена. Нет проверки типов или даже подсчета аргументов. Нет
преобразования типов, за исключением того, который предоставляет сам
язык JavaScript. Нет возможности указать тип возвращаемого значения.
Это очень упрощенные теги.
Невозможно создать два метода с одним именем, но разным числом параметров. Но поскольку все функции JavaScript поддерживают списки аргументов, нет нужды такие вариации создавать.
Наконец, тег <body> содержит те сообщения JavaScript, которые
образуют метод. Этот тег не имеет специальных атрибутов. Если метод
должен что-то возвращать, следует использовать сообщение return.
Объект arguments, определенный для всех функций JavaScript, также
можно использовать в содержании тега <body>.
Листинг 15.10 демонстрирует, как эти теги работают вместе:
<method name="play">
<parameter name="boy"/>
<parameter name="dog"/>
<parameter name="ball"/>
<body>
<![CDATA[
if ( arguments.length != 3)
throw Components.results.NS_ERROR_INVALID_ARG;
if ( boy == "Tom" dog == "Spot" ) {
return document.fetch(ball.type);
}
return null;
]]>
</body>
</method>
Этот пример показывает, что проверка передаваемых аргументов должна
быть выполнена вручную. Можно использовать сообщение throw
чтобы остановить выполнение метода и вернуть исключение в
вызывающий код. В этом примере возвращаемое значение - одно из
официальных значений ошибок XPCOM. Если используется одна из этих
констант, метод будет соответствовать стандартам компонентов XPCOM.
- это метод или функция,
определенная где-то вне XBL-связки.
function play(boy, dog, ball) {
if ( arguments.length != 3)
throw Components.results.NS_ERROR_INVALID_ARG;
if ( boy == "Tom" dog == "Spot" ) {
return document.fetch(ball.type);
}
return null;
}
Эти два листинга даже трудно различить, так что неудивительно, что
содержание тега <method> конвертируется в JavaScript, как только
документ XBL загружается и парсится.
Теги < и < - это обработчики
событий, которые запускаются лишь однажды за время жизни связки. Они
используются для инициализации и очистки, как и все конструкторы и
Они имеют один специальный атрибут:
action
Атрибут action - сокращение для содержания тегов < и <. Это содержание - тело
функции JavaScript, так же как в XBL теге <body>. Его можно
поместить между открывающим и action. Если используются оба способа, применяется атрибут action, хотя так делать вряд ли имеет смысл.
Тег < выполняет свою работу, когда связка
объединяется с граничным тегом. Это может быть очень большое число
раз, и если так, то нужно проследить, чтобы действие конструктора
имело оптимальный код. Невозможно управлять связкой в цепочке
наследования, используя этот тег. Нет также возможности управлять
каким-либо граничным тегом в секции <content> из тега <. Коду конструктора аргументы не передаются, но
указатель this всегда доступен. Код конструктора не обязан возвращать
какое-либо значение.
Если текущая связка наследует иную связку, то теги < запускаются в порядке от конца к началу в цепочке
наследования, другими словами, тег < первичной
связки будет в последним.
Тег < выполняет свое действие, когда связка
отсоединяется от граничного тега. Редко когда это случается без того,
чтобы весь целевой документ не был закрыт, но если связка управляется
вручную, или поддерживается состояние, разделяемое многими окнами, тег < может быть полезен. Так же, как и для тега <, здесь нет возможности воздействовать на связки,
являющиеся частями текущей связки. Коду
Если текущая связка расширяет (наследуется из) другой связки, то
теги < запускаются в порядке от начала к концу в
цепочке наследования - другими словами, тег <
первичной связки будет в последовательности первым.
Обычная практика - создавать объекты XPCOM из конструктора. Если требуется лишь один такой объект для данной связки, а не по объекту на каждый граничный тег, то обычный способ устроить это показан в листинге 15.12.
<constructor>
<![CDATA[ if (!document.globalPicker) {
var Cc = Components.classes;
var Ci = Components.interfaces;
var comp = Cc["@mozilla.org/filepicker;1"];
document.globalPicker = comp.getService(Ci.nsIFilePicker);
}
]]>
</constructor>
В этом коде каждый граничный тег проверяет, была ли уже проведена
инициализация, и если была, просто игнорирует этот шаг. Все связки
объединяются в разное время, но поскольку Mozilla выполняет лишь одну
задачу одновременно (
Тег < - простой контейнер, содержащий все
обработчики событий XBL-связки. Он не имеет собственных специальных
атрибутов. Он содержит один или более тегов <. Каждый
тег отвечает за исполнение некоторого кода JavaScript в ответ
на событие
Связки XBL в директории
Обработчики событий, определяемые в XBL, - один из четырех
источников обработчиков событий в Mozilla. Лекция 6,
"События", описывает поддержку обработчиков в стиле "on...". Там также описывается тег <key>. Его
синтаксис очень похож на синтаксис тега <. Последний тип
обработчиков зарыт в самой глубине платформы. Эти обработчики написаны
на C/C++ и автоматически устанавливаются платформой при первом
открытии окна.
Этот последний тип обработчиков - обработчики по умолчанию, которые
действуют, если ничто иное не установлено. Платформа Mozilla создает
специальный контроллер команд для обработки фокуса и точно так же
устанавливает ряд специальных обработчиков для наиболее типичных
событий. Когда добавляются обработчики <key>, они пристраиваются
на верхушку группы фундаментальных обработчиков, так же, как
определенные в приложении обработчики onclick пристраиваются на
верхушку XBL-связок. Когда добавляются обработчики <,
они располагаются рядом с фундаментальными обработчиками, как если бы
и те, и другие были зарегистрированы с помощью addEventListener().
Хотя последний, наиболее фундаментальный тип обработчиков
реализован как часть XBL системы, они недоступны для прикладных
программистов. Главное, на что следует обратить внимание, это то, что
есть обработчики, лежащие ниже XBL системы, и поиск в
Тег < очень похож на XUL-тег <key>. Он
определяет одну цель события (event target) и одно действие для одного
точно определенного события. Действие - либо фрагмент скрипта, либо
команда.
Тег < реализует действие по умолчанию для события,
возникающего в граничном теге. Оно может быть переопределено в самом
граничном теге с помощью обычного обработчика событий
Чтобы обработчик начал действовать, в граничном теге должно
возникнуть соответствующее событие. Это значит, что событие должно
быть создано либо действием пользователя, как последовательность
изменений документа, либо с помощью метода dispatchEvent().
Обсуждение событий XBL следует ниже, в разделе "Скриптинг"
этой лекции.
Тег < имеет следующие специальные атрибуты:
event phase command modifiers clickcount key keycode charcode button action
Атрибут event определяет mousedown - пример события, которое не
имеет значения по умолчанию.
Атрибут определяет, на какой стадии события в цикле ", "target" или "bubbling".
По-умолчанию "bubbling".
Атрибут command определяет команду (как описано в лекции 9,
"Команды"), которая будет выполняться, когда возникнет
событие. Однако контроллер, используемый для поиска и выполнения
команды, будет определяться тегом, имеющим фокус, а не граничным тегом
связки. Это значит, что связка должна быть способна иметь фокус, как
целое. Иначе придется предпринять некоторые действия, чтобы убедиться,
что часть связки, имеющая фокус, имеет и подходящий контроллер. command и action - взаимоисключающие атрибуты. Атрибут command не
имеет действия по умолчанию.
Атрибут modifiers имеет список значений, разделенный
пробелами или запятыми, а именно shift, control, alt, meta, accel и access. Он используется, чтобы определить,
какие модификаторы клавиш должны быть нажаты, чтобы клавиатурное
событие имело место. Все указанные модификаторы должны быть нажаты. accel - общий, платформеннонезависимый модификатор, описываемый в
лекции 6, "События". access соответствует случаю, когда
нажимается "горячая клавиша". Горячие клавиши определяются
XUL-тегом key= attribute. По умолчанию модификаторов клавиш нет.
Атрибут clickcount используется только для событий мыши. Он
содержит единственную цифру, определяющую, сколько
Атрибут key используется только для клавиатурных событий. Он
содержит единственный печатаемый символ, например "A". Нужно
использовать либо key, либо keycode для клавиатурных событий, но не
оба атрибута вместе. Значения по умолчанию нет.
Атрибут keycode используется только для клавиатурных событий. Он
содержит единственный код VK_ из списка в Таблице 6.3. Нужно
использовать либо key, либо keycode для клавиатурных событий, но не
оба атрибута вместе. Значения по умолчанию нет.
Атрибут charcode - устаревшее название атрибута key. Используйте key.
Атрибут button используется только для событий мыши. Он содержит
единственную цифру, определяющую, какая клавиша мыши нажата. Число
клавишей мыши определяется операционной системой, Mozilla поддерживает
по крайней мере три клавиши. Первая клавиша - клавиша 0. По умолчанию
- любая клавиша. На двух- или трехкнопочных мышах правая клавиша - 2.
Атрибут action содержит скрипт, который должен выполняться, когда
возникнет событие. Атрибуты action и command - взаимоисключающие.
Значения по умолчанию нет.
Если не определены ни command, ни action, можно пометить обработчик
событий на JavaScript между началом и концом тега <. Вот
пример:
<handler event="click" phase="target" clickcount="1" button="0"> this.do_custom_click(); // a <method> of the binding </handler>
Отныне это будет действием по умолчанию для события:
"единичный do_custom_click() определен где-то в связке, так что он может быть
вызван прямо в
Система XBL имеет ресурс тегов, которых нет, но кажется, что они существуют. Следующее описание применимо к версиям до 1.4.
Атрибут type для тегов <, <method> и
иных.
Атрибут applyauthorsheets тега <content>.
Атрибут applybindingsheets тега <children>.
Тег <element> и все ссылающиеся на него.
Следующие события не поддерживаются:
contentgenerated, contentdestroyed, bindingattached, bindingdetached.
Следующие два атрибута сохранились от ранних версий XBL и их
следует избегать: атрибут includes при использовании с тегом <content> и атрибут charcode при использовании с тегом <.
Тег <script> не является частью XBL и в чистом XBL работать
не будет.
Следующие атрибуты ничего не делают:
attachto applyauthorstyles styleexplicitcontent
Система наследования XBL была рассмотрена ранее в разделе "Объектоподобные свойства связок" ранее в этой лекции. Здесь мы рассмотрим ее использование. Только создатель связки может использовать наследуемые связки.
Листинг 15.13 показывает связки, связанные наследованием.
<!-- both bindings contained in example.xml -->
<binding id="smileyA">
<content>
<xul:image src="faceA.png"/>
</content>
<implementation>
<method name="methodA">
<body> return true;
</body>
</method>
</implementation>
</binding>
<binding id="smileyB" extends="example.xml#smileyA">
<content>
<xul:image src="faceB.png"/>
</content>
<implementation>
<method name="methodB">
<body> return false;
</body>
</method>
</implementation>
</binding>
В таблице 15.2 описывается, как наследуются различные части связки.
Если связка smileyA соединяется с XUL-тегом, этот тег будет иметь в
качестве контента лишь тег <image src="faceA.png">, и
один метод, methodA(). В этом случае цепочка наследования граничного
тега имеет длину 1 и содержит лишь связку smileyA. Здесь нет
наследования, и smileyA - первичная связка.
Если с XUL-тегом связывается smileyB, то этот тег будет иметь в
качестве контента единственный тег <image src="faceB.png">,
и два метода, methodA() и methodB(). В этом
случае цепочка наследования граничного тега имеет длину 1 и содержит
связку smileyB в начале и связку smileyA в хвосте цепочки. В этом
случае наследование есть, и smileyB - первичная связка.
Обе связки можно применять к разным тегам в одно и то же время.
Невозможно сказать, наследуется ли данная связка, поскольку ее URL
может быть использован откуда угодно. Если связка расположена в
Популярный прием, часто используемый в Mozilla - использовать
логику набора связок в связке без содержания. Такая связка не имеет
секций <resources> или <content>, и никогда (или редко)
непосредственно связывается с тегом. Она содержит главным образом
программную логику и информацию о состоянии.
Если другая связка использует данную как основу, методы и обработчики связки с нулевым контентом будут присоединены к расширяемой связке во время выполнения. Связку с нулевым контентом можно использовать много раз с разными целями. В терминах объектно- ориентированного программирования, связка с нулевым содержанием может быть названа "базовый класс с виртуальным содержанием".
Примером такой связки с нулевым контентом может быть связка button-base в файле button.xml архива
properties: accessible type dlgType group open checked check- State autoCheck handlers: event="command"
Эти свойства и события отвечают за управление рядом состояний,
используемых кнопкоподобными виджетами. Например, свойство checked
имеет скриптовые логики < и <, которые
позволяют граничному тегу иметь < или < -подобные состояния. Эти логики выполняют
домашнюю работу в граничном теге, устанавливая атрибуты XML и
координируя состояние checked с другими возможными атрибутами.
Логика в такой связке наследуется многими другими связками. Эти
связки, в свою очередь, наследуются многими тегами XUL: всеми
разновидностями <button>, всеми вариантами <toolbarbutton>, <, <dropmarker>, <, <menu>, кнопками в <wizard> и < -подобными окнами и т.д. Ясно, что связка button-base
используется очень широко.
Теги, основанные на связках с нулевым контентом, позволяют избежать
ненужного удвоения кода. Когда некоторый тег использует такую связку,
он должен иметь секцию <content>.
Можно создать связку XBL для обработки пользовательского ввода.
Такая связка имеет большую секцию < и понемногу всего
остального, хотя может иметь также методы и свойства.
Такие связки называются "фасадом ввода" по двум причинам. Во-первых, они создают слой обработки событий и пользовательского ввода в форме набора обработчиков. Это похоже на прилавок магазина. Во вторых, они полагаются на некие иные связки для обеспечения требуемого виджет-специфичного поведения. Это "тонкие" связки, а фасад - тонкая вещь. Вот простейший пример "фасада ввода":
<binding id="click-facade" extends="bindings.xml#base-widget">
<handlers>
<handler event="click"> this.click(); </handler>
</handlers>
</binding>
Эта простая связка возводит фасад ввода между вводом единичного
click() - эта задача
остается для некоторой иной связки. Данный метод может быть
стандартным (в этом случае его обеспечивает связка base- ), или
высокоспециализированным (в этом случае его обеспечит связка,
расширяющая связку click-facade ).
Код обработчика в этой связке может быть и посложнее. Может потребоваться управлять состоянием, включающим и выключающим определенный тип ввода, в зависимости от истории ввода. Фасад ввода - это еще одно место, где можно разместить функциональность обработки пользовательского ввода.
Так же, как и связка с нулевым содержанием, связки фасада ввода
редко непосредственно связываются прямо с тегом. Их главная цель -
извлечение из набора связок общей семантики пользовательского ввода и
сохранение этой семантики в одном месте. Отсутствие секции <content> подразумевает, что она должна быть расширена
(наследоваться) перед использованием.
В Платформе Mozilla (до версии 1.4) нет фасадов ввода, но есть
простор для их применения. Если вы заглянете в связки XBL для тегов <tree>, <listbox>, <tabbox> и HTML <select>,
то увидите одинаковое поведение при обработке клавиатурного ввода во
всех этих связках. Это подмножество кода может быть объединено в
фасадах ввода и затем использоваться в любом виджете, обеспечивая
однотипное поведение.
Mozilla сейчас имеет одну разновидность фасадов ввода. Это
документы XUL, содержащие набор связок <key>. Эти документы
включаются в большинство приложений Mozilla через оверлеи. Так же как
фасады ввода XBL характерны для связок XBL, фасады ввода XUL в форме
наборов связок <key> характерны для документов XUL.
Название этой лекции предполагает, что связки используются для создания законченного виджета, и это конечно так. Но возможны связки для реализации лишь части виджета. Такие связки называются связками внутреннего контента.
Связки внутреннего контента создавать просто. Нужно сделать
некоторые предположения о родительском теге граничного тега такой
связки. Мы предполагаем, что граничный тег будет предоставлять контент
своему родительскому тегу, который должен являться контейнером.
Контейнер отвечает за границы виджета. Связка внутреннего контента
полагается на то, что родительский тег будет работать корректно. В XUL
очевидными контейнерами являются <box>, <button>, <menupopup>, <scrollbar> и <.
Связки внутреннего контента зависят от родительского тега граничного тега и тесно связаны с ним. Такая связка может предоставлять методы и свойства, ожидаемые родительским тегом, либо иную информацию. Эта тесная связка подразумевает, что связка сама по себе будет выглядеть неважно. А вызванная из соответствующего контейнера, она будет отлично ему соответствовать.
В XUL несколько связок следуют этой философии. Например, теги,
используемые внутри тега <scrollbar>: <, < и <scrollbarbutton>. Не все эти теги имеют
XBL-связки, но все они полагаются на родительский тег для корректного
функционирования. Примеры тегов с XBL связками: тег <dropmarker>
внутри тега <button> и <tabs> внутри <tabbox>.
Когда связка привязывается к тегу в целевом документе, она проходит следующий путь:
-moz-binding у некоторого загружаемого тега.onload.extends, шаги 2-7 повторяются (параллельно) для каждой связки в цепочке наследования. Так что какая-то другая связка может достичь шага 7 до первичной связки.<content> копируются в граничный тег.<handler > устанавливаются в граничном теге с помощью менеджера связывания.<property> и <method> добавляются <constructor > в цепочке наследования.onload задач уменьшается на единицу.Для JavaScript граничный тег выглядит как обычный объект
Свойства могут вызываться как методы, или присваиваться, или быть прочитаны.
Свойства могут быть добавлены или установлены в null. Свойства,
содержащие методы (объекты Function ), могут быть изменены
определенными нами методами.
Обработчики событий, загруженные с помощью стилевого атрибута on..., или с помощью addEventListener(), могут заменить
собой обработчики связки.
Интерфейсы
Интерфейсы
Ни одно из этих действий не затрагивает XBL документ связки для граничного тега.
Программисту XBL связки следует в первую очередь обратить внимание
на время загрузки связки. Общего способа определить, закончился ли
процесс загрузки связки, нет. Единственный способ удостовериться в
этом - использовать обработчик onload документа, к которому
принадлежит данный тег, и избегать шаблонов с отложенной
("ленивой") загрузкой (lazy-loading templates). Если вы
используете целиком вручную написанные связки, снабдите их некоторым
сигналом, что загрузка окончена.
Другой важный аспект скриптования граничного тега имеет дело с
обработкой событий. Это материя обычных
Обычно события event. Свойство event.originalTarget этого объекта очень часто используется в связке;
(в версии 1.4 свойство event.target еще не надежно).
Если, однако, граничный тег не является частью фокусного кольца
данного окна (как, например, тег XUL <box> ), часть объединяемого
контента все еще может получить событие. В частности, если
объединяемый контент содержит теги, являющиеся кандидатами в фокусное
кольцо (как < или <button> ), эти теги могут
получить фокус клавишей tab. Здесь работает следующий принцип:
Если тег может быть способен получить фокус, а его родительский тег - нет, то пусть он его получит.
Система связок XBL не имеет интерфейса для "обновления" или "перестройки", которым можно было бы обновить граничный тег. Граничный тег может только целиком получить или потерять связку. Существует два способа сделать это.
Первый путь - изменить связку граничного тега: модифицировать
свойство стиля -mozbinding скриптом. Самая очевидная возможность
сделать это - присвоить данному свойству специальное значение none или
убрать это значение. К сожалению, ошибки в Mozilla делают этот путь
ненадежным. Рекомендуемая альтернатива - создать два стилевых
класса:
.binding-installed { -moz-binding : url("test.xml#Test"); }
.binding-removed { -moz-binding : none; }
Вместо того чтобы указывать значение самому свойству -moz-,
присвойте
Второй путь изменить связку граничного тега - использовать специальный интерфейс XPCOM. Этот интерфейс
nsIDOMDocumentXBL
Он всегда доступен для объекта документа. В Таблице 15.3 перечислены методы этого интерфейса.
| Возвращает | |
|---|---|
void |
addBinding(nsIDOMElement element, String URL) |
void |
removeBinding(nsIDOMElement element, String URL) |
nsIDocument |
loadBindingDocument(String URL) |
nsIDomElement |
getBindingParent(nsIDOMNode node) |
nsIDOMNodeList |
getAnonymousNodes(nsIDOMElement element) |
nsIDOMElement |
getAnonymousElementByAttribute(nsIDOMElement element, String attribute, String value) |
Методы addBinding() и removeBinding(), соответственно, добавляют и
убирают из объекта
Метод loadBindingDocument() загружает (синхронизируя процесс)
XBL-документ с указанным URL в дерево
Оставшиеся два метода - XBL-вариации метода document.. Вместо того, чтобы возвращать объекты тега
из дерева
getAnonymousNodes() возвращает объект, содержащий все
непосредственные дочерние теги тега <content> связки. Число
дочерних тегов равно свойству length возвращаемого объекта, и они
доступны методом item() возвращаемого объекта, то есть номеру
индекса.
getAnonymousElementByAttribute() возвращает единичный тег из набора
тегов внутри тега <content> связки.
Возвращаемый тег имеет атрибут name и атрибут value, указанные в
вызове метода.
Последний метод решает проблему, возникающую при слиянии anonid. Указываемый
Вторая проблема, решаемая этим тегом, возникает при использовании
тем. Тема может содержать не только стилевую информацию; скины темы
могут содержать скрипты. Эти скрипты могут модифицировать контент
данного виджета так, чтобы он соответствовал общему облику темы. getAnonymousElementByAttribute() позволяет
Система XPCOM имеет два компонента, имеющих отношение к XBL:
@mozilla.org/xbl;1 @mozilla.org/xbl/binding-manager;1
Ни один из них не имеет интерфейсов, пригодных для использования в прикладных скриптах.
Расширение -moz- стилей -moz- ".
Каждая создаваемая связка должна иметь собственную стилевую
таблицу, так, чтобы виджет мог поддерживать многие темы и скины. Эта
таблица указывается в секции <resources> кода связки.
В данном разделе "Практика" мы разработаем некоторый код общего назначения, использующий XBL. В частности, мы создадим новую XBL-связку и соответствующий ей XUL-тег, которые внесут свой вклад в содержание и поведение диалогового окна утилиты NoteTaker.
Не следует превращать контент XUL в связки XBL только потому, что есть такая возможность. Только код, используемый более одного раза на данной странице или в другом приложении, является подходящим кандидатом для включения в XBL. Связки XBL помещают свой контент в некоторую добавочную структуру. Обычный контент не всегда годится для XBL с точки зрения эффективности кода. Только если связка вызывается часто, она уменьшит, а не увеличит сложность результирующего кода.
В утилите NoteTaker нет повторяющихся частей кода в контенте панели
инструментов или диалогового окна, так что вряд ли стоит использовать
XBL. Но ведь нам нужен пример для иллюстрации этой технологии. Стоит
поэкспериментировать с информацией о позиционировании панели Edit
(параметры top, left, height, width ). Эти четыре параметра очень
похожи на стили позиционирования в стандарте
Мы можем улучшить существующую систему позиционирования с помощью
нового виджета. Создадим связку XBL, которой пользователь сможет
манипулировать графически, чтобы указать будущее положение заметки.
Эта связка будет виджетом специального назначения, в чем-то подобным
тегу <colorpicker>, а в чем-то - окошку Print Preview.
Этот виджет не будет интегрирован в конечный код утилиты NoteTaker, мы просто проиллюстрируем такую возможность.
Нам нужно продумать визуальный, XML, JavaScript интерфейсы, а также интерфейс пользовательского ввода, а потом воплотить эти интерфейсы в XBL-коде. Цель виджета - подсказать пользователю информацию о позиционировании и затем сделать эту информацию доступной основному XUL-документу.
Сначала взглянем на визуальный интерфейс. Визуальная часть -
вдохновитель всей конструкции виджета. Она должна явиться нам как
озарение, поскольку все виджеты по своей природе представляют собой
нечто уникальное. Это вызов нашему творческому мышлению, ведь каждый
виджет должен быть оригинален. Если он не оригинален, мы можем
попросту скопировать и усовершенствовать существующий виджет, например <button>.
Есть, правда, один способ избежать необходимости быть слишком
оригинальным. Виджет XBL может вбирать в себя другие, более простые
виджеты и образовывать из них группу. Такую
Поскольку все XUL-теги и комбинации тегов занимают на экране прямоугольную область, мы знаем, что должны начать с прямоугольника. Можно исхитриться и сконструировать сверхъестественный виджет, который нарушит это правило, но столь далеко в код приходится углубляться не слишком часто. На рисунке 15.2 изображен простой набросок нашегонового виджета.
Идея напоминает другие утилиты визуального конфигурирования, такие
как
(рис 15.2) Модель XBL-связки, позволяющая пользователю позиционировать заметку.На рисунке 15.2 главный
прямоугольник - наш новый виджет. Он имеет три части: задник - <box>, представляющий весь десктоп полностью, опциональный белый <box>, представляющий окно или страницу браузера, и желтый <box>, представляющий заметку, которую нужно позиционировать.
Каждый <box> имеет соответствующую надпись, на тот случай, если
кому-то что-то не очевидно. Главный прямоугольник получит размеры
согласно параметрам разрешения экрана.
Этот главный прямоугольник принимает пользовательский ввод. Если мы
кликнем главной кнопкой мыши внутри прямоугольника, заметка
расположится так, что ее верхний левый угол окажется как раз под
местом
Когда заметка позиционирована, вычисляются ее координаты. Если белого прямоугольника (браузера) нет, координаты относятся ко всему десктопу. Браузер может занимать и весь десктоп. Если белый прямоугольник имеет место, координаты отсчитываются от его угла. Белый прямоугольник нужен по психологическим соображениям: люди обычно предпочитают прямоугольники в "золотой пропорции", т.е. в пропорции 1:1,618. Окошки браузера в конце концов обычно оказываются именно в этой пропорции. Белый прямоугольник напоминает нам, как эта идеальная пропорция выглядит.
Второй интерфейс - пользовательский ввод. Виджет будет поддерживать
разовый
Третий необходимый интерфейс - XML-интерфейс. Для нас это означает
выбор имени тега и множество требуемых атрибутов, которые нам
понадобятся, чтобы обеспечить его вид и поведение. Связку можно
построить на любом теге, но мы выбираем <noteplacer>.
Следующие атрибуты будут иметь специальные значения:
scale screenx screeny pageless
scale - целое, указывающее размер виджета noteplacer по отношению к
размеру десктопа. Например, значение 4 (значение по умолчанию 2)
означает, что noteplacer вчетверо меньше целого десктопа.
screenx означает ширину десктопа в пикселях. Значение по умолчанию
дано свойством window.screen.width.
screeny означает высоту десктопа в пикселях. Значение по умолчанию
дано свойством window.screen.height.
pageless может иметь значение true или false. В случае true белый прямоугольник не появится на
фоне виджета. По умолчанию false.
Теперь вопрос верстки. Будет ли виджет способен изменять размеры?
Какова его ориентация? Список вопросов растет. Поскольку виджет noteplacer изображает форму десктопа, он будет иметь фиксированный
размер и не будет растягиваться. Он должен всегда иметь горизонтальную
ориентацию и не изменять ее.
Последний интерфейс - JavaScript XBL-интерфейс граничного тега. Мы реализуем следующие свойства:
top left width height scale screenx screeny pageless setFromEvent(e,primary)
top, left, width, и height
соответствуют полям в диалоговом окне Edit.
scale, screenx, screeny, и pageless относятся к атрибутам XML граничного тега.
setFromEvent() позиционирует один из углов заметки, используя
объект event. Если второй аргумент true, устанавливается верхний левый
угол, если нет, правый нижний.
Так вот, ни с того ни с сего, не приходится думать о поддержке
каких-либо существующих интерфейсов платформы (например, nsIAccessible ), чего, может, и хотелось бы. Граничный тег будет
автоматически поддерживать стандартные интерфейсы
Все вместе эти четыре интерфейса полностью определяют новый виджет. Последний вопрос, который нужно задать: можем ли мы использовать какую-либо уже существующую XBL-связку? Похоже, что нет, наш новый виджет слишком прост.
Чтобы создать собственно связку, начнем с простого ее скелета. На этом шаге мы определим ее части. Скелет связки приведен в листинге 15.14.
<?xml version="1.0"?>
<bindings id="notetaker"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="noteplacer">
<resources> </resources>
<content> </content>
<implementation>
<constructor></constructor>
<destructor></destructor>
</implementation>
<handlers></handlers>
</binding>
</bindings>
Набор связок, необходимых для утилиты NoteTaker, мы назвали
"notetaker", а связку тега <noteplacer> -
"noteplacer". Поскольку здесь нет цепочки наследования, нет
и атрибута extends в теге <. Поскольку новый виджет
основан на простых XUL-боксах, нет нужды и в атрибуте display. Нам
нужно лишь заполнить эти четыре секции связки.
Начнем с секций <content> и <resources>. Используем
контент, служивший основой для рисунка 15.3 и затем рассмотрим, как
можно модифицировать его для XBL-системы. Используемый контент
приведен в листинге 15.15.
<stack minwidth="320" minheight="240">
<description value="Screen"/>
<box class="page" top="0" left="86" minwidth="148"
minheight="240">
<description value="Page"/>
</box>
<box class="note" top="20" left="106" minwidth="40"
minheight="40">
<description value="Note"/>
</box>
</stack>
Этот контент имеет фиксированные параметры размера, указываемые прямо в коде. Большинство виджетов в вопросе размеров должно полагаться на платформу, а не устанавливать их жестко, чтобы верстка контента была аккуратной. Наш виджет, однако, имеет фиксированные размеры, поэтому мы здесь нарушили это правило.
Прежде чем этот код сгодится для секции <content> связки,
нужно еще поработать. Существуют некоторые проблемы:
Часть page виджета всегда присутствует, нам нужно сделать ее
невидимой, если используется полный размер экрана браузера.
Часть page слишком скучна. Мы можем захотеть поместить здесь что-то
более наглядное, например, панель инструментов и меню браузера.
Фиксированные атрибуты размеров бесполезны для большинства тегов.
<noteplacer> и текущих значений разрешения экрана.
Размеры шрифтов также пока неясны. Если виджет представляет собой скалируемый десктоп, размеры шрифтов должны также быть скалируемыми.
Для всех названных проблем есть простые решения. Исчезновение блока page - самое простое. Позволим тегу <box>, содержащему блок page, наследовать атрибут pageless из тега <notepicker>:
<box class="page" xbl:inherits="collapsed=pageless" ...>
Чтобы сделать page не столь скучным, позволим эксплицитному
контенту тега <noteplacer> определять контент тега <box class="page">. Аккуратно пересмотрев правила слияния
<description value="page"/>
нужно изменить на:
<children> <description value="page"/> </children>
Если эксплицитный контент есть, он будет добавлен в соответствующее
место, если нет, по умолчанию имеется тег <description>.
Теперь избавимся от фиксированных размеров, указанных в пикселях.
Они были получены для виджета на десктопе 640х480, с коэффициентом
пропорциональности два. Вместо этого пусть значения вычисляются в
конструкторе связки во время выполнения. Мы не можем просто
наследовать их из атрибутов тега <noteplacer>, поскольку
требуемые значения являются математической комбинацией значений этих
атрибутов, а не просто копией. Вскоре мы увидим, как это делается.
Наконец, размеры шрифтов также пусть вычисляет конструктор. Добавим
стиль всякому <description>, и для тега <label>. Этот стиль скалирует
для нас размеры шрифтов, чтобы они соответствовали размерам виджета. В
некоторых случаях текст получится нечитаемым, но и цель виджета -
лишь дать некоторое наглядное представление.
Для выполнения этих двух пунктов добавим атрибут anonid < и два тега <box>.
Результат показан в листинге 15.16. Обратите внимание на префикс xul:
namespace каждого XUL-тега.
<content>
<xul:stack anonid="desktop">
<xul:description value="Screen"/>
<xul:box xbl:inherits="collapsed=pageless"
class="page" anonid="page">
<xul:children>
<xul:description value="Page"/>
</xul:children>
</xul:box>
<xul:box class="note" anonid="note">
<xul:description value="Note"/>
</xul:box>
</xul:stack>
</content>
Если мы попробуем запустить связку на данном этапе (вообще-то неплохая идея), результат будет выглядеть не слишком хорошо. Он так выглядит, потому что виджет не имеет пока необходимой ему информации. Связка работает, она просто еще не закончена.
Наконец, мы можем создать простую стилевую таблицу, хранящую
значения по умолчанию для
stack {
background-color : background;
font-family : -moz-fixed;
}
box.page {
background-color : white;
border : solid thin;
border-color : black;
}
box.note {
background-color : lightyellow;
border : solid thin;
border-color : yellow;
}
В этом случает цвет фона будет тот же, что и у реального десктопа.
Шрифт -moz-fixed (системный) имеет одно важное свойство: он может
скалироваться до любого размера. 7px это 14px, скалированный с
коэффициентом два. Заметьте, что значение пространства имен по
умолчанию для подключаемых стилевых таблиц XBL - это пространство имен
XUL.
Это означает, что для тегов в стилевых таблицах не нужно указывать
префикс с пространством имен
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul");
xul|stack { ... styles ... };
Стилевая таблица помещается в секцию <resources>
спецификации XBL с помощью относительного URL. Она имеет относительный
URL, потому что связка noteplacer принадлежит только пакету notetaker
и помещается в той же директории, что и он. Это не глобальная связка в
глобальном пакете. В общем случае файл CSS следует использовать во
всех связках пакета notetaker, и этот файл должен называться
notetaker.css. Мы используем другое имя, чтобы подчеркнуть, что этот
файл имеет только лишь стилевую информацию для XBL, и избежать
конфликта со
<resources> <stylesheet src="noteplacer.css"/> </resources>
Создав контент и стилевую таблицу, мы выполнили половину работ по созданию связки. Мы пока что создали только ее визуальный и XML интерфейсы.
Нам остаются секции < и <. Эти
две секции определяют интерфейс JavaScript и интерфейс
пользовательского ввода. Сначала рассмотрим интерфейс JavaScript,
определенный нами в списке требований в предыдущем разделе.
Очень часто можно увидеть, что XML-атрибуты прямо описываются как
свойства JavaScript граничного объекта, и мы можем поступить так же.
Это делается просто, как можно увидеть из примера, взятого из связки button-base:
<property name="type"
onget="return this.getAttribute('type');"
onset="this.setAttribute('type', val);
return val;"
/>
Мы не используем это метод, потому что не хотим сохранять состояние нашего виджета в атрибутах XML. Это решение основано на рассмотрении преимуществ и недостатков сохранения состояния в атрибутах. Вот преимущества:
<content> других связок.Недостатки сохранения состояния в XML-атрибутах следующие:
Если вы создаете набор виджетов общего назначения или часто используемую связку, преимущества могут перевесить недостатки, и можно рассмотреть использование XML атрибутов.
В нашем случае виджет определенно специфичен лишь для единственного
приложения, и не является виджетом общего назначения. У нас нет
очевидного случая применения его с очевидными значениями по умолчанию.
Мы не собираемся добавлять код платформы для его обработки или
использовать сложные стилевые приемы. Единственным случаем отсутствия
атрибута может быть атрибут pageless, где отсутствие значения можно
понять как равенство его false. Для нашего виджета мы предпочтем
надежный интерфейс, никогда не дающий нулевых или пустых значений.
Остальная часть приложения может использовать этот виджет как
настоящий закрытый ящик. Это решение означает, что мы будем
применять JavaScript для сохранения состояния виджета.
В общем и целом, нам нужно теперь создать контент для тегов <field>, <property>, <method>, < и < виджета.
Для тега <field> мы используем золотое
<field name="ratio">(1+Math.sqrt(5))/2</field>
Это математическое выражение - один из способов вычислить золотое
Что касается конструктора, заметим, что наш виджет довольно
большой, и что он не должен увеличиваться и уменьшаться в размерах в
зависимости от изменений окружения. Такой фиксированный размер -
нестандартное решение. Но он удовлетворяет нашей цели, т.е.
аккуратному отображению десктопа. Это означает, что < может вычислять размеры виджета лишь раз, и нам
не нужно беспокоиться о том, чтобы он был растягиваемым впоследствии.
Конструктор также может сохранять информацию о состоянии виджета в
JavaScript. Логика и верстки, и состояний показана в листинге
15.18.
this.getAEBA = function (x,y,z) {
return document.getAnonymousElementByAttribute(x,y,z);
}
this.desktop = getAEBA(this,"anonid","desktop");
this.page = getAEBA(this,"anonid","page");
this.note = getAEBA(this,"anonid","note");
this.d = {}; // protect numbers from string-ification
this.d.top = 40;
this.d.left = 40;
this.d.width = 100;
this.d.height = 100;
this.d.scale = att2var("scale", 2);
this.d.screenx = att2var("screenx", window.screen.width);
this.d.screeny = att2var("screeny", window.screen.height);
this.d.pageless = att2var("pageless", false);
this.d.page_offset = 0;
if ( !d.pageless )
d.page_offset = (d.screenx - d.screeny/ratio)/d.scale/2;
/* layout the content once */
this.setAttribute("style","font-size:"+14/d.scale+"px;");
placeDesktop();
placeNote();
if ( ! d.pageless )
placePage();
Свойство getAEBA - всего лишь сокращение для труднопроизносимого
метода document.getAnonymousElementByAttribute(). Мы запомним важные
d (для data) сохранит
значение состояния data как число, несмотря на тенденцию XBL
преобразовывать простые переменные в строки. Все свойства this.d
спрятаны от пользователя виджета (специалиста по прикладному
программированию, использующего тег <noteplacer> ). После того,
как эти свойства будут вычислены, часть виджета <content>
получит правильные значения атрибутов, включая скалирование текста.
Функции att2var(), placeDesktop(), placeNote() и placePage() являются
методами объекта, объявленного в начале кода конструктора. Они
показаны в листинге 15.19.
this.att2var = function (name, dvalue) {
var val = this.getAttribute(name);
if ( val == "" ) return dvalue;
if ( isNaN(val) ) return dvalue;
return val - 0;
}
this.arg2var = function (arg) {
var err = "Bad argument passed to noteplacer binding";
if (arg == "" ) throw err;
if ( isNaN(arg) ) throw err;
return arg;
}
this.placeNote = function () {
note.setAttribute("top", d.top /d.scale);
note.setAttribute("left", d.page_offset + d.left / d.scale);
note.setAttribute("minwidth", d.width / d.scale);
note.setAttribute("minheight",d.height / d.scale);
}
this.placeDesktop = function () {
desktop.setAttribute("minwidth", d.screenx/d.scale);
desktop.setAttribute("minheight",d.screeny/d.scale);
}
this.placePage = function () {
page.setAttribute("minheight", d.screeny/d.scale);
page.setAttribute("minwidth", d.screeny/d.scale/ratio);
page.setAttribute("top", "0"); page.setAttribute("left",
d.page_offset);
}
Метод att2var() вычисляет значение arg2var() проверяет, является ли
передаваемый аргумент числом. Скоро мы его используем. Остальные
методы определяют положение виджета на основании информации о
состоянии и некоторых вычислений. Все эти методы, а также метод getAEBA(), принадлежат только виджету. Они не проявляются как свойства
<noteplacer>.
Мы не держим XPCOM-компонентов или других больших объектов во время
жизни виджета, так что не от чего и избавляться, когда виджет
закрывается. Как следствие, тег < не будет иметь
содержания.
Благодаря предпринятым нами к настоящему моменту усилиям по
сохранению информации о состоянии виджета, реализация тегов <property> очень проста. Листинг 15.20 демонстрирует эти
теги.
<property name="top" onget="return this.d.top;" onset="this.d.top = arg2var(val); placeNote();" /> <property name="left" onget="return this.d.left;" onset="this.d.left = arg2var(val); placeNote();" /> <property name="width" onget="return this.d.width;" onset="this.d.width = arg2var(val); placeNote();" /> <property name="height" onget="return this.d.height;" onset="this.d.height = arg2var(val); placeNote();" /> <property name="scale" readonly="true" onget="return this.d.scale;" /> <property name="screenx" readonly="true" onget="return this.d.screenx;" /> <property name="screeny" readonly="true" onget="return this.d.screeny;" /> <property name="pageless" readonly="true" onget="return this.d.pageless;" />
Вряд ли эти теги могли бы быть проще. Заметьте, как установщики
передают исключения через arg2var(), если значение, пересылаемое
виджету пользователем, бессмысленно. Если бы наш виджет был более
динамичным, вызов функции placeNote() в каждом атрибуте onget был бы
более сложен и требовал бы большего объема вычислений.
Вернемся к единственному требуемому тегу <method>.
Координаты виджета, используемые и в атрибутах XML, и в свойствах
JavaScript вычисляются относительно панели, на которую помещена
заметка. Однако, когда наступает событие setFromEvent() позволяет
нам позиционировать угол заметки, используя этот объект. Виджет
выполняет требуемое преобразование координат. Метод показан в листинге
15.21.
this.getCoords = function(x,y) {
return {
x: (x - this.boxObject.x - d.page_offset) * d.scale,
y: (y - this.boxObject.y) * d.scale
};
}
<method name="setFromEvent">
<parameter name="evt"/>
<parameter name="cornerFlag"/>
<body>
<![CDATA[
var coords = getCoords(evt.clientX, evt.clientY);
if (cornerFlag) {
d.width += d.left - coords.x;
d.height += d.top - coords.y;
d.top = coords.y;
d.left = coords.x;
}
else {
d.width = coords.x - d.left;
d.height = coords.y - d.top;
}
placeNote();
]]>
</body>
</method>
Функция getCoords() преобразует указанные координаты. После того,
как этот метод получает локальные координаты из getCoords(), он вновь
вычисляет размер и положение верхнего левого угла заметки, основываясь
на полученных значениях координат и существующих значениях размеров
заметки. Затем заметка вновь позиционируется. Этот метод может
использовать некоторые добавочные проверки (например, высота и ширина
не должны быть отрицательны), но для наших целей он выполняет свою
работу.
Последняя часть спецификации связки - секция <. У
нас есть два обработчика, оба для this.d.topclick. Если она имеет
значение true, false, нижнего правого. Инициализируем переменную
значением true в конструкторе. Для вторичной кнопки используем теорему
Пифагора ("квадрат гипотенузы прямоугольного треугольника равен
сумме квадратов катетов"), чтобы вычислить угол, находящийся по
диагонали, ближайший к месту
<handlers>
<handler event="click" button="0">
<![CDATA[
this.setFromEvent(event,d.topclick);
this.d.topclick = !this.d.topclick;
]]>
</handler>
<handler event="click" button="2">
<![CDATA[
var coords = this.getCoords(event.clientX,event.clientY);
var dist1, dist2;
with (Math) {
dist1 = sqrt(pow(coords.x-d.left,2)
+ pow(coords.y-d.top,2));
dist2 = sqrt( pow(coords.x - (d.left + d.width), 2)
+ pow(coords.y - (d.top + d.height), 2) );
}
this.setFromEvent(event, (dist1 < dist2));
]]>
</handler>
</handlers>
Используя секцию setFromEvent() и частный метод getCoords(), так что
их логика очень проста.
С окончанием работы над секцией < заканчивается
работа над связкой в целом, а это почти 150 строк кода. Поскольку
изменений больше не требуется, все что нам остается - это попробовать
ее в работе.
Создав связку noteplacer, теперь мы хотим ее опробовать. Несколько
следующих шагов, по сути, - полезный способ создания тестовой упряжи
для новой связки. Подобная "упряжь" полезна не только для
финального тестирования, но и во время отладки.
Чтобы связать связку с тегом, используем стилевое правило:
noteplacer { -moz-binding : url("noteplacer.xml#noteplacer"); }
Пока поместим эту строку в файл xulextras.css. Этот файл будет
расположен в той же директории, что и весь контент noteplacer. Эта
стилевая таблица добавит к стандартному множеству тегов XUL новый тег <noteplacer>.
При тестировании нового виджета мы хотим увидеть следующие вещи:
Виджет правильно вписывается в окружающий контент.
Виджет правильно реагирует на пользовательский ввод, включая изменения размеров окна.
Атрибуты, указанные виджету, производят желаемый эффект.
Эксплицитный контент, передаваемый виджету, дает желаемый эффект.
С этой целью создадим тестовый XUL-документ, приведенный в листинге 15.23.
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="xulextras.css" type="text/css"?>
<!DOCTYPE window>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul" onload="install()">
<script>
var np; function install() {
np = document.getElementById("test");
np.addEventListener("click", report, false);
}
function report() {
var str = "";
str += "Top: " + np.top + "\n";
str += "Left: " + np.left + "\n";
str += "Width: " + np.width + "\n";
str += "Height: " + np.height + "\n";
str += "ScreenX: " + np.screenx + "\n";
str += "ScreenY: " + np.screeny + "\n";
str += "scale: " + np.scale + "\n";
alert(str);
}
</script>
<description>Before Test </description>
<hbox>
<description value="Left of Test"/>
<noteplacer screenx="1024" screeny="768" scale="4">
<toolbox flex="1">
<toolbar grippyhidden="true">
<description value="File"/>
<description value="Edit"/>
<description value="View"/>
<description value="Go"/>
<spacer flex="1"/>
</toolbar>
<spacer style="background-color:white" flex="1"/>
</toolbox>
</noteplacer>
<description value="Right of Test"/>
</hbox>
<description>After Test </description>
</window>
</handler>
</handlers>
Этот документ упаковывает тег <noteplacer> в соответствующий
контент и добавляет имитацию панели инструментов. Он также содержит
обработчик событий этого тега. Обработчик событий использует
обработчики
Имитация панели инструментов, конечно, очень примитивна. Но она
позволяет понять, что имеется в виду, а это все, что от нее в данный
момент требуется. Возможно, когда-нибудь технология захвата картинки
экрана в компоненте инспектора
(рис 15.3) Тестовый XUL-документ с тегом <noteplacer>.Если обработчик
(рис 15.4) Диагностическое предупреждение с сообщением о состоянии виджета <noteplacer>Немного вычислений и высвеченные значения положения заметки могут быть подтверждены как подходящие.
Мы видим, как тег <noteplacer> может быть интегрирован в
приложение NoteTaker с помощью JavaScript. Из диалогового окна Edit он
может быть загружен в отдельное второе диалоговое окно или встроен
где-либо в уже существующий <tabbox>. Когда диалоговое окно
закрывается, обработчик событий onclose считывает состояние виджета и
копирует значения в соответствующие поля панели Edit.
Сам по себе наш виджет даст пользователю немного подсказок по его
использованию. Как и многие другие теги XUL, <noteplacer>
функционален, но не очевиден. Этот тег должен быть окружен другим
контентом перед предъявлением его пользователю. На рисунке 15.5
приведен один из возможных сценариев.
(рис 15.5) Использование тега <noteplacer> в приложении.На этом раздел "Практика" данной лекции заканчивается.
В связках XBL нет ничего загадочного; и объект window, и объект document доступны всем свойствам, методам, обработчикам событий, и
конструкторам/
Нет ничего загадочного и в работе связок с
Две наиболее часто возникающие проблемы при создании XBL-связки связаны с пространствами имен XML и внутренними свойствами JavaScript. Запомните о пространствах имен следующее:
XBL-свойсво inherit должно иметь префикс с идентификатором
пространства имен наподобие xbl:, потому что пространство имен,
используемое по умолчанию для тега, который содержит это свойство,
всегда либо XUL, либо HTML.
XBL должен иметь отдельное пространство имен, потому что некоторые
имена его тегов совпадают с именами тегов других приложений XML,
такими как XUL,
Если применяется стандартный набор пространств имен, где по
умолчанию используется XBL, каждый XUL или HTML тег в секции <content> должен будет иметь префикс соответствующего
пространства имен. В противном случае никакой контент не будет выведен
на экран.
В свойствах JavaScript XBL-связок допускаются две простые оплошности:
Забывают указывать префикс this для переменных связки.
Забывают, что когда простые переменные с префиксом this
сохраняются, они преобразуются в строку.
Но наиболее сложная проблема с конструированием связок состоит в том, что они загружаются асинхронно. Мы не можем даже предполагать, в какой момент свойства и методы связки станут доступны. У этой проблемы есть несколько простых решений.
Самое простое решение - использовать обработчик событий документа onload для любого требуемого инициализационного кода. Это решение
годится, только если все используемые связки грузятся лишь однажды из
стилевых таблиц и никогда не изменяются.
Другое простое решение - добавить к каждой создаваемой связке такой тег:
<field name="loaded" readonly="true">true</field>
Перед обращением к связке из скрипта проверьте данное свойство;
если оно имеет значение true, значит, связка доступна.
Более систематическое решение состоит в использовании части связки <. Вот такой кусочек кода - простая регистрационная
система:
with (window.document) bindTotal = (bindTotal) ? ++bindTotal : 1;
Если окно приложения XUL состоит всего из нескольких очень сложных связок XBL, процесс их загрузки проследить довольно легко. Общее число загруженных виджетов можно проверять по таймеру. А если деструктор виджета уменьшает это число, оно становится динамически изменяемым показателем доступности виджетов. Для высокоспециализированных виджетов такой промежуточный слой между виджетом и содержащим его документом может стать весьма практичным решением. Та же практика используется для координации фреймов в web-документе.
Последнее, и глобальное, решение проблемы асинхронности -
использовать метод loadBindingDocument().
Наконец, XBL-виджеты имеют некоторые ограничения, связанные с
секретностью. Если два документа, загружаемые с двух разных URL,
должны иметь полный доступ друг к другу, они должны пройти тест
Mozilla, который называется "Same Origin". Этот тест
требует, чтобы оба URL принадлежали одному и тому же серверу.
XBL-связки также должны проходить этот тест, если они установлены там, где
требования секретности могут быть нарушены. Приложение XUL с одного
сервера не может стандартным способом использовать XBL-связку с
другого. Чем возиться со сложной процедурой сертификации и цифровой
подписи кода, обычно проще инсталлировать XBL-связку в
В любом случае, если связка должна каким-то образом использовать
преимущества, предоставляемые XPCOM-компонентами, документ, содержащий
граничный тег связки, должен быть инсталлирован в
Технология XBL делает разработку пользовательских интерфейсов более гибкой и компонентной. Она следует общей философии языков разметки, подобных HTML: она настолько проста, чтобы ее легко было использовать. Но XBL также и мощный инструмент разработки программного обеспечения - он позволяет некоторой части функциональности в коде быть изолированной, четко определенной и использоваться неоднократно.
XBL-часть платформы Mozilla обогащает платформу интерактивными, визуальными виджетами, придавая им очень гибкие и объектно- ориентированные свойства. XBL-связками являются почти каждый тег XUL и многие теги HTML. Действия по умолчанию, определенные этими связками, и делают эти теги столь простыми и гибкими в работе.
В следующей лекции мы увидим объекты, с которыми связки XBL обычно
связаны. Это объекты системы XPCOM. Мы уже видели многие из них, но
есть еще множество для работы с такими технологиями как XUL и
В этой лекции объясняется, как улучшить язык XUL с помощью новых
тегов и новых свойств, используя XBL (XML
XBL - основанный на XML язык, позволяющий конструировать новые
мощные теги для XUL, HTML и XML. Это
Простой XUL позволяет пользователю создавать собственные теги,
наподобие <mytag>, но они не слишком полезны. Их можно оформить
стилями, но они остаются простыми <box> -подобными тегами. С
помощью же XBL, напротив, можно создавать целые виджеты с уникальным
поведением и обликом. Контент XBL-виджетов комбинируется из XUL, HTML
и других XBL-тегов. XBL не столь гибок как Java-
XBL не создает новых тегов, с его помощью создаются лишь новые
связки (-moz-.
После того как это сделано, говорят, что тег и связка - связаны.
Простейшая связка приведена в листинге 15.1. Это фрагмент документа
XBL, реализующий виджет "улыбочку".
<binding id="smiley">
<content>
<xul:image src="face.png"/>
</content>
<handlers>
<handler event="click" action="alert('have a day')"/>
</handlers>
</binding>
Эту связку можно привязать к тегу с именем < с
помощью следующей строки CSS:
smiley { -moz-binding: url("smiley.xml#smiley"); }
Теперь тег < всегда будет отображать улыбку в
документе XUL. Если по нему кликнуть, появится окошко с приветствием.
Это несложный виджет со своей простейшей интерактивностью. Ни в XUL,
ни в HTML тега < нет.
Система XBL встроена в C/C++ код платформы Mozilla, но сами
пользовательские связки пишутся на JavaScript и XML. Эта
интерпретируемая среда позволяет создавать связки так же легко, как
XUL или HTML. Простота применения интенсивно используется в Mozilla.
Множество XBL-связок вносят свой вклад в приложения Mozilla, такие как
классический
На протяжении всей этой книги мы часто ссылались на файлы .xml в
архиве <tabbrowser> и <colorpicker>, которые определены полностью средствами XBL. Даже
простые теги, например, <button>, имеют XBL-связки.
За пределами мира Mozilla технология, подобная XBL - это язык
Связки XBL имеют ясно определенный интерфейс и уникальность, что
делает XBL небольшой компонентной системой. Как XPCOM предназначен для
компонентов
Поскольку связки XBL создаются с помощью XML и JavaScript, их можно свободно перемешивать с HTML или XUL. HTML используется нечасто, потому что группа тегов, применяемых как HTML, фиксирована и стандартна. Гораздо чаще можно увидеть XBL в приложениях XUL.
На картинке в начале этой лекции показано место XBL в платформе
Mozilla. Несмотря на свой статус компонентной системы, XBL - одна из
главных технологий в Mozilla. Во время загрузки документа XUL связки
XBL идентифицируются и встраиваются в содержание конечного документа.
Это немного похоже на работу системы оверлеев. После того как теги,
используемые в связках XBL, загрузятся, они отображают свой контент
так же, как любой другой тег XUL. Система XBL также имеет поддержку
обработки событий, создаваемых пользователем при вводе. Она использует
систему практически такую же, как система обработки тега <key>.
Здесь мы продолжим общее
XBL расширяет XML так же, как C++ расширяет C. Он добавляет объектно-ориентированные возможности системе, у которой средств для работы с объектами не было.
Каждый документ XBL - это просто список связок (<. Конструирование связки
подобно конструированию класса объектов. В Листинге 15.2 показана
простая связка XBL, являющаяся вариантом тега-связки <.
<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" >
<binding id="checkbox" extends="general.xml#basetext">
<resources>
<stylesheet src="chrome://global/skin/checkbox.css"/>
</resources>
<content>
<xul:image class="checkbox-check"
xbl:inherits="checked,disabled"/>
<xul:hbox>
<xul:image class="checkbox-icon" xbl:inherits="src"/>
<xul:label xbl:inherits="xbl:text=label,accesskey,crop"/>
</xul:hbox>
</content>
<implementation implements="nsIDOMXULCheckboxElement">
<method name="check" action="this.checked = true"/>
<property name="checked" onset="if (val)
this.setAttribute('checked','true');"
onget="return this.getAttribute('checked') == 'true';" />
</implementation>
<handlers>
<handler event="click" button="0"
action="if (!this.disabled) this.checked = !
this.checked;"/>
<handler event="keypress" key=" ">
<![CDATA[ this.checked = !this.checked; ]]>
</handler>
</handlers>
</binding>
</bindings>
Листинг 15.2 демонстрирует многие стандартные черты связок. Разделы <resource> и <content> описывают данные в форме стилей,
изображений, тегов и других простых элементов XUL. Эти разделы
содержат контент XML. Разделы < и < описывают свойства, методы и связанные с событиями
хуки. Эти секции существуют в форме
Рекомендуем изучать связки, созданные другими людьми. В разделе "Чтение чужого кода" лекции 16, "Объекты XPCOM", и в Таблице 16.1 приведены некоторые советы, облегчающие изучение связок, созданных командой mozilla.org.
XBL - это приложение XML. Его XML-определение можно найти по адресу http://www.mozilla.org/xbl. Mozilla не грузит этот URL, он используется лишь как идентификатор. Стандартным суффиксом для XBL-файлов является .xml.
Стандартный тип application/xml.
Связки XBL идентифицируются с помощью URL. Специальной http: и :. Так же, как
для #id, идентифицирующий каждую
связку внутри документа XBL. Как и в случае с #id, рассматривается как целый ресурс, а не
фрагмент ресурса. Пример:
chrome://global/content/bindings/button.xml#button.
XBL был принят консорциумом
Реализация XBL в Mozilla отличается от предложенной в
Стандарты, конкурирующие с XBL, это
XBL имеет более широкую область применения, чем любой иной стандарт
Чтобы связки XBL можно было использовать, они должны быть
предварительно встроены в иерархию
Перед тем, как связка будет использована, ее нужно связать с
существующими XML-тегами документа. Эти теги называются граничными
тегами (<content>, то теги внутри него
называются
Когда мы вызываем XBL-связку, иерархия
Шаги 1 и 2 повторяются для каждого граничного тега. Процесс порождения контента очень похож на такой же процесс для оверлеев и шаблонов. Так же как в оверлеях, контент добавляется в целевой документ в определенной точке. Так же как в шаблонах, добавочный контент порождается повторным копированием определенного набора тегов. Платформа Mozilla автоматически выполняет эти шаги.
Исходное XBL-определение связки недоступно в целевом документе.
Если необходимо, его можно загрузить и исследовать как любой иной
Эти принципы подробно рассматриваются в разделе "Как обрабатываются связки".
Систему XBL можно использовать для реализации действий, выполнения которых требуют HTML и XUL-теги.
Такое действие по умолчанию можно видеть на примере тега HTML <input type="submit">. Когда мы
Ответ состоит в том, что действие по умолчанию можно встроить в
XBL-связку. Связка дает способ связать вместе событие
Данный виджет может иметь различное действие по умолчанию для
каждого порождаемого пользователем события. В случае тега <input
type="submit"> нажатие клавиш Return или Enter или
Разработчик приложения может изменить действие по умолчанию,
используя обычный обработчик событий. К этой задачке, однако, нужно
подходить аккуратно. Если обработчик события установлен в форме
значения атрибута (как, например, onclick ), то будет использован
именно он, а не обработчик XBL. Если обработчик события установлен с
помощью функции addEventListener(), то этот обработчик должен быть
установлен до того, как обработчик XBL будет включен в тег. Это
требование ставит обработчики приложения перед обработчиками XBL в
списке обработчиков события. См. замечания в разделе
"Скриптинг".
Система XBL не ответственна за обнаружение события и процесс "всплытия" события. Она не отвечает также за состояние фокуса и состояние фокусного кольца. Это вещи, обрабатываемые глубоко внутри C/С++-части кода платформы. Поддержка специальных функций (для людей с ограниченными возможностями) выполнена на XBL, но система ввода, которая осуществляет первую реакцию на команды этого типа, есть часть ядра системы.
Связки XBL имеют объектно-ориентированные свойства и могут
рассматриваться как объекты с точки зрения JavaScript или
XBL поддерживает традиционные концепции объектно-ориентированного подхода. В таблице 15.1 приведено описание поддержки ОО в XBL.
| Концепция | Поддержка в XBL |
|---|---|
| Теги XBL собирают контент (включая контент граничного тега) и код JavaScript в единую связку, сливая эксплицитный и |
|
| Локализация | Граничный тег хранит логику всего контента и JavaScript. XBL-связка может содержать другой граничный тег, и, следовательно, следующую связку |
| Граничный тег содержит всю полезную информацию о связке, хотя некоторая полезная информация может быть получена из JavaScript-объекта document | |
| Наследование | XBL имеет атрибут inherits, для наследования XBL-атрибутов, и атрибут extends, для наследования целых связок |
| Скрытие информации | Код подключенной связки скрыт и недоступен из граничного тега. Доступен только соответствующий интерфейс |
| Интерфейсы | Связка, предоставляющая интерфейс, может быть наследована другой связкой с помощью атрибута extends. Связка может поддерживать интерфейсы XPCOM с помощью атрибута |
| Позднее связывание | Связки подгружаются в граничный документ независимо и асинхронно. Связка может быть подгружена и выгружена в любое время с помощью правил |
| Объектность | Граничная связка с точки зрения JavaScript является объектом |
| Объектно-ориентированность | Атрибут extends позволяет XBL-связке быть основанной на ряде (цепочке наследования) других связок. См. Последующее обсуждение |
| Не поддерживается | |
| Определение типов | Не поддерживается. Можно использовать лишь интерфейс nsIClassInfo |
XBL-связка может наследовать другую связку. Та, в свою очередь,
может наследовать следующую. Множество унаследованных связок образует
упорядоченный список, называемый цепочкой наследования. Когда данный
граничный тег встраивается в документ, он является началом (головным
элементом) цепочки наследования. Он также называется первичной
связкой. Таким образом цепочка наследования всегда имеет длину не
меньше единицы. Если
На рисунке 15.1 приведен пример цепочки наследования, которую имеет
тег <button>.
(рис 15.1) Иерархия наследования для XUL-тега <button>.В примере показаны цепочки наследования трех элементов. Связка "button" привязана к тегу <button>. Эта связка -
начало цепочки наследования. Две другие связки - это связки общего
назначения, наследуемые во множестве мест в XUL. Связка button-base
используется во всех (или почти всех) кнопкоподобных виджетах, а
связка basetext используется во всех виджетах, имеющих дело с текстом.
Связки button и button-base определены в одном и том же XBL-документе,
(button.xml), а basetext в другом, general.xml. Все три связки
добавляют некоторое содержание в <button>.
Две связки могут наследовать одну базовую связку, так что полный граф цепочек наследования может выглядеть как дерево (или "роща" деревьев). Эта древоподобная структура может быть полезной в процессе проектирования, но ее нельзя исследовать или передвигаться по ней из скриптов.
В Таблице 15.2 описано, как наследуются различные свойства связок XBL.
| Свойство XBL | Наследуется? |
|---|---|
<resources> |
Все связки цепочки наследования загружают свои ресурсы. Все стилевые таблицы имеют по умолчанию одинаковый вес, но правила у начала цепочки подгружаются позже, и, следовательно, отменяют ранее загруженные правила |
<content> |
Нет наследования. Используется единственная связка из начала цепочки наследования. Если граничные теги содержатся в теге <content>, а не наследуются, используются их связки |
<field>, <property>, <method> |
Свойства и методы наследуются. Если имя составной связки совпадает с именем элементарной, составная замещает основную, и последняя становится недоступна из скриптов составной |
< и < |
Оба свойства наследуются. Конструкторы запускаются по одному, начиная с первой основной связки и заканчивая последней составной. |
< |
Обработчики событий наследуются. Обработчики событий составной связки отменяют действие обработчика базовой связки, если речь идет об одном и том же событии |
Атрибут display |
Нет наследования. Используется атрибут последней составной связки |
Система XBL - это очень простой набор компонентов. Он позволяет стандартизированным компонентам взаимодействовать удобным образом.
Компонентная система, подобная XBL - система модулей Perl,
доступных с помощью ключевых слов use и require. Обе системы
достаточно примитивны. К связкам XBL можно получить доступ через
Имена компонентов в системе XBL - это URLs в форме Resource#Id, где Resource - это web-адрес документа, а id - значение атрибута id тега <. Так же как id как ресурс, а
не как сдвиг (offset) в существующем ресурсе.
XBL не имеет регистра компонентов или их службы имен, и не имеет возможности доступа к внутреннему устройству связок. Вместо этого документ XUL или HTML имеет простой внутренний список активных связок, используемых данным документом.
Компонентная система XBL является распределенной системой, поскольку связка может быть получена по URL откуда угодно. Связки не имеют доступа к серверу, с которого были загружены, если только не содержат кода именно для этой цели.
Система XBL не имеет свойств, подобных сложным компонентным
системам, таким как COM от Microsoft, XPCOM самой платформы Mozilla,
Связка XBL может реализовывать один или несколько интерфейсов
XPCOM. Это позволяет объекту
Связки не могут вести себя как компоненты XPCOM до тех пор, пока они не привязаны.
Этот раздел описывает конкретные теги и атрибуты XBL.
Некоторые теги XBL имеют имена, совпадающие с именами, используемыми в Mozilla где-нибудь еще. При проектировании связки всегда неплохо указать полную ссылку на соответствующее пространство имен, чтобы избежать двусмысленности. Вот имена тегов XBL, используемые в другом значении:
<bindings> <body> <children> <content> <image>
Имена атрибутов, используемых в ином значении:
method action command modifiers charcode keycode key name readonly text
Большинство тегов XUL и HTML могут быть граничными в XBL. Чтобы тег мог быть граничным, он должен иметь фрейм - прямоугольную оформляемую стилями зону, в которой он высвечивается.
Тег со следующим атрибутом не имеет фрейма и не может быть граничным.
{ display: none; }
Тег, получающий этот атрибут, потеряет те связки, которые имел.
Поэтому граничный тег XUL должен иметь атрибут , а не ,
если нужно его спрятать.
Связываются в связки конкретные теги, а не имена тегов. Каждое
стилевое правило, содержащее -moz-, связывает набор конкретных
тегов. В листинге 15.3 приведен ряд примеров.
box { -moz-binding: url("binding.xml#sample"); }
#id { -moz-binding: url("binding.xml#sample"); }
.class { -moz-binding: url("binding.xml#sample"); }
box[X="here"] { -moz-binding: url("binding.xml#sample"); }
box,vbox,hbox { -moz-binding: url("binding.xml#sample"); }
box vbox { -moz-binding: url("binding.xml#sample"); }
Первая строка кода присоединит каждый конкретный тег <box> к
одной и той же связке. Каждый конкретный тег имеет собственный
интерфейс и свое class. Четверная строка – подмножество тегов <box>, имеющих атрибут X="here". Пятая строка – теги <box>, <, <hbox> и т.д. Если два правила
присоединяют один и тот же конкретный тег (а это очень неудачный
вариант), используется более конкретное правило, либо более позднее
правило, если селекторы одинаковы. То есть обычные правила выполнения
инструкций
Такая обработка стилевых правил используется в XUL для тегов,
имеющих различные варианты, наподобие тега <button>. Каждый
вариант использует различные связки. Их можно посмотреть в файле
xul.css архива
Можно явно указать отсутствие связок:
{ -moz-binding : none; }
Mozilla (по крайней мере, до версии 1.4) требует специальных приемов для добавления и уничтожения связок; следуйте советам, данным в разделе "Скриптинг", а не применяйте стилевые правила "в лоб".
Наконец, заметим, что есть одна давно известная ошибка (по крайней мере до версии 1.4). Тег со следующим стилем не будет работать корректно:
{ display: block; }
Потому что block не является частью XUL, это -moz-.
Тег < является верхним тегом в документе XBL. У него
нет специального значения и специальных атрибутов. Он может содержать
только теги <.
Декларация <!DOCTYPE> не обязательна для документов XBL. Если
такая декларация есть, необходимым минимумом является следующее:
<!DOCTYPE bindings>
Тег < содержит описание одной XBL-связки. Он может
иметь до четырех вложенных тегов. Каждый из следующих тегов может
появиться максимум один раз:
<resources> <content> <implementation> <handlers>
Все четыре тега опциональны. Рекомендуется, чтобы они были описаны
именно в данном порядке, но это не обязательно. Тег <
без контента бесполезен, за исключением того случая, когда он убирает
весь контент и все действия по умолчанию из граничного тега. Эффект
подобен действию стиля "-moz-.
Тег < имеет следующие специальные атрибуты:
id display extends inheritstyle
Атрибут id идентифицирует связку. Связка не имеет имени, а только
идентифицирующий ее URL. Если часть #id в этом URL отсутствует, будет
использован атрибут id первой связки в документе XBL.
Атрибут extends - это механизм наследования в XBL. Его можно
установить в URL следующей связки. Последовательность связок,
определяемых атрибутом extends, формирует цепочку наследования; это
обсуждалось в разделе "Объектные свойства связок".
Атрибут extends может иметь сокращенное значение. Его можно
использовать также для атрибута display. Оно состоит из префикса xul:
и имени тега XUL. Оно утверждает, что связка основывается на
существующем теге и должна использовать его свойства. В случае
атрибута extends, этот тег дает базовую реализацию связки. Пример:
extends="xul:box"
Атрибут display может иметь только сокращенное значение,
используемое для атрибута extends. Оно указывает, какой объект box
применяется в данной связке. Указанный объект box - один из тех,
которые обычно используются указанным тегом XUL. Пример:
display="xul:button"
Эта запись означает, что связка приобретет объект box, который
имеет XUL тег <button>.
Атрибут inheritstyle может иметь значение false. Его значение по
умолчанию true. Если его установить в false, граничный тег не
приобретет тех стилей, с помощью которых оформлялся до того, как к
нему была присоединена связка.
В теге <resources> указывается, какие еще документы требуются
данной связке. Он подобен HTML тегу <LINK>. Тег <resources> не имеет специальных атрибутов и может содержать
только следующие теги:
<image> <stylesheet>
Можно указать ноль или более этих тегов. Последовательность не
имеет значения, за исключением того, что более поздние теги <stylesheet> будут применены после более ранних. Система XBL
обходится не слишком интеллектуально с содержанием тега <resources>, как описывается далее.
Тег <image> идентичен одноименному XUL-тегу, кроме того, что
здесь единственным используемым атрибутом является src. Так же, как в
XUL, src определяет URL изображения. <image src="
XBL ничего не делает с этим тегом, лишь предписывает платформе
Mozilla получить это изображение и кэширует его. Это подсказка
платформе, что данное изображение важно и может понадобиться позже.
Оно может понадобиться в XUL теге <image>, HTML теге <img>, liststyle-image, или в контентной части
XBL-определения. Указание этого тега - лишь оптимизация
выполнения.
Тег <stylesheet> идентичен HTML тегу <style src=>. Он
не может иметь иного собственного контента.
<stylesheet src="chrome://global/skin/button.css"/>
Стилевые таблицы используются в XBL, чтобы хранить все детали
визуализации виджета. Это позволяет виджетам быть зависящими от темы.
Это также дает возможность сконструировать стилевые правила так, чтобы
они применялись лишь к <button>
(основанного на XBL связке с id="button" ) сохранялись по
зависящему от темы URL.
Можно использовать более одного тега <stylesheet> на связку,
но это делается редко. Если такое случается, стили прикладываются в
порядке их появления.
Если связка имеет цепочку наследования других связок, и они также
имеют теги <stylesheet>, все стилевые таблицы будут
использованы. Они прикладываются в порядке от конца цепочки к ее
началу, так что первичная стилевая таблица имеет преимущество.
Все стандартные связки тегов, хранимые в
Тег <content> содержит весь <children>,
специфичный для XBL. <script>, не работают в анонимном контенте.
Тег <content> имеет два специальных атрибута:
includes excludes
Оба атрибута считаются устаревшими, их следует избегать.
Используйте вместо них в анонимном контенте тег <children>. Если
в теге <content> появляются любые другие атрибуты, они будут
скопированы в граничный тег.
Атрибуты граничного тега могут быть добавлены тегам внутри тега <content> с помощью атрибута inherits. Эксплицитный контент
граничного тега может быть слит с тегами внутри тега <content> с
помощью тега <children>.
Если связка использует атрибут extends, так что строится на основе
другой связки, тег <content> в этой другой связке
игнорируется.
Если тег <content> связки пуст, граничный тег также не будет
иметь контента.
<content> может быть фрагментом
документа любого типа и любого размера. Тег <children> может
появиться в любом месте этого фрагмента.
Отличные от XBL теги в контенте могут использовать один атрибут
XBL, а именно inherits. Этот атрибут служит для того, чтобы передать
параметры и их значения из граничного тега
Этот механизм дает пользователю возможность управлять inherits в
Атрибут inherits содержит разделенный запятыми или пробелами список
соответствий атрибутов. В списке соответствий указывается, какой
атрибут
att1 att1=att2 xbl:text=att2 att1=xbl:text
att1 и att2 - любые правильные имена атрибутов XML.
Первая запись утверждает, что атрибут граничного тега att1 и его
значение должны быть просто скопированы в
Вторая форма записи говорит о том, что атрибут att1 att2 граничного тега.
Третья форма использует специальное зарезервированное имя xbl:text.
Она говорит, что <текстовое> содержание att2 граничного тега. Это
дает тот же эффект, что и использование тега <textnode> в
шаблонах XUL.
Четвертая форма говорит, что атрибут att1
Поскольку атрибут inherits является атрибутом XBL, он не может
появиться в не-XBL теге. Он должен быть полностью определен, включая
его пространство имен XML. Это достигается благодаря префиксу xbl:
(или подобному) и добавлению полной декларации пространства имен в
начале документа XML. В силу этих причин XBL документы часто имеют две
ссылки на пространство имен XBL:
<bindings id="test" xmlns="http://www.mozilla.org/xbl" xmlns:xbl="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" >
Первое пространство имен XBL обычное по умолчанию, второе
указывается специально для атрибута inherits.
Если все это соединить, получится следующий пример атрибута inherits:
<xul:label dir="ltr" xbl:inherits="xbl:text=value,style,align=justify"/>
Если граничный тег был таким:
<mytag value="Test" style="color:red" justify="start"/>
то после замены <xul:label> будет заменен на:
<xul:label dir="ltr" style="color:red" align="start"> Test </xul:label>
Атрибут inherits может быть использован в любом месте dir=". Если специальный атрибут xbl:text использован более
одного раза, все определенные значения появятся в текстовой ноде
Тег <children> управляет слиянием эксплицитного контента
граничного тега (если он есть) с <content>. Тег <children> может появиться в любом
месте
includes
Атрибут includes может содержать разделенный запятыми список имен
тегов. Определения пространства имен не требуется. Этот атрибут
изменяет процесс слияния контентов. Вот обзор возможностей:
<children> в
анонимном контенте игнорируются. Это все равно что удалить все теги <children> из секции <content>, но оставить остальные теги
нетронутыми. Финальный контент является копией оставшегося <children>. Если это условие выполняется, финальным
контентом будет объединенная копия эксплицитного и <children> в анонимном контенте использовались некорректно, либо
в граничном теге есть некоторый неучтенный эксплицитный контент. В
этом случае результат объединения непредсказуем.Последние два случая требуют дальнейшего уточнения. Процесс слияния
контента целиком определяется тегом <children>. Этот тег создает
иллюзию, будто эксплицитный контент добавляется к
Если у тега <children> нет атрибута includes, эксплицитным
контентом будет замещен и сам тег <children>, и <children>.
Если атрибут includes есть, тег <children> будет замещен лишь
частью эксплицитного контента. Будут размещены все непосредственные
дочерние теги граничного тега, чьи имена совпадают со списком в
атрибуте includes. Они будут помещены в той точке <children>. Они будут размещены в том же
порядке, в каком были в граничном теге.
3. Если пункт 2 повторяется аккуратно, то окажется достаточно тегов <children includes=>, чтобы разместить весь эксплицитный
контент. В этом случае весь эксплицитный и
4. Если пункт 2 не повторяется достаточное количество раз,
некоторые непосредственные дочерние теги граничного тега не найдут для
себя соответствующего тега <children includes=>. Это неполный
охват эксплицитных тегов. Mozilla сама добавит весь эксплицитный
контент в финальный контент, а весь
Если пункт 2 реализован небрежно, некоторые дочерние теги
граничного тега могут соответствовать более чем одному тегу <children>. Это непорядок, в таком случае результат может быть
непредсказуем. В итоге разработчик связки должен либо (a) не делать
никаких предположений об эксплицитном контенте граничного тега и
избегать использовать includes, либо (b) полностью предвидеть, что
граничный тег будет размещать в анонимном контенте и использовать includes везде; или (c) делать обоснованные догадки и положиться на
то, что система XBL придумает здесь что-то более или менее
рациональное.
Листинг 15.4 демонстрирует корректный пример этой системы в действии.
<!-- tag to be bound -->
<mytag>
<image src="face.png"/>
<description label="Smile"/>
<image src="face.png"/>
</mytag>
<!-- Example 1: unknown explicit content -->
<content>
<box>
<children/>
</box>
</content>
<!-- Example 2: known explicit content -->
<content>
<children includes="description"/>
<box>
<children includes="image"/>
</box>
</content>
<!-- Example 3: known but optional explicit content -->
<content>
<children includes="image|description">
<label value="No emoticon supplied"/>
</children>
</content>
В данном листинге тег <mytag> - граничный. Остальные
фрагменты принадлежат трем разным связкам. Пример 1 добавляет весь,
неважно какой, эксплицитный контент. Пример 2 корректно добавит каждый
тип эксплицитного контента в соответствующем месте. Пример 3 также
добавит эксплицитный контент, но если его нет, вместо него будет
использоваться тег <label>. В листинге 15.5. приведен финальный
контент для всех этих случаев.
<!-- Example 1: unknown explicit content -->
<mytag>
<box>
<image src="face.png"/>
<description label="Smile"/>
<image src="face.png"/>
</box>
</mytag>
<!-- Example 2: known explicit content -->
<mytag>
<description label="Smile"/>
<box>
<image src="face.png"/>
<image src="face.png"/>
</box>
</mytag>
<!-- Example 3: known but optional explicit content -->
<mytag>
<image src="face.png"/>
<description label="Smile"/>
<image src="face.png"/>
</mytag>
Если исходный контент тега <mytag> сильно изменить, пример 1
останется работающим, в то время как 2 и 3 могут дать неожиданные
результаты.
В примере листинга 15.6 приведена конструкция, которая никогда не
будет работать надежно, потому что теги <image> эксплицитного
контента не соответствуют ни одному из двух тегов контента
<content>
<children/>
<box>
<children includes="image"/>
</box>
</content>
<content> сам, в свою очередь,
может включать граничные теги для некоторой XBL связки. Это вполне
допустимо, поскольку большинство XUL-тегов - граничные теги.
XBL автоматически поддерживает граничные теги как
Можно сконструировать циклы вложения, но этого следует избегать.
Тег <content> не должен содержать свой собственный граничный
тег.
Тег < - это простой тег-контейнер. Он
реализует объектоподобный интерфейс связки. Этот интерфейс реализуется
на JavaScript. Впоследствии он будет доступен скриптам JavaScript,
работающим вне граничного тега. Созданный интерфейс доступен, как
свойства и методы граничного тега.
Тег < имеет один специальный атрибут:
implements
Этому атрибуту можно присвоить список (разделенный пробелами или
запятыми) имен интерфейсов XPCOM, таких как nsISimpleEnumerator или nsIDOMEventListener. Может быть использовано любое имя интерфейса.
Платформа Mozilla посчитает связку как соединенный через XPConnect
компонент XPCOM и использует эти имена, чтобы определить, что связка
должна делать. Тогда уж заботой разработчика связки будет, чтобы она
выполняла то, что обещает. Система XBL автоматически добавляет
функциональность, эквивалентную интерфейсу nsISupports.
Если любой из этих интерфейсов реализован и объявлен, они появляются как интерфейсы граничного тега.
Атрибут type не поддерживается тегом < или его
подтегами. Подразумевается, что используется язык JavaScript.
Рекомендуется задействовать синтаксис XML <![, если
ваши скрипты имеют заметный размер.
Тег < может содержать в качестве дочерних
любые из следующих тегов, в любом порядке:
<field> <property> <method>
Тег < также может содержать один из следующих
тегов:
<constructor> <destructor>
Все эти пять тегов содержат скрипты на языке JavaScript. Эти скрипты имеют доступ к некоторым хорошо известным свойствам JavaScript:
this window document event
Свойства window и document - те же самые, что используются в XUL и
HTML и относятся к свойствам window и document граничного тега.
Свойство this относится к объекту getAttribute(). Свойство event существует только для тега < и содержит объект
Имейте в виду, что в секции < свойство this
имеет особенность. Все простые значения, присваиваемые свойствам
объекта this, автоматически конвертируются в тип "строка".
Согласно этому правилу, следующий код вернет строку
"1213":
this.dozen = 12; alert(dozen + 13);
Это преобразование заметно только при использовании оператора "+". В других математических операторах строки будут автоматически конвертированы в числа, и мы не заметим преобразования в строку. Простая подсказка - храните значения в объектах. Следующая строка кода вернет 25:
this.d = {}; d.dozen = 12; alert(d.dozen + 13);
Связка без тега < также полезна. Она может
отображать контент и обрабатывать события.
В листинге 15.7 дан пример некоторого XBL-объекта. Он реализует экспериментальную осветительную лампу. Каждый раз, когда лампа включается, ее возраст слегка увеличивается, а мощность слегка падает. Наверное, пытаться включать и выключать ее не слишком эффективно.
<implementation>
<field name="rating" readonly="true">60</field>
<field name="lit">true</field>
<field name="age">0</field>
<property name="power"
onget="age++; return rating-age/1000;"
onset="age=(rating-val)*1000;" >
<method name="toggle">
<body>
if ( this.power > 30 ) this.lit = !this.lit;
</body>
</method>
</implementation>
Этот объект имеет четыре свойства: (значение мощности,
здесь, видимо, в ваттах), lit (булева константа) age (целое) и power
(динамически вычисляемое значение). Он имеет один метод: .
Имена свойств появляются и в значениях атрибутов XBL-тегов, и в коде
JavaScript. Например, метод использует свойства power и lit,
чьи имена также появляются как значения атрибута name тега <field>.
Интерфейс в листинге 15.7 эквивалентен объекту JavaScript в листинге 15.8.
var bulb = {
const rating : 60,
lit : true,
age : 0,
get power() { age++; return rating-age/1000; },
set power(val) { age=(rating-val)*1000; },
toggle : function () {
if ( this.power > 30 ) this.lit = !this.lit;
}
};
Очевидно, оба листинга очень похожи. Почему же не использовать простой объект JavaScript и не отказаться от XBL? Такой объект придется вручную указывать для каждого тега, где это будет нужно, используя скрипты. При использовании XBL объект появится автоматически везде, где ему будет предписано появиться правилами CSS связки XBL.
Тег <field> - самая простая часть интерфейса связки. Он
предназначен для сохранения значения простой переменной. Используется
для хранения информации о состоянии, указываемой программистом, для
каждого граничного тега. Тег <property> - более гибкая версия
тега <field>.
<field> имеет два специальных атрибута:
name readonly
Атрибут name хранит имя свойства JavaScript. Это должно быть
правильное значение имени переменной JavaScript.
Атрибут readonly может иметь значение true, в этом случае значение field нельзя изменить скриптом.
<field> имеет следующий синтаксис:
<field>JavaScript expression</field>
Обратите внимание, что содержание тега есть выражение, а не утверждение (statement). Поскольку выражение вычисляется лишь один раз, обычно это простое выражение, но оно может быть, если потребуется, и сложным. Примеры:
<field name="count">3+2</field> <field name="address" readonly="true">"12 High St"</field> <field name="phonelist">[]</field>
Примеры выглядят странно, поскольку нет явного присваивания. Вместо этого система XBL определяет значения выражений и использует результат. Эти теги подобны следующим утверждениям JavaScript:
Однажды созданные теги fields являются свойствами объекта
граничного тега, (т.е. то же самое, что this ), и их далее можно
использовать обычным образом.
Тег <property> предназначен для сохранения простой
переменной, как и тег <field>. Эта переменная доступна как
свойство JavaScript объекта граничного тега.
Разница между <property> и <field> состоит в том, что
переменная тега <property> ведет себя как интерфейс, в то время
как переменная тега <field> - как простое значение.
Значение переменной <property> может динамически вычисляться,
когда она читается или записывается, и обе операции могут иметь
вторичные эффекты. Это значит, что скрипт, использующий property,
может вызывать иные процессы, получая или устанавливая ее
значение.
Вспомним лекцию 5, "Сценарии". Свойство property
JavaScript может быть определено с функциями __defineGetter__ и __defineSetter__.
Тег <property> работает точно таким же образом, за
исключением того, что свойство property прописывается здесь тегами < и < или сокращенно, атрибутами onget и onset.
Тег <property> имеет четыре специальных атрибута:
name readonly onget onset
name - имя свойства JavaScript, которое это свойство определяет.
Оно должно быть правильным именем JavaScript.
readonly означает, что property ведет себя как неизменяемая
переменная JavaScript. Переменная может быть прочитана, но не
изменена.
onget - сокращенная запись тега <, она содержит в
качестве значения скрипт. Если присутствуют и onget, и <,
используется onget.
onset - сокращенная запись тега <, она содержит в
качестве значения скрипт. Если присутствуют и onset, и <, используется onset. onset бесполезен, если указано readonly="true".
Тег <property> может иметь ноль или более тегов < и <. Контент этих тегов - функции
JavaScript.
Тег < и атрибут onget должны содержать
последовательность сообщений JavaScript. Возвращается результат этой
последовательности.
Тег < и атрибут onset также должны содержать
последовательность сообщений JavaScript, но возвращается значение
переменной . Специальная переменная содержит устанавливаемое
значение.
В листинге 15.7 приведен простой пример onget и onset.
Эквивалентный синтаксис с тегами < и <
приведен в листинге 15.9. Секцию в данном примере можно не
использовать, поскольку код тривиален. Повсюду, для ясности,
применяется ключевое слово this - это рекомендуемая практика.
<property name="power">
<getter>
<![CDATA[ this.age++; return this.rating - this.age/1000; ]]>
</getter>
<setter>
<![CDATA[ this.age = (this.rating - val) * 1000; return val; ]]>
</setter>
</property>
Если < и onset не определены, и делается попытка
присвоить значение с помощью этого свойства, на консоли JavaScript
появится сообщение об ошибке (или генерируется исключение). Если
предпринимается попытка получить значение данного свойства, когда ни <, ни onget не определены, будет возвращено значение .
Тег <method> используется для определения метода интерфейса.
Он содержит ноль или более тегов <, за которыми
следует в точности один тег <body>. Тег <method> имеет
один специальный атрибут:
name
Атрибут name указывает имя свойства JavaScript, содержащего объект Function, так что оно должно быть правильным идентификатором
JavaScript. Тег <method> не поддерживает атрибут action, и
Mozilla может упасть, если его использовать.
Если должны применяться цепочки наследования, не получится
использовать тег <method>, если он был перезаписан
унаследованным тегом <method> с тем же именем. Нельзя работать с
методом, который был перезаписан.
Тег < имеет тот же синтаксис, что и тег <method>. Его единственный атрибут name определяет одно имя
переменной, передаваемой методу. Порядок тегов < тот
же самый, что и порядок передаваемых переменных.
Теги <method> и < не используются для
создания полностью типизированных функций-сигнатур. Они используются
просто как имена. Нет проверки типов или даже подсчета аргументов. Нет
преобразования типов, за исключением того, который предоставляет сам
язык JavaScript. Нет возможности указать тип возвращаемого значения.
Это очень упрощенные теги.
Невозможно создать два метода с одним именем, но разным числом параметров. Но поскольку все функции JavaScript поддерживают списки аргументов, нет нужды такие вариации создавать.
Наконец, тег <body> содержит те сообщения JavaScript, которые
образуют метод. Этот тег не имеет специальных атрибутов. Если метод
должен что-то возвращать, следует использовать сообщение return.
Объект arguments, определенный для всех функций JavaScript, также
можно использовать в содержании тега <body>.
Листинг 15.10 демонстрирует, как эти теги работают вместе:
<method name="play">
<parameter name="boy"/>
<parameter name="dog"/>
<parameter name="ball"/>
<body>
<![CDATA[
if ( arguments.length != 3)
throw Components.results.NS_ERROR_INVALID_ARG;
if ( boy == "Tom" dog == "Spot" ) {
return document.fetch(ball.type);
}
return null;
]]>
</body>
</method>
Этот пример показывает, что проверка передаваемых аргументов должна
быть выполнена вручную. Можно использовать сообщение throw
чтобы остановить выполнение метода и вернуть исключение в
вызывающий код. В этом примере возвращаемое значение - одно из
официальных значений ошибок XPCOM. Если используется одна из этих
констант, метод будет соответствовать стандартам компонентов XPCOM.
- это метод или функция,
определенная где-то вне XBL-связки.
function play(boy, dog, ball) {
if ( arguments.length != 3)
throw Components.results.NS_ERROR_INVALID_ARG;
if ( boy == "Tom" dog == "Spot" ) {
return document.fetch(ball.type);
}
return null;
}
Эти два листинга даже трудно различить, так что неудивительно, что
содержание тега <method> конвертируется в JavaScript, как только
документ XBL загружается и парсится.
Теги < и < - это обработчики
событий, которые запускаются лишь однажды за время жизни связки. Они
используются для инициализации и очистки, как и все конструкторы и
Они имеют один специальный атрибут:
action
Атрибут action - сокращение для содержания тегов < и <. Это содержание - тело
функции JavaScript, так же как в XBL теге <body>. Его можно
поместить между открывающим и action. Если используются оба способа, применяется атрибут action, хотя так делать вряд ли имеет смысл.
Тег < выполняет свою работу, когда связка
объединяется с граничным тегом. Это может быть очень большое число
раз, и если так, то нужно проследить, чтобы действие конструктора
имело оптимальный код. Невозможно управлять связкой в цепочке
наследования, используя этот тег. Нет также возможности управлять
каким-либо граничным тегом в секции <content> из тега <. Коду конструктора аргументы не передаются, но
указатель this всегда доступен. Код конструктора не обязан возвращать
какое-либо значение.
Если текущая связка наследует иную связку, то теги < запускаются в порядке от конца к началу в цепочке
наследования, другими словами, тег < первичной
связки будет в последним.
Тег < выполняет свое действие, когда связка
отсоединяется от граничного тега. Редко когда это случается без того,
чтобы весь целевой документ не был закрыт, но если связка управляется
вручную, или поддерживается состояние, разделяемое многими окнами, тег < может быть полезен. Так же, как и для тега <, здесь нет возможности воздействовать на связки,
являющиеся частями текущей связки. Коду
Если текущая связка расширяет (наследуется из) другой связки, то
теги < запускаются в порядке от начала к концу в
цепочке наследования - другими словами, тег <
первичной связки будет в последовательности первым.
Обычная практика - создавать объекты XPCOM из конструктора. Если требуется лишь один такой объект для данной связки, а не по объекту на каждый граничный тег, то обычный способ устроить это показан в листинге 15.12.
<constructor>
<![CDATA[ if (!document.globalPicker) {
var Cc = Components.classes;
var Ci = Components.interfaces;
var comp = Cc["@mozilla.org/filepicker;1"];
document.globalPicker = comp.getService(Ci.nsIFilePicker);
}
]]>
</constructor>
В этом коде каждый граничный тег проверяет, была ли уже проведена
инициализация, и если была, просто игнорирует этот шаг. Все связки
объединяются в разное время, но поскольку Mozilla выполняет лишь одну
задачу одновременно (
Тег < - простой контейнер, содержащий все
обработчики событий XBL-связки. Он не имеет собственных специальных
атрибутов. Он содержит один или более тегов <. Каждый
тег отвечает за исполнение некоторого кода JavaScript в ответ
на событие
Связки XBL в директории
Обработчики событий, определяемые в XBL, - один из четырех
источников обработчиков событий в Mozilla. Лекция 6,
"События", описывает поддержку обработчиков в стиле "on...". Там также описывается тег <key>. Его
синтаксис очень похож на синтаксис тега <. Последний тип
обработчиков зарыт в самой глубине платформы. Эти обработчики написаны
на C/C++ и автоматически устанавливаются платформой при первом
открытии окна.
Этот последний тип обработчиков - обработчики по умолчанию, которые
действуют, если ничто иное не установлено. Платформа Mozilla создает
специальный контроллер команд для обработки фокуса и точно так же
устанавливает ряд специальных обработчиков для наиболее типичных
событий. Когда добавляются обработчики <key>, они пристраиваются
на верхушку группы фундаментальных обработчиков, так же, как
определенные в приложении обработчики onclick пристраиваются на
верхушку XBL-связок. Когда добавляются обработчики <,
они располагаются рядом с фундаментальными обработчиками, как если бы
и те, и другие были зарегистрированы с помощью addEventListener().
Хотя последний, наиболее фундаментальный тип обработчиков
реализован как часть XBL системы, они недоступны для прикладных
программистов. Главное, на что следует обратить внимание, это то, что
есть обработчики, лежащие ниже XBL системы, и поиск в
Тег < очень похож на XUL-тег <key>. Он
определяет одну цель события (event target) и одно действие для одного
точно определенного события. Действие - либо фрагмент скрипта, либо
команда.
Тег < реализует действие по умолчанию для события,
возникающего в граничном теге. Оно может быть переопределено в самом
граничном теге с помощью обычного обработчика событий
Чтобы обработчик начал действовать, в граничном теге должно
возникнуть соответствующее событие. Это значит, что событие должно
быть создано либо действием пользователя, как последовательность
изменений документа, либо с помощью метода dispatchEvent().
Обсуждение событий XBL следует ниже, в разделе "Скриптинг"
этой лекции.
Тег < имеет следующие специальные атрибуты:
event phase command modifiers clickcount key keycode charcode button action
Атрибут event определяет mousedown - пример события, которое не
имеет значения по умолчанию.
Атрибут определяет, на какой стадии события в цикле ", "target" или "bubbling".
По-умолчанию "bubbling".
Атрибут command определяет команду (как описано в лекции 9,
"Команды"), которая будет выполняться, когда возникнет
событие. Однако контроллер, используемый для поиска и выполнения
команды, будет определяться тегом, имеющим фокус, а не граничным тегом
связки. Это значит, что связка должна быть способна иметь фокус, как
целое. Иначе придется предпринять некоторые действия, чтобы убедиться,
что часть связки, имеющая фокус, имеет и подходящий контроллер. command и action - взаимоисключающие атрибуты. Атрибут command не
имеет действия по умолчанию.
Атрибут modifiers имеет список значений, разделенный
пробелами или запятыми, а именно shift, control, alt, meta, accel и access. Он используется, чтобы определить,
какие модификаторы клавиш должны быть нажаты, чтобы клавиатурное
событие имело место. Все указанные модификаторы должны быть нажаты. accel - общий, платформеннонезависимый модификатор, описываемый в
лекции 6, "События". access соответствует случаю, когда
нажимается "горячая клавиша". Горячие клавиши определяются
XUL-тегом key= attribute. По умолчанию модификаторов клавиш нет.
Атрибут clickcount используется только для событий мыши. Он
содержит единственную цифру, определяющую, сколько
Атрибут key используется только для клавиатурных событий. Он
содержит единственный печатаемый символ, например "A". Нужно
использовать либо key, либо keycode для клавиатурных событий, но не
оба атрибута вместе. Значения по умолчанию нет.
Атрибут keycode используется только для клавиатурных событий. Он
содержит единственный код VK_ из списка в Таблице 6.3. Нужно
использовать либо key, либо keycode для клавиатурных событий, но не
оба атрибута вместе. Значения по умолчанию нет.
Атрибут charcode - устаревшее название атрибута key. Используйте key.
Атрибут button используется только для событий мыши. Он содержит
единственную цифру, определяющую, какая клавиша мыши нажата. Число
клавишей мыши определяется операционной системой, Mozilla поддерживает
по крайней мере три клавиши. Первая клавиша - клавиша 0. По умолчанию
- любая клавиша. На двух- или трехкнопочных мышах правая клавиша - 2.
Атрибут action содержит скрипт, который должен выполняться, когда
возникнет событие. Атрибуты action и command - взаимоисключающие.
Значения по умолчанию нет.
Если не определены ни command, ни action, можно пометить обработчик
событий на JavaScript между началом и концом тега <. Вот
пример:
<handler event="click" phase="target" clickcount="1" button="0"> this.do_custom_click(); // a <method> of the binding </handler>
Отныне это будет действием по умолчанию для события:
"единичный do_custom_click() определен где-то в связке, так что он может быть
вызван прямо в
Система XBL имеет ресурс тегов, которых нет, но кажется, что они существуют. Следующее описание применимо к версиям до 1.4.
Атрибут type для тегов <, <method> и
иных.
Атрибут applyauthorsheets тега <content>.
Атрибут applybindingsheets тега <children>.
Тег <element> и все ссылающиеся на него.
Следующие события не поддерживаются:
contentgenerated, contentdestroyed, bindingattached, bindingdetached.
Следующие два атрибута сохранились от ранних версий XBL и их
следует избегать: атрибут includes при использовании с тегом <content> и атрибут charcode при использовании с тегом <.
Тег <script> не является частью XBL и в чистом XBL работать
не будет.
Следующие атрибуты ничего не делают:
attachto applyauthorstyles styleexplicitcontent
Система наследования XBL была рассмотрена ранее в разделе "Объектоподобные свойства связок" ранее в этой лекции. Здесь мы рассмотрим ее использование. Только создатель связки может использовать наследуемые связки.
Листинг 15.13 показывает связки, связанные наследованием.
<!-- both bindings contained in example.xml -->
<binding id="smileyA">
<content>
<xul:image src="faceA.png"/>
</content>
<implementation>
<method name="methodA">
<body> return true;
</body>
</method>
</implementation>
</binding>
<binding id="smileyB" extends="example.xml#smileyA">
<content>
<xul:image src="faceB.png"/>
</content>
<implementation>
<method name="methodB">
<body> return false;
</body>
</method>
</implementation>
</binding>
В таблице 15.2 описывается, как наследуются различные части связки.
Если связка smileyA соединяется с XUL-тегом, этот тег будет иметь в
качестве контента лишь тег <image src="faceA.png">, и
один метод, methodA(). В этом случае цепочка наследования граничного
тега имеет длину 1 и содержит лишь связку smileyA. Здесь нет
наследования, и smileyA - первичная связка.
Если с XUL-тегом связывается smileyB, то этот тег будет иметь в
качестве контента единственный тег <image src="faceB.png">,
и два метода, methodA() и methodB(). В этом
случае цепочка наследования граничного тега имеет длину 1 и содержит
связку smileyB в начале и связку smileyA в хвосте цепочки. В этом
случае наследование есть, и smileyB - первичная связка.
Обе связки можно применять к разным тегам в одно и то же время.
Невозможно сказать, наследуется ли данная связка, поскольку ее URL
может быть использован откуда угодно. Если связка расположена в
Популярный прием, часто используемый в Mozilla - использовать
логику набора связок в связке без содержания. Такая связка не имеет
секций <resources> или <content>, и никогда (или редко)
непосредственно связывается с тегом. Она содержит главным образом
программную логику и информацию о состоянии.
Если другая связка использует данную как основу, методы и обработчики связки с нулевым контентом будут присоединены к расширяемой связке во время выполнения. Связку с нулевым контентом можно использовать много раз с разными целями. В терминах объектно- ориентированного программирования, связка с нулевым содержанием может быть названа "базовый класс с виртуальным содержанием".
Примером такой связки с нулевым контентом может быть связка button-base в файле button.xml архива
properties: accessible type dlgType group open checked check- State autoCheck handlers: event="command"
Эти свойства и события отвечают за управление рядом состояний,
используемых кнопкоподобными виджетами. Например, свойство checked
имеет скриптовые логики < и <, которые
позволяют граничному тегу иметь < или < -подобные состояния. Эти логики выполняют
домашнюю работу в граничном теге, устанавливая атрибуты XML и
координируя состояние checked с другими возможными атрибутами.
Логика в такой связке наследуется многими другими связками. Эти
связки, в свою очередь, наследуются многими тегами XUL: всеми
разновидностями <button>, всеми вариантами <toolbarbutton>, <, <dropmarker>, <, <menu>, кнопками в <wizard> и < -подобными окнами и т.д. Ясно, что связка button-base
используется очень широко.
Теги, основанные на связках с нулевым контентом, позволяют избежать
ненужного удвоения кода. Когда некоторый тег использует такую связку,
он должен иметь секцию <content>.
Можно создать связку XBL для обработки пользовательского ввода.
Такая связка имеет большую секцию < и понемногу всего
остального, хотя может иметь также методы и свойства.
Такие связки называются "фасадом ввода" по двум причинам. Во-первых, они создают слой обработки событий и пользовательского ввода в форме набора обработчиков. Это похоже на прилавок магазина. Во вторых, они полагаются на некие иные связки для обеспечения требуемого виджет-специфичного поведения. Это "тонкие" связки, а фасад - тонкая вещь. Вот простейший пример "фасада ввода":
<binding id="click-facade" extends="bindings.xml#base-widget">
<handlers>
<handler event="click"> this.click(); </handler>
</handlers>
</binding>
Эта простая связка возводит фасад ввода между вводом единичного
click() - эта задача
остается для некоторой иной связки. Данный метод может быть
стандартным (в этом случае его обеспечивает связка base- ), или
высокоспециализированным (в этом случае его обеспечит связка,
расширяющая связку click-facade ).
Код обработчика в этой связке может быть и посложнее. Может потребоваться управлять состоянием, включающим и выключающим определенный тип ввода, в зависимости от истории ввода. Фасад ввода - это еще одно место, где можно разместить функциональность обработки пользовательского ввода.
Так же, как и связка с нулевым содержанием, связки фасада ввода
редко непосредственно связываются прямо с тегом. Их главная цель -
извлечение из набора связок общей семантики пользовательского ввода и
сохранение этой семантики в одном месте. Отсутствие секции <content> подразумевает, что она должна быть расширена
(наследоваться) перед использованием.
В Платформе Mozilla (до версии 1.4) нет фасадов ввода, но есть
простор для их применения. Если вы заглянете в связки XBL для тегов <tree>, <listbox>, <tabbox> и HTML <select>,
то увидите одинаковое поведение при обработке клавиатурного ввода во
всех этих связках. Это подмножество кода может быть объединено в
фасадах ввода и затем использоваться в любом виджете, обеспечивая
однотипное поведение.
Mozilla сейчас имеет одну разновидность фасадов ввода. Это
документы XUL, содержащие набор связок <key>. Эти документы
включаются в большинство приложений Mozilla через оверлеи. Так же как
фасады ввода XBL характерны для связок XBL, фасады ввода XUL в форме
наборов связок <key> характерны для документов XUL.
Название этой лекции предполагает, что связки используются для создания законченного виджета, и это конечно так. Но возможны связки для реализации лишь части виджета. Такие связки называются связками внутреннего контента.
Связки внутреннего контента создавать просто. Нужно сделать
некоторые предположения о родительском теге граничного тега такой
связки. Мы предполагаем, что граничный тег будет предоставлять контент
своему родительскому тегу, который должен являться контейнером.
Контейнер отвечает за границы виджета. Связка внутреннего контента
полагается на то, что родительский тег будет работать корректно. В XUL
очевидными контейнерами являются <box>, <button>, <menupopup>, <scrollbar> и <.
Связки внутреннего контента зависят от родительского тега граничного тега и тесно связаны с ним. Такая связка может предоставлять методы и свойства, ожидаемые родительским тегом, либо иную информацию. Эта тесная связка подразумевает, что связка сама по себе будет выглядеть неважно. А вызванная из соответствующего контейнера, она будет отлично ему соответствовать.
В XUL несколько связок следуют этой философии. Например, теги,
используемые внутри тега <scrollbar>: <, < и <scrollbarbutton>. Не все эти теги имеют
XBL-связки, но все они полагаются на родительский тег для корректного
функционирования. Примеры тегов с XBL связками: тег <dropmarker>
внутри тега <button> и <tabs> внутри <tabbox>.
Когда связка привязывается к тегу в целевом документе, она проходит следующий путь:
-moz-binding у некоторого загружаемого тега.onload.extends, шаги 2-7 повторяются (параллельно) для каждой связки в цепочке наследования. Так что какая-то другая связка может достичь шага 7 до первичной связки.<content> копируются в граничный тег.<handler > устанавливаются в граничном теге с помощью менеджера связывания.<property> и <method> добавляются <constructor > в цепочке наследования.onload задач уменьшается на единицу.Для JavaScript граничный тег выглядит как обычный объект
Свойства могут вызываться как методы, или присваиваться, или быть прочитаны.
Свойства могут быть добавлены или установлены в null. Свойства,
содержащие методы (объекты Function ), могут быть изменены
определенными нами методами.
Обработчики событий, загруженные с помощью стилевого атрибута on..., или с помощью addEventListener(), могут заменить
собой обработчики связки.
Интерфейсы
Интерфейсы
Ни одно из этих действий не затрагивает XBL документ связки для граничного тега.
Программисту XBL связки следует в первую очередь обратить внимание
на время загрузки связки. Общего способа определить, закончился ли
процесс загрузки связки, нет. Единственный способ удостовериться в
этом - использовать обработчик onload документа, к которому
принадлежит данный тег, и избегать шаблонов с отложенной
("ленивой") загрузкой (lazy-loading templates). Если вы
используете целиком вручную написанные связки, снабдите их некоторым
сигналом, что загрузка окончена.
Другой важный аспект скриптования граничного тега имеет дело с
обработкой событий. Это материя обычных
Обычно события event. Свойство event.originalTarget этого объекта очень часто используется в связке;
(в версии 1.4 свойство event.target еще не надежно).
Если, однако, граничный тег не является частью фокусного кольца
данного окна (как, например, тег XUL <box> ), часть объединяемого
контента все еще может получить событие. В частности, если
объединяемый контент содержит теги, являющиеся кандидатами в фокусное
кольцо (как < или <button> ), эти теги могут
получить фокус клавишей tab. Здесь работает следующий принцип:
Если тег может быть способен получить фокус, а его родительский тег - нет, то пусть он его получит.
Система связок XBL не имеет интерфейса для "обновления" или "перестройки", которым можно было бы обновить граничный тег. Граничный тег может только целиком получить или потерять связку. Существует два способа сделать это.
Первый путь - изменить связку граничного тега: модифицировать
свойство стиля -mozbinding скриптом. Самая очевидная возможность
сделать это - присвоить данному свойству специальное значение none или
убрать это значение. К сожалению, ошибки в Mozilla делают этот путь
ненадежным. Рекомендуемая альтернатива - создать два стилевых
класса:
.binding-installed { -moz-binding : url("test.xml#Test"); }
.binding-removed { -moz-binding : none; }
Вместо того чтобы указывать значение самому свойству -moz-,
присвойте
Второй путь изменить связку граничного тега - использовать специальный интерфейс XPCOM. Этот интерфейс
nsIDOMDocumentXBL
Он всегда доступен для объекта документа. В Таблице 15.3 перечислены методы этого интерфейса.
| Возвращает | |
|---|---|
void |
addBinding(nsIDOMElement element, String URL) |
void |
removeBinding(nsIDOMElement element, String URL) |
nsIDocument |
loadBindingDocument(String URL) |
nsIDomElement |
getBindingParent(nsIDOMNode node) |
nsIDOMNodeList |
getAnonymousNodes(nsIDOMElement element) |
nsIDOMElement |
getAnonymousElementByAttribute(nsIDOMElement element, String attribute, String value) |
Методы addBinding() и removeBinding(), соответственно, добавляют и
убирают из объекта
Метод loadBindingDocument() загружает (синхронизируя процесс)
XBL-документ с указанным URL в дерево
Оставшиеся два метода - XBL-вариации метода document.. Вместо того, чтобы возвращать объекты тега
из дерева
getAnonymousNodes() возвращает объект, содержащий все
непосредственные дочерние теги тега <content> связки. Число
дочерних тегов равно свойству length возвращаемого объекта, и они
доступны методом item() возвращаемого объекта, то есть номеру
индекса.
getAnonymousElementByAttribute() возвращает единичный тег из набора
тегов внутри тега <content> связки.
Возвращаемый тег имеет атрибут name и атрибут value, указанные в
вызове метода.
Последний метод решает проблему, возникающую при слиянии anonid. Указываемый
Вторая проблема, решаемая этим тегом, возникает при использовании
тем. Тема может содержать не только стилевую информацию; скины темы
могут содержать скрипты. Эти скрипты могут модифицировать контент
данного виджета так, чтобы он соответствовал общему облику темы. getAnonymousElementByAttribute() позволяет
Система XPCOM имеет два компонента, имеющих отношение к XBL:
@mozilla.org/xbl;1 @mozilla.org/xbl/binding-manager;1
Ни один из них не имеет интерфейсов, пригодных для использования в прикладных скриптах.
Расширение -moz- стилей -moz- ".
Каждая создаваемая связка должна иметь собственную стилевую
таблицу, так, чтобы виджет мог поддерживать многие темы и скины. Эта
таблица указывается в секции <resources> кода связки.
В данном разделе "Практика" мы разработаем некоторый код общего назначения, использующий XBL. В частности, мы создадим новую XBL-связку и соответствующий ей XUL-тег, которые внесут свой вклад в содержание и поведение диалогового окна утилиты NoteTaker.
Не следует превращать контент XUL в связки XBL только потому, что есть такая возможность. Только код, используемый более одного раза на данной странице или в другом приложении, является подходящим кандидатом для включения в XBL. Связки XBL помещают свой контент в некоторую добавочную структуру. Обычный контент не всегда годится для XBL с точки зрения эффективности кода. Только если связка вызывается часто, она уменьшит, а не увеличит сложность результирующего кода.
В утилите NoteTaker нет повторяющихся частей кода в контенте панели
инструментов или диалогового окна, так что вряд ли стоит использовать
XBL. Но ведь нам нужен пример для иллюстрации этой технологии. Стоит
поэкспериментировать с информацией о позиционировании панели Edit
(параметры top, left, height, width ). Эти четыре параметра очень
похожи на стили позиционирования в стандарте
Мы можем улучшить существующую систему позиционирования с помощью
нового виджета. Создадим связку XBL, которой пользователь сможет
манипулировать графически, чтобы указать будущее положение заметки.
Эта связка будет виджетом специального назначения, в чем-то подобным
тегу <colorpicker>, а в чем-то - окошку Print Preview.
Этот виджет не будет интегрирован в конечный код утилиты NoteTaker, мы просто проиллюстрируем такую возможность.
Нам нужно продумать визуальный, XML, JavaScript интерфейсы, а также интерфейс пользовательского ввода, а потом воплотить эти интерфейсы в XBL-коде. Цель виджета - подсказать пользователю информацию о позиционировании и затем сделать эту информацию доступной основному XUL-документу.
Сначала взглянем на визуальный интерфейс. Визуальная часть -
вдохновитель всей конструкции виджета. Она должна явиться нам как
озарение, поскольку все виджеты по своей природе представляют собой
нечто уникальное. Это вызов нашему творческому мышлению, ведь каждый
виджет должен быть оригинален. Если он не оригинален, мы можем
попросту скопировать и усовершенствовать существующий виджет, например <button>.
Есть, правда, один способ избежать необходимости быть слишком
оригинальным. Виджет XBL может вбирать в себя другие, более простые
виджеты и образовывать из них группу. Такую
Поскольку все XUL-теги и комбинации тегов занимают на экране прямоугольную область, мы знаем, что должны начать с прямоугольника. Можно исхитриться и сконструировать сверхъестественный виджет, который нарушит это правило, но столь далеко в код приходится углубляться не слишком часто. На рисунке 15.2 изображен простой набросок нашегонового виджета.
Идея напоминает другие утилиты визуального конфигурирования, такие
как
(рис 15.2) Модель XBL-связки, позволяющая пользователю позиционировать заметку.На рисунке 15.2 главный
прямоугольник - наш новый виджет. Он имеет три части: задник - <box>, представляющий весь десктоп полностью, опциональный белый <box>, представляющий окно или страницу браузера, и желтый <box>, представляющий заметку, которую нужно позиционировать.
Каждый <box> имеет соответствующую надпись, на тот случай, если
кому-то что-то не очевидно. Главный прямоугольник получит размеры
согласно параметрам разрешения экрана.
Этот главный прямоугольник принимает пользовательский ввод. Если мы
кликнем главной кнопкой мыши внутри прямоугольника, заметка
расположится так, что ее верхний левый угол окажется как раз под
местом
Когда заметка позиционирована, вычисляются ее координаты. Если белого прямоугольника (браузера) нет, координаты относятся ко всему десктопу. Браузер может занимать и весь десктоп. Если белый прямоугольник имеет место, координаты отсчитываются от его угла. Белый прямоугольник нужен по психологическим соображениям: люди обычно предпочитают прямоугольники в "золотой пропорции", т.е. в пропорции 1:1,618. Окошки браузера в конце концов обычно оказываются именно в этой пропорции. Белый прямоугольник напоминает нам, как эта идеальная пропорция выглядит.
Второй интерфейс - пользовательский ввод. Виджет будет поддерживать
разовый
Третий необходимый интерфейс - XML-интерфейс. Для нас это означает
выбор имени тега и множество требуемых атрибутов, которые нам
понадобятся, чтобы обеспечить его вид и поведение. Связку можно
построить на любом теге, но мы выбираем <noteplacer>.
Следующие атрибуты будут иметь специальные значения:
scale screenx screeny pageless
scale - целое, указывающее размер виджета noteplacer по отношению к
размеру десктопа. Например, значение 4 (значение по умолчанию 2)
означает, что noteplacer вчетверо меньше целого десктопа.
screenx означает ширину десктопа в пикселях. Значение по умолчанию
дано свойством window.screen.width.
screeny означает высоту десктопа в пикселях. Значение по умолчанию
дано свойством window.screen.height.
pageless может иметь значение true или false. В случае true белый прямоугольник не появится на
фоне виджета. По умолчанию false.
Теперь вопрос верстки. Будет ли виджет способен изменять размеры?
Какова его ориентация? Список вопросов растет. Поскольку виджет noteplacer изображает форму десктопа, он будет иметь фиксированный
размер и не будет растягиваться. Он должен всегда иметь горизонтальную
ориентацию и не изменять ее.
Последний интерфейс - JavaScript XBL-интерфейс граничного тега. Мы реализуем следующие свойства:
top left width height scale screenx screeny pageless setFromEvent(e,primary)
top, left, width, и height
соответствуют полям в диалоговом окне Edit.
scale, screenx, screeny, и pageless относятся к атрибутам XML граничного тега.
setFromEvent() позиционирует один из углов заметки, используя
объект event. Если второй аргумент true, устанавливается верхний левый
угол, если нет, правый нижний.
Так вот, ни с того ни с сего, не приходится думать о поддержке
каких-либо существующих интерфейсов платформы (например, nsIAccessible ), чего, может, и хотелось бы. Граничный тег будет
автоматически поддерживать стандартные интерфейсы
Все вместе эти четыре интерфейса полностью определяют новый виджет. Последний вопрос, который нужно задать: можем ли мы использовать какую-либо уже существующую XBL-связку? Похоже, что нет, наш новый виджет слишком прост.
Чтобы создать собственно связку, начнем с простого ее скелета. На этом шаге мы определим ее части. Скелет связки приведен в листинге 15.14.
<?xml version="1.0"?>
<bindings id="notetaker"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="noteplacer">
<resources> </resources>
<content> </content>
<implementation>
<constructor></constructor>
<destructor></destructor>
</implementation>
<handlers></handlers>
</binding>
</bindings>
Набор связок, необходимых для утилиты NoteTaker, мы назвали
"notetaker", а связку тега <noteplacer> -
"noteplacer". Поскольку здесь нет цепочки наследования, нет
и атрибута extends в теге <. Поскольку новый виджет
основан на простых XUL-боксах, нет нужды и в атрибуте display. Нам
нужно лишь заполнить эти четыре секции связки.
Начнем с секций <content> и <resources>. Используем
контент, служивший основой для рисунка 15.3 и затем рассмотрим, как
можно модифицировать его для XBL-системы. Используемый контент
приведен в листинге 15.15.
<stack minwidth="320" minheight="240">
<description value="Screen"/>
<box class="page" top="0" left="86" minwidth="148"
minheight="240">
<description value="Page"/>
</box>
<box class="note" top="20" left="106" minwidth="40"
minheight="40">
<description value="Note"/>
</box>
</stack>
Этот контент имеет фиксированные параметры размера, указываемые прямо в коде. Большинство виджетов в вопросе размеров должно полагаться на платформу, а не устанавливать их жестко, чтобы верстка контента была аккуратной. Наш виджет, однако, имеет фиксированные размеры, поэтому мы здесь нарушили это правило.
Прежде чем этот код сгодится для секции <content> связки,
нужно еще поработать. Существуют некоторые проблемы:
Часть page виджета всегда присутствует, нам нужно сделать ее
невидимой, если используется полный размер экрана браузера.
Часть page слишком скучна. Мы можем захотеть поместить здесь что-то
более наглядное, например, панель инструментов и меню браузера.
Фиксированные атрибуты размеров бесполезны для большинства тегов.
<noteplacer> и текущих значений разрешения экрана.
Размеры шрифтов также пока неясны. Если виджет представляет собой скалируемый десктоп, размеры шрифтов должны также быть скалируемыми.
Для всех названных проблем есть простые решения. Исчезновение блока page - самое простое. Позволим тегу <box>, содержащему блок page, наследовать атрибут pageless из тега <notepicker>:
<box class="page" xbl:inherits="collapsed=pageless" ...>
Чтобы сделать page не столь скучным, позволим эксплицитному
контенту тега <noteplacer> определять контент тега <box class="page">. Аккуратно пересмотрев правила слияния
<description value="page"/>
нужно изменить на:
<children> <description value="page"/> </children>
Если эксплицитный контент есть, он будет добавлен в соответствующее
место, если нет, по умолчанию имеется тег <description>.
Теперь избавимся от фиксированных размеров, указанных в пикселях.
Они были получены для виджета на десктопе 640х480, с коэффициентом
пропорциональности два. Вместо этого пусть значения вычисляются в
конструкторе связки во время выполнения. Мы не можем просто
наследовать их из атрибутов тега <noteplacer>, поскольку
требуемые значения являются математической комбинацией значений этих
атрибутов, а не просто копией. Вскоре мы увидим, как это делается.
Наконец, размеры шрифтов также пусть вычисляет конструктор. Добавим
стиль всякому <description>, и для тега <label>. Этот стиль скалирует
для нас размеры шрифтов, чтобы они соответствовали размерам виджета. В
некоторых случаях текст получится нечитаемым, но и цель виджета -
лишь дать некоторое наглядное представление.
Для выполнения этих двух пунктов добавим атрибут anonid < и два тега <box>.
Результат показан в листинге 15.16. Обратите внимание на префикс xul:
namespace каждого XUL-тега.
<content>
<xul:stack anonid="desktop">
<xul:description value="Screen"/>
<xul:box xbl:inherits="collapsed=pageless"
class="page" anonid="page">
<xul:children>
<xul:description value="Page"/>
</xul:children>
</xul:box>
<xul:box class="note" anonid="note">
<xul:description value="Note"/>
</xul:box>
</xul:stack>
</content>
Если мы попробуем запустить связку на данном этапе (вообще-то неплохая идея), результат будет выглядеть не слишком хорошо. Он так выглядит, потому что виджет не имеет пока необходимой ему информации. Связка работает, она просто еще не закончена.
Наконец, мы можем создать простую стилевую таблицу, хранящую
значения по умолчанию для
stack {
background-color : background;
font-family : -moz-fixed;
}
box.page {
background-color : white;
border : solid thin;
border-color : black;
}
box.note {
background-color : lightyellow;
border : solid thin;
border-color : yellow;
}
В этом случает цвет фона будет тот же, что и у реального десктопа.
Шрифт -moz-fixed (системный) имеет одно важное свойство: он может
скалироваться до любого размера. 7px это 14px, скалированный с
коэффициентом два. Заметьте, что значение пространства имен по
умолчанию для подключаемых стилевых таблиц XBL - это пространство имен
XUL.
Это означает, что для тегов в стилевых таблицах не нужно указывать
префикс с пространством имен
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul");
xul|stack { ... styles ... };
Стилевая таблица помещается в секцию <resources>
спецификации XBL с помощью относительного URL. Она имеет относительный
URL, потому что связка noteplacer принадлежит только пакету notetaker
и помещается в той же директории, что и он. Это не глобальная связка в
глобальном пакете. В общем случае файл CSS следует использовать во
всех связках пакета notetaker, и этот файл должен называться
notetaker.css. Мы используем другое имя, чтобы подчеркнуть, что этот
файл имеет только лишь стилевую информацию для XBL, и избежать
конфликта со
<resources> <stylesheet src="noteplacer.css"/> </resources>
Создав контент и стилевую таблицу, мы выполнили половину работ по созданию связки. Мы пока что создали только ее визуальный и XML интерфейсы.
Нам остаются секции < и <. Эти
две секции определяют интерфейс JavaScript и интерфейс
пользовательского ввода. Сначала рассмотрим интерфейс JavaScript,
определенный нами в списке требований в предыдущем разделе.
Очень часто можно увидеть, что XML-атрибуты прямо описываются как
свойства JavaScript граничного объекта, и мы можем поступить так же.
Это делается просто, как можно увидеть из примера, взятого из связки button-base:
<property name="type"
onget="return this.getAttribute('type');"
onset="this.setAttribute('type', val);
return val;"
/>
Мы не используем это метод, потому что не хотим сохранять состояние нашего виджета в атрибутах XML. Это решение основано на рассмотрении преимуществ и недостатков сохранения состояния в атрибутах. Вот преимущества:
<content> других связок.Недостатки сохранения состояния в XML-атрибутах следующие:
Если вы создаете набор виджетов общего назначения или часто используемую связку, преимущества могут перевесить недостатки, и можно рассмотреть использование XML атрибутов.
В нашем случае виджет определенно специфичен лишь для единственного
приложения, и не является виджетом общего назначения. У нас нет
очевидного случая применения его с очевидными значениями по умолчанию.
Мы не собираемся добавлять код платформы для его обработки или
использовать сложные стилевые приемы. Единственным случаем отсутствия
атрибута может быть атрибут pageless, где отсутствие значения можно
понять как равенство его false. Для нашего виджета мы предпочтем
надежный интерфейс, никогда не дающий нулевых или пустых значений.
Остальная часть приложения может использовать этот виджет как
настоящий закрытый ящик. Это решение означает, что мы будем
применять JavaScript для сохранения состояния виджета.
В общем и целом, нам нужно теперь создать контент для тегов <field>, <property>, <method>, < и < виджета.
Для тега <field> мы используем золотое
<field name="ratio">(1+Math.sqrt(5))/2</field>
Это математическое выражение - один из способов вычислить золотое
Что касается конструктора, заметим, что наш виджет довольно
большой, и что он не должен увеличиваться и уменьшаться в размерах в
зависимости от изменений окружения. Такой фиксированный размер -
нестандартное решение. Но он удовлетворяет нашей цели, т.е.
аккуратному отображению десктопа. Это означает, что < может вычислять размеры виджета лишь раз, и нам
не нужно беспокоиться о том, чтобы он был растягиваемым впоследствии.
Конструктор также может сохранять информацию о состоянии виджета в
JavaScript. Логика и верстки, и состояний показана в листинге
15.18.
this.getAEBA = function (x,y,z) {
return document.getAnonymousElementByAttribute(x,y,z);
}
this.desktop = getAEBA(this,"anonid","desktop");
this.page = getAEBA(this,"anonid","page");
this.note = getAEBA(this,"anonid","note");
this.d = {}; // protect numbers from string-ification
this.d.top = 40;
this.d.left = 40;
this.d.width = 100;
this.d.height = 100;
this.d.scale = att2var("scale", 2);
this.d.screenx = att2var("screenx", window.screen.width);
this.d.screeny = att2var("screeny", window.screen.height);
this.d.pageless = att2var("pageless", false);
this.d.page_offset = 0;
if ( !d.pageless )
d.page_offset = (d.screenx - d.screeny/ratio)/d.scale/2;
/* layout the content once */
this.setAttribute("style","font-size:"+14/d.scale+"px;");
placeDesktop();
placeNote();
if ( ! d.pageless )
placePage();
Свойство getAEBA - всего лишь сокращение для труднопроизносимого
метода document.getAnonymousElementByAttribute(). Мы запомним важные
d (для data) сохранит
значение состояния data как число, несмотря на тенденцию XBL
преобразовывать простые переменные в строки. Все свойства this.d
спрятаны от пользователя виджета (специалиста по прикладному
программированию, использующего тег <noteplacer> ). После того,
как эти свойства будут вычислены, часть виджета <content>
получит правильные значения атрибутов, включая скалирование текста.
Функции att2var(), placeDesktop(), placeNote() и placePage() являются
методами объекта, объявленного в начале кода конструктора. Они
показаны в листинге 15.19.
this.att2var = function (name, dvalue) {
var val = this.getAttribute(name);
if ( val == "" ) return dvalue;
if ( isNaN(val) ) return dvalue;
return val - 0;
}
this.arg2var = function (arg) {
var err = "Bad argument passed to noteplacer binding";
if (arg == "" ) throw err;
if ( isNaN(arg) ) throw err;
return arg;
}
this.placeNote = function () {
note.setAttribute("top", d.top /d.scale);
note.setAttribute("left", d.page_offset + d.left / d.scale);
note.setAttribute("minwidth", d.width / d.scale);
note.setAttribute("minheight",d.height / d.scale);
}
this.placeDesktop = function () {
desktop.setAttribute("minwidth", d.screenx/d.scale);
desktop.setAttribute("minheight",d.screeny/d.scale);
}
this.placePage = function () {
page.setAttribute("minheight", d.screeny/d.scale);
page.setAttribute("minwidth", d.screeny/d.scale/ratio);
page.setAttribute("top", "0"); page.setAttribute("left",
d.page_offset);
}
Метод att2var() вычисляет значение arg2var() проверяет, является ли
передаваемый аргумент числом. Скоро мы его используем. Остальные
методы определяют положение виджета на основании информации о
состоянии и некоторых вычислений. Все эти методы, а также метод getAEBA(), принадлежат только виджету. Они не проявляются как свойства
<noteplacer>.
Мы не держим XPCOM-компонентов или других больших объектов во время
жизни виджета, так что не от чего и избавляться, когда виджет
закрывается. Как следствие, тег < не будет иметь
содержания.
Благодаря предпринятым нами к настоящему моменту усилиям по
сохранению информации о состоянии виджета, реализация тегов <property> очень проста. Листинг 15.20 демонстрирует эти
теги.
<property name="top" onget="return this.d.top;" onset="this.d.top = arg2var(val); placeNote();" /> <property name="left" onget="return this.d.left;" onset="this.d.left = arg2var(val); placeNote();" /> <property name="width" onget="return this.d.width;" onset="this.d.width = arg2var(val); placeNote();" /> <property name="height" onget="return this.d.height;" onset="this.d.height = arg2var(val); placeNote();" /> <property name="scale" readonly="true" onget="return this.d.scale;" /> <property name="screenx" readonly="true" onget="return this.d.screenx;" /> <property name="screeny" readonly="true" onget="return this.d.screeny;" /> <property name="pageless" readonly="true" onget="return this.d.pageless;" />
Вряд ли эти теги могли бы быть проще. Заметьте, как установщики
передают исключения через arg2var(), если значение, пересылаемое
виджету пользователем, бессмысленно. Если бы наш виджет был более
динамичным, вызов функции placeNote() в каждом атрибуте onget был бы
более сложен и требовал бы большего объема вычислений.
Вернемся к единственному требуемому тегу <method>.
Координаты виджета, используемые и в атрибутах XML, и в свойствах
JavaScript вычисляются относительно панели, на которую помещена
заметка. Однако, когда наступает событие setFromEvent() позволяет
нам позиционировать угол заметки, используя этот объект. Виджет
выполняет требуемое преобразование координат. Метод показан в листинге
15.21.
this.getCoords = function(x,y) {
return {
x: (x - this.boxObject.x - d.page_offset) * d.scale,
y: (y - this.boxObject.y) * d.scale
};
}
<method name="setFromEvent">
<parameter name="evt"/>
<parameter name="cornerFlag"/>
<body>
<![CDATA[
var coords = getCoords(evt.clientX, evt.clientY);
if (cornerFlag) {
d.width += d.left - coords.x;
d.height += d.top - coords.y;
d.top = coords.y;
d.left = coords.x;
}
else {
d.width = coords.x - d.left;
d.height = coords.y - d.top;
}
placeNote();
]]>
</body>
</method>
Функция getCoords() преобразует указанные координаты. После того,
как этот метод получает локальные координаты из getCoords(), он вновь
вычисляет размер и положение верхнего левого угла заметки, основываясь
на полученных значениях координат и существующих значениях размеров
заметки. Затем заметка вновь позиционируется. Этот метод может
использовать некоторые добавочные проверки (например, высота и ширина
не должны быть отрицательны), но для наших целей он выполняет свою
работу.
Последняя часть спецификации связки - секция <. У
нас есть два обработчика, оба для this.d.topclick. Если она имеет
значение true, false, нижнего правого. Инициализируем переменную
значением true в конструкторе. Для вторичной кнопки используем теорему
Пифагора ("квадрат гипотенузы прямоугольного треугольника равен
сумме квадратов катетов"), чтобы вычислить угол, находящийся по
диагонали, ближайший к месту
<handlers>
<handler event="click" button="0">
<![CDATA[
this.setFromEvent(event,d.topclick);
this.d.topclick = !this.d.topclick;
]]>
</handler>
<handler event="click" button="2">
<![CDATA[
var coords = this.getCoords(event.clientX,event.clientY);
var dist1, dist2;
with (Math) {
dist1 = sqrt(pow(coords.x-d.left,2)
+ pow(coords.y-d.top,2));
dist2 = sqrt( pow(coords.x - (d.left + d.width), 2)
+ pow(coords.y - (d.top + d.height), 2) );
}
this.setFromEvent(event, (dist1 < dist2));
]]>
</handler>
</handlers>
Используя секцию setFromEvent() и частный метод getCoords(), так что
их логика очень проста.
С окончанием работы над секцией < заканчивается
работа над связкой в целом, а это почти 150 строк кода. Поскольку
изменений больше не требуется, все что нам остается - это попробовать
ее в работе.
Создав связку noteplacer, теперь мы хотим ее опробовать. Несколько
следующих шагов, по сути, - полезный способ создания тестовой упряжи
для новой связки. Подобная "упряжь" полезна не только для
финального тестирования, но и во время отладки.
Чтобы связать связку с тегом, используем стилевое правило:
noteplacer { -moz-binding : url("noteplacer.xml#noteplacer"); }
Пока поместим эту строку в файл xulextras.css. Этот файл будет
расположен в той же директории, что и весь контент noteplacer. Эта
стилевая таблица добавит к стандартному множеству тегов XUL новый тег <noteplacer>.
При тестировании нового виджета мы хотим увидеть следующие вещи:
Виджет правильно вписывается в окружающий контент.
Виджет правильно реагирует на пользовательский ввод, включая изменения размеров окна.
Атрибуты, указанные виджету, производят желаемый эффект.
Эксплицитный контент, передаваемый виджету, дает желаемый эффект.
С этой целью создадим тестовый XUL-документ, приведенный в листинге 15.23.
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="xulextras.css" type="text/css"?>
<!DOCTYPE window>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/
there.is.only.xul" onload="install()">
<script>
var np; function install() {
np = document.getElementById("test");
np.addEventListener("click", report, false);
}
function report() {
var str = "";
str += "Top: " + np.top + "\n";
str += "Left: " + np.left + "\n";
str += "Width: " + np.width + "\n";
str += "Height: " + np.height + "\n";
str += "ScreenX: " + np.screenx + "\n";
str += "ScreenY: " + np.screeny + "\n";
str += "scale: " + np.scale + "\n";
alert(str);
}
</script>
<description>Before Test </description>
<hbox>
<description value="Left of Test"/>
<noteplacer screenx="1024" screeny="768" scale="4">
<toolbox flex="1">
<toolbar grippyhidden="true">
<description value="File"/>
<description value="Edit"/>
<description value="View"/>
<description value="Go"/>
<spacer flex="1"/>
</toolbar>
<spacer style="background-color:white" flex="1"/>
</toolbox>
</noteplacer>
<description value="Right of Test"/>
</hbox>
<description>After Test </description>
</window>
</handler>
</handlers>
Этот документ упаковывает тег <noteplacer> в соответствующий
контент и добавляет имитацию панели инструментов. Он также содержит
обработчик событий этого тега. Обработчик событий использует
обработчики
Имитация панели инструментов, конечно, очень примитивна. Но она
позволяет понять, что имеется в виду, а это все, что от нее в данный
момент требуется. Возможно, когда-нибудь технология захвата картинки
экрана в компоненте инспектора
(рис 15.3) Тестовый XUL-документ с тегом <noteplacer>.Если обработчик
(рис 15.4) Диагностическое предупреждение с сообщением о состоянии виджета <noteplacer>Немного вычислений и высвеченные значения положения заметки могут быть подтверждены как подходящие.
Мы видим, как тег <noteplacer> может быть интегрирован в
приложение NoteTaker с помощью JavaScript. Из диалогового окна Edit он
может быть загружен в отдельное второе диалоговое окно или встроен
где-либо в уже существующий <tabbox>. Когда диалоговое окно
закрывается, обработчик событий onclose считывает состояние виджета и
копирует значения в соответствующие поля панели Edit.
Сам по себе наш виджет даст пользователю немного подсказок по его
использованию. Как и многие другие теги XUL, <noteplacer>
функционален, но не очевиден. Этот тег должен быть окружен другим
контентом перед предъявлением его пользователю. На рисунке 15.5
приведен один из возможных сценариев.
(рис 15.5) Использование тега <noteplacer> в приложении.На этом раздел "Практика" данной лекции заканчивается.
В связках XBL нет ничего загадочного; и объект window, и объект document доступны всем свойствам, методам, обработчикам событий, и
конструкторам/
Нет ничего загадочного и в работе связок с
Две наиболее часто возникающие проблемы при создании XBL-связки связаны с пространствами имен XML и внутренними свойствами JavaScript. Запомните о пространствах имен следующее:
XBL-свойсво inherit должно иметь префикс с идентификатором
пространства имен наподобие xbl:, потому что пространство имен,
используемое по умолчанию для тега, который содержит это свойство,
всегда либо XUL, либо HTML.
XBL должен иметь отдельное пространство имен, потому что некоторые
имена его тегов совпадают с именами тегов других приложений XML,
такими как XUL,
Если применяется стандартный набор пространств имен, где по
умолчанию используется XBL, каждый XUL или HTML тег в секции <content> должен будет иметь префикс соответствующего
пространства имен. В противном случае никакой контент не будет выведен
на экран.
В свойствах JavaScript XBL-связок допускаются две простые оплошности:
Забывают указывать префикс this для переменных связки.
Забывают, что когда простые переменные с префиксом this
сохраняются, они преобразуются в строку.
Но наиболее сложная проблема с конструированием связок состоит в том, что они загружаются асинхронно. Мы не можем даже предполагать, в какой момент свойства и методы связки станут доступны. У этой проблемы есть несколько простых решений.
Самое простое решение - использовать обработчик событий документа onload для любого требуемого инициализационного кода. Это решение
годится, только если все используемые связки грузятся лишь однажды из
стилевых таблиц и никогда не изменяются.
Другое простое решение - добавить к каждой создаваемой связке такой тег:
<field name="loaded" readonly="true">true</field>
Перед обращением к связке из скрипта проверьте данное свойство;
если оно имеет значение true, значит, связка доступна.
Более систематическое решение состоит в использовании части связки <. Вот такой кусочек кода - простая регистрационная
система:
with (window.document) bindTotal = (bindTotal) ? ++bindTotal : 1;
Если окно приложения XUL состоит всего из нескольких очень сложных связок XBL, процесс их загрузки проследить довольно легко. Общее число загруженных виджетов можно проверять по таймеру. А если деструктор виджета уменьшает это число, оно становится динамически изменяемым показателем доступности виджетов. Для высокоспециализированных виджетов такой промежуточный слой между виджетом и содержащим его документом может стать весьма практичным решением. Та же практика используется для координации фреймов в web-документе.
Последнее, и глобальное, решение проблемы асинхронности -
использовать метод loadBindingDocument().
Наконец, XBL-виджеты имеют некоторые ограничения, связанные с
секретностью. Если два документа, загружаемые с двух разных URL,
должны иметь полный доступ друг к другу, они должны пройти тест
Mozilla, который называется "Same Origin". Этот тест
требует, чтобы оба URL принадлежали одному и тому же серверу.
XBL-связки также должны проходить этот тест, если они установлены там, где
требования секретности могут быть нарушены. Приложение XUL с одного
сервера не может стандартным способом использовать XBL-связку с
другого. Чем возиться со сложной процедурой сертификации и цифровой
подписи кода, обычно проще инсталлировать XBL-связку в
В любом случае, если связка должна каким-то образом использовать
преимущества, предоставляемые XPCOM-компонентами, документ, содержащий
граничный тег связки, должен быть инсталлирован в
Технология XBL делает разработку пользовательских интерфейсов более гибкой и компонентной. Она следует общей философии языков разметки, подобных HTML: она настолько проста, чтобы ее легко было использовать. Но XBL также и мощный инструмент разработки программного обеспечения - он позволяет некоторой части функциональности в коде быть изолированной, четко определенной и использоваться неоднократно.
XBL-часть платформы Mozilla обогащает платформу интерактивными, визуальными виджетами, придавая им очень гибкие и объектно- ориентированные свойства. XBL-связками являются почти каждый тег XUL и многие теги HTML. Действия по умолчанию, определенные этими связками, и делают эти теги столь простыми и гибкими в работе.
В следующей лекции мы увидим объекты, с которыми связки XBL обычно
связаны. Это объекты системы XPCOM. Мы уже видели многие из них, но
есть еще множество для работы с такими технологиями как XUL и
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.