Опубликован: 10.12.2007 | Уровень: специалист | Доступ: платный
Лекция 9:

Команды

9.3. Как вызвать команду

Команды в Mozilla могут быть вызваны различным образом.

Если объекты контроллер или функтор доступны, их методы могут быть вызваны прямо из JavaScript. При этом мы игнорируем систему команд и относимся к этим объектам, как к любым другим.

Из JavaScript может быть вызван метод диспетчера getControllerForCommand(). Этот метод - первый шаг по превращению имени команды в выполняемый код. В этом случае диспетчер ищет необходимую нам реализацию команды.

Из JavaScript может быть вызван метод doCommand() XUL-тега, способного иметь фокус. Если это выполнено, тег <command>, указанный как значение атрибута команды, будет выполнен. При этом мы не используем диспетчер или контроллеры.

Если нажата клавиша, имеющая соответствующий тег <key>, или мы щелкнули мышью на теге, который может иметь фокус, будет выполнена команда, указанная как значение атрибута command. Это тот же случай, как вызов метода doCommand(), за исключение того, что тег или клавиша сначала порождают событие command. Платформа имеет специальный механизм для определения типа события и атрибутов команды, чтобы определить, должна ли быть запущена соответствующая команда.

Если порождено такое событие DOM, метод dispatchEvent() может быть вызван из любого тега XUL. Если тег принадлежит фокусному кольцу, то вызов этого метода эквивалентен пользовательскому вводу, порождающему такое событие. То есть данный случай эквивалентен предыдущему.

Во всех трех описанных случаях выполняемая команда может обратиться к диспетчеру. Это свяжет тег <command> с контроллером.

Наконец, если вызван метод диспетчера UpdateCommands(), любое сообщение об изменении команды будет послано всем XUL-тегам, наблюдающим за изменениями. Это означает, что событие commandupdate будет послано всем обновителям команд ( command updaters ).

Приложения классической Mozilla включают функцию, называемую goDoCommand(). Эта функция управляет диспетчером. Это стартовая точка команд в таких приложениях. Она хранится в файле globalOverlay.js архива toolkit.jar в директории chrome.

9.3.1. Круг силы

Данный краткий обзор системы команд предоставляет удобную возможность программистам прикладных приложений. Реализация команды может и начаться, и кончиться в единственном документе XUL, как было показано ранее в примере "hello, world".

Команда может войти в систему распространения команд из обычного JavaScript. Этот скрипт может сам по себе быть обработчиком событий, возможно, для более традиционных событий DOM, таких как события click или select. В этом случае скрипт должен быть привязан к тегу XUL.

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

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

Все вместе это означает, что команда может начаться и кончиться в теге XUL (или XUL и JavaScript). Например, тег <toolbarbutton>, порождающий команду, может получить сообщение, что состояние команды изменилось. Этот же тег <toolbarbutton> может содержать и реализацию контроллера команды. Диспетчер и стандартный механизм обработки событий - лишь кусочки головоломки, созданной платформой Mozilla.

9.4. Использование команд в XUL

Для команд в Mozilla есть специальный тег, <command>. Можно использовать также <commandset> и <commands>, но это определяемые пользователем теги, не имеющие собственного значения. Тег <commandset> используется как любой иной тег-контейнер, например, <keyset>, и содержит набор тегов <command>.

XUL также имеет набор специальных атрибутов, применимых к любому тегу. Это следующие атрибуты:

command events targets commandupdater

и два обработчика событий:

oncommand oncommandupdate

Вне рамок XUL Mozilla также имеет набор заранее определенных имен команд, но мы обсудим это позже.

9.4.1. Теги <command> и command=

Тег <command> используется для определения команды, так же как тег <key> используется для определения отклика на нажатие клавиши. Он представляет команду и может воплощать конкретные ее аспекты. В терминах "круга силы" (9.3.3.1) тег <command> представляет и идентификатор, чтобы вызвать команду, и реализацию, выполняющую команду. Он имеет следующие специальные атрибуты:

disabled oncommand

Атрибут disabled может принимать значение true, в этом случае команда бездействует.

oncommand принимает значение JavaScript-кода, используемого вместо какого-либо контроллера. Иногда используются атрибуты disabled, label, accesskey, и checked. Их задействует система обновления команд, описываемая ниже, но они не имеют никакого специального значения в теге <command>.

Пример использования тега <command>:

<command id="test-command" oncommand="alert('executed');"/>

Атрибут id именует команду. Обработчик события oncommand дает реализацию команды - это обработчик команды. Если данный тег порождает событие DOM с именем command, то этот обработчик запускается. Поскольку тег <command> не имеет графического отображения (виджета), этот тег редко используется для порождения события.

Атрибут command позволяет другим тегам применять тег <command> таким же способом, каким атрибут key дает возможность другим тегам использовать тег <key>. Например:

<mytag id="myAppTag" command="test-command"/>

Если тег <mytag> порождает событие command правильного типа, вызывается упомянутая выше функция alert(). Для реализации "mytag" можно использовать только следующие теги:

<button> <checkbox> <radio> <toolbarbutton> <menu> <menuitem> <key>

Когда один из этих тегов получает фокус, воздействие пользователя порождает событие command автоматически. Обработчик oncommand можно добавить прямо в эти теги, но это нерекомендуемый способ. Лучше реализовать все нужные команды в тегах <command>, чем "размазать" их реализацию по многим виджетам приложения.

Обработчик oncommand может быть вызван прямо из JavaScript:

var target = document.getElementById("mytag-id"); 
target.doCommand();

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

Есть еще один способ использования атрибута command. Система связок XBL имеет свой тег <handler>, позволяющий обычному событию DOM, подобно событию click, передаваться в указанную команду. Для этого в XBL-теге <handler> используется атрибут command.

9.4.2. Атрибуты commandupdater="true" и oncommandupdate=

Если XUL-тег имеет эти атрибуты, он обладает способностью обновлять команды и будет получать извещения об обновлении команд. Эти извещения - часть системы "источник события - наблюдатель". Когда парсер XUL обнаруживает атрибут commandupdater, он регистрирует тег, имеющий его, как тег-наблюдатель в диспетчере. Когда вызывается метод диспетчера UpdateCommands(), все зарегистрированные наблюдатели получают извещения о событии. В результате, если происходит событие commandupdate, запускается обработчик события oncommandupdate данного тега. Пример такого кода прост:

<mytag commandupdater="true" oncommandupdate="update_all()"/>

Функция update_all() - некоторый конкретный скрипт данного приложения. Он делает всю необходимую работу с изменившейся командой. Например, такая функция есть в классической Mozilla. Файл globalOverlay.js архива toolkit.jar в chrome содержит функцию goUpdateCommand() (и иные функции go...). Эта функция выполняет стандартные процедуры обновления команд. Она устанавливает атрибут disabled тега <command>, вызывая метод контроллера isCommandEnabled().

Дальнейшие примеры обновления команд приведены в разделе "Как заставить виджет реагировать на состояние команды". Тегу, способному обновлять состояние команды, можно указать и такой фильтр:

<mytag commandupdater="true" events="focus blur" 
targets="*" oncommandupdate="update_all()"/>

Атрибут events ограничивает список событий, генерирующих событие commandupdate. Это может быть список событий, разделенных пробелами или запятыми, и он может включать имена команд. Атрибут targets имеет тот же синтаксис, за исключением того, что вместо списка имен используется список идентификаторов ( ids ). Делать это за редким исключением не рекомендуется. Таким способом мы ограничиваем список рассматриваемых событий теми, чьи цели (теги) включены в список ids. Значение по умолчанию обоих атрибутов равно "*", то есть "все".

Даже если атрибут targets указан, событие commandupdate передается тегу, способному изменить состояние команды, но не тегам - целям. Ниже мы увидим, как используется данная функциональность.

Событие commandupdate можно вызвать из JavaScript, как и событие command. Чтобы это сделать, следует вызвать метод диспетчера UpdateCommands(). В случае команд, определенных в XUL, это не слишком гибкий и полезный подход, потому что простые обработчики событий, используемые в oncommand, не имеют состояний. Только если команда реализуется JavaScript (то есть используется объект controller ), вызов события commandupdate имеет смысл.

9.4.3. Теги <commandset> и <commands>

Тег <commandset> определяется программистом и не имеет специального значения. Его используют, чтобы сгруппировать команды вместе.

Иногда приложение XUL состоит из множества отдельных файлов. В этом случае тег <commandset> зачастую имеет id, по которому его можно найти в результирующем документе, тем же способом, который описан в "Оверлеи и Chrome" , "Оверлеи и chrome".

Он используется и при обновлении команд. Это удобно, поскольку его дочерние теги обычно являются тегами <command>. Когда генерируется событие commandupdate, обработчик oncommandupdate тега <commandset> просматривает по очереди все дочерние теги и проверяет их состояние. Такая стратегия используется в chrome классической Mozilla.

Наконец, тег <commands> также является тегом, определяемым программистом и не имеющим специального значения. Он используется лишь для группирования тегов <commandset>. Этот тег тоже применяется в системе оверлеев Mozilla. В результате все теги <commandsets>, разбросанные по файлам приложения, окажутся дочерними тегами тега <commands>.

Дмитрий Гуменюк
Дмитрий Гуменюк
Россия, Звенигород
Konstantin Grishko
Konstantin Grishko
Россия, Москва, Московский финансово-промышленный университет "Синергия", Москва