• Содержание
  • Разработка приложений с помощью Mozilla / автор: Н.Макфарлейн
    10. Глава: Окна и панели

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

    Разные аспекты платформы Mozilla существенно различаются по сложности. Работа с окнами очень проста. Средства управления окнами, доступные приложениям XUL, во многом подобны средствам, используемым в традиционном web-программировании. Для тех, кому раньше приходилось использовать метод DOM window.open(), эта глава будет просто повторением пройденного. XUL (а также объектная модель HTML-документа в Mozilla) предоставляет некоторые новые возможности, но вряд ли в этой главе вы встретите что-то сенсационное. Как правило, вся работа с окнами сводится к нескольким строкам кода.

    Mozilla позволяет создавать множество различных типов самостоятельных окон, начиная с крошечных всплывающих подсказок к элементам интерфейса (tooltips, в локализациях многих программ они называются просто "подсказками") и заканчивая сложными окнами больших приложений. Кроме того, она позволяет создавать внутри окон другие, "встроенные" окна, в которых могут отображаться другие документы. В этой книге для таких окон используется термин "панели". Средства защиты web-браузера накладывают ограничения на типы встроенных окон, однако эти ограничения не действуют, если приложение установлено в каталог chrome или рассматривается как безопасное.

    Окна Mozilla могут преподнести несколько сюрпризов. Пространства имен XML позволяют сочетать различные типы содержимого. Доступны усовершенствованные средства управления существующими окнами. Пожалуй, наиболее значительным новшеством в части содержимого окон являются оверлеи. Эта тема весьма важна, ей посвящена глава 12 - "Оверлеи и chrome".

    На схеме в начале главы показаны элементы архитектуры Mozilla, имеющие отношение к управлению окнами. Как показано на схеме, это, в первую очередь, фреймы JavaScript. Документы могут нуждаться в более сложном контейнере, чем фрейм, описываемый простым тегом <box>, поэтому существует несколько типов фреймов. В связи с окнами заслуживают внимания несколько компонентов XPCOM. Но в любом случае, это несложная тема.

    10.1. Обычные окна. Тег <window>

    Прежде чем обратиться к новым тегам XUL, мы кратко рассмотрим хорошо известный тег <window>. Этот тег поддерживает следующие специальные атрибуты:

    sizemode windowtype screenX screenY width height
    

    Атрибут sizemode применим только к тегам <window> (или <dialog>), описывающим окна верхнего уровня. Он отражает состояние окна на рабочем столе и может принимать значения normal, minimized или maximized (нормальное, свернутое, развернутое на весь экран).

    Атрибут windowtype позволяет задавать группы однотипных окон. Значением этого атрибута может быть любая строка, определенная программистом. Атрибут имеет смысл, если одновременно открыто два или более окон одного и того же типа. При открытии второго и последующих окон, Mozilla пытается сместить их относительно существующих окон данного типа. Это сделано для того, чтобы пользователь не "потерял" однотипные окна из-за их полного перекрытия.

    Атрибуты screenX screenY определяют смещение окна в пикселах относительно левого верхнего угла экрана.

    Атрибуты width и height задают высоту и ширину окна в пикселах.

    Ни один из атрибутов screenX, screenY, width, height не может быть изменен после того, как окно отображено на экране.

    Диалоговое окно может быть создано при помощи тега <window>, как описано ниже в разделе о функции window.open(). Как правило, в системах семейства UNIX диалоговые окна не являются модальными, поэтому в специальной семантике диалога необходимости нет. В целом, при наличии специального тега <dialog> для диалогового окна использование тега <window> для этой цели не имеет практического смысла.

    10.2 Всплывающие окна

    Окно XUL может перекрываться другим содержимым, заданным в том же документе, ("всплывающим содержимым") при использовании следующих тегов:

    <tooltip> <menupopup> <popup> <popupgroup> <popupset>
    

    Однако не все эти теги рекомендованы к использованию, и не все они применимы в любом месте документа. Так, <menupopup> следует использовать только внутри тегов <menu> или <menulist>. Следующие атрибуты других тегов XUL, определяющих элементы интерфейса, также могут определять различные виды всплывающего содержимого для этих элементов:

    tooltiptext grippytooltiptext popup menu context contextmenu 
    contentcontextmenu
    

    Некоторые из перечисленных атрибутов также объявлены устаревшими. Тег <menupopup> рассматривается в главе 7 "Формы и меню". Прочие теги и атрибуты описываются в этой главе.

    Для создания некоторых визуальных эффектов может использоваться тег <deck>, представленный в главе 2 "Управление геометрией XUL".

    10.2.1 Задание всплывающего содержимого

    Система тегов и атрибутов, используемая для всплывающего содержимого, несет на себе отпечаток долгой истории развития Mozilla. Безусловно, лучше использовать современные теги, чем те, которые объявлены устаревшими. Однако и устаревшие теги сейчас корректно обрабатываются, и их поддержка вряд ли прекратится в версиях Mozilla 1.x.

    Существует три основных типа всплывающих окон: всплывающие подсказки, контекстные меню и обычные меню.

    При использовании большинства современных тегов содержимое, описывающее всплывающие подсказки и контекстные меню, следует помещать внутрь тега <popupset>. Это тег, который не имеет собственного визуального отображения и используется для организации других тегов, подобно тегу <keyset>. При необходимости в документе XUL может быть несколько тегов <menupopup>.

    Всплывающая подсказка определяется при помощи тега <tooltip>, а контекстные меню - посредством тега <menupopup>. Обычные меню также могут быть описаны внутри тега <popupset> при помощи <menupopup>, однако рекомендуется использовать для создания обычных меню другие средства - теги <menu> и <menulist>.

    Традиционной, но устаревшей практикой является описание контекстных меню при помощи тега <popup>. Редко встречающиеся теги <context> и <popupset> еще более архаичны. Эти и другие теги могут быть заключены в очень старый тег <popupgroup>. Этот тег может использоваться в пределах документа только один раз. Не стоит задействовать ни один из этих трех тегов, хотя <popup> все еще широко применяется при описании интерфейса Mozilla. Они объявлены устаревшими, и для них существуют современные альтернативы.

    10.2.2 Всплывающая подсказка

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

    Тег <tooltip> поддерживает следующие атрибуты:

    label crop default titletip
    

    Если <tooltip> не имеет содержимого, его текст определяется значением атрибута label. Атрибут crop определяет, каким образом подсказка может быть сокращена, если на экране недостаточно места.

    Если значение атрибута default - true, данная подсказка является всплывающей подсказкой по умолчанию для всего документа. Если атрибут titletip имеет значение true, всплывающая подсказка отображается для элемента интерфейса в том случае, если он частично скрыт. Оба эти атрибута имеют смысл только для подсказок к заголовкам столбцов тега <tree>.

    Тег <tooltip> может иметь любое содержимое - он функционирует подобно тегу <vbox>. Однако большое количество содержимого для данного тега не имеет смысла, поскольку пользователь не может пролистывать это содержимое при помощи мыши или иным способом. Размерами всплывающей подсказки можно управлять при помощи атрибутов minwidth и minheight, однако это может вызывать проблемы при размещении элементов в родительском окне, так что использовать эти атрибуты не рекомендуется.

    Чтобы связать всплывающую подсказку с каким-либо элементом интерфейса, нужно присвоить атрибуту tooltip нужного тега значение id тега <tooltip>, определяющего подсказку. Сокращенная нотация позволяет обойтись без специального тега <tooltip>, задав текст подсказки в качестве значения атрибута tooltip нужного элемента интерфейса. Еще один вариант - включить тег <tooltip> в содержимое тега, описывающего элемент интерфейса, для которого создается подсказка. В этом случае следует указать для родительского тега атрибут tooltip="child".

    Атрибут contenttooltip, который может использоваться только с тегом <tabbrowser>, определяет подсказку для содержимого этого тега.

    Кроме того, всплывающая подсказка появляется над заголовком окна, если текст заголовка не помещается в него целиком.

    Ссылка на элемент интерфейса, к которому относится всплывающая подсказка, видимая в настоящий момент, может быть получен при помощи свойства window.tooltipNode.

    10.2.3. Контекстные меню

    Контекстное меню - один из видов раскрывающихся меню. Оно выглядит так же, как и прочие меню, но появляется в ответ на "контекстный" щелчок мыши (щелчок правой кнопкой на большинстве платформ, щелчок с удержанием клавиши "Яблоко" на Macintosh). При этом меню появляется в том месте, где находится курсор мыши, а не каком-либо заранее определенном месте документа.

    Для создания контекстного меню используется тег <menupopup>, описанный в главе 7 "Формы и меню". Чтобы связать меню с элементом интерфейса, необходимо установить значение атрибута contextmenu этого тега равным значению атрибута id тега <menupopup>. Исключение составляет тег <tabbrowser> - у него следует устанавливать атрибут contentcontextmenu.

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

    Атрибуты popupanchor и popupalign применимы к контекстным меню так же, как и к обычным меню, созданным при помощи тега <menupopoup>.

    Ссылка на элемент интерфейса, к которому относится контекстное меню, видимое в настоящий момент, может быть получена при помощи свойства window.popupNode.

    10.3. Диалоговые окна

    Если в ходе работы приложения возникает необходимость вывести на экран простенький фрагмент данных, логично использовать диалоговое окно. Диалоговое окно представляет собой обычное окно XUL, имеющее весьма ограниченную область применения. Как правило, диалоговые окна не являются независимыми и существуют в контексте какого-либо другого, более значительного окна (т.е. используют его ресурсы).

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

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

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

    Однако если диалоговые окна действительно необходимы, Mozilla представляет развитые средства для работы с ними.

    10.3.1. Тег <dialog>

    Основой создания диалоговых окон является тег <dialog>. Он во многом подобен тегу <window>, однако обладает дополнительной функциональностью по сравнению с ним. По умолчанию тег <dialog> создает немодальное окно, которое не блокирует возможность работы с другими окнами приложения.

    Для знакомства с тегом <dialog> достаточно в любом документе XUL заменить тег <window> на <dialog>. Нужно иметь в виду, что тег <dialog> рассчитан на использование в chrome, и его применение в документах, запускаемых в системе Microsoft Windows из других каталогов, может привести к зависанию Mozilla. В системах семейства UNIX этой проблемы не возникает.

    На рисунке 10.1 показаны различные примеры использования тега <dialog>. При этом стандартные диагностические стили включены, а единственным содержимым документа является слово Content внутри тега <description>. Два окна в первом ряду имеют одно и то же содержимое, заключенное в тег верхнего уровня <dialog> и <window> соответственно. Как мы видим, <dialog> при отображении автоматически добавляет тег <box> для своего содержимого, а также два тега <button>. Во втором ряду показано диалоговое окно со всеми кнопками, которые предусмотрены для тега <dialog>. Для отображения кнопок использовался атрибут buttons этого тега. В примере, приведенном в последнем ряду, к диалоговому окну было добавлено дополнительное содержимое - шесть кнопок. Эти кнопки заменяют стандартные кнопки, которые в данном случае не отображаются. Обратите внимание на то, что текст у кнопок во втором и третьем ряду различается. Давайте рассмотрим, каким образом это сделано.

    Различные примеры использования тега <dialog>.

    Рис. 10.1.  Различные примеры использования тега <dialog>.

    Тег <dialog> определен при помощи XBL. Это определение предусматривает дополнительные контейнеры для содержимого и кнопки. Отображение тега также зависит от файла свойств, входящего в состав chrome. Этот файл содержит подписи для кнопок, соответствующие различным платформам. Возможность доступа к этому файлу - одна из причин, чтобы использовать диалоговые окна в chrome. Тег <dialog> поддерживает следующие атрибуты:

    buttonpack buttondir buttonalign buttonorient title buttons
    

    Значением атрибута buttons является список строк, разделенных запятыми. Также допускаются пробелы между строками. Это строка параметров, подобная используемой методом window.open(), но в данном случае ее синтаксис проще. Допустимы следующие значения строк:

    accept cancel extra1 extra2 help disclosure
    

    Нужные строки следует просто перечислить через запятую, например:

    <dialog buttons="accept,cancel,help"/>
    

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

    ondialogaccept ondialogcancel ondialogextra1 ondialogextra2 
    ondialoghelp ondialogdisclosure
    

    Атрибут title, как и в случае тега <window>, задает текст заголовка окна. Атрибуты buttonpack/dir/align/orient служат для управления контейнером <hbox> диалогового окна, предназначенным для размещения кнопок. Они аналогичны атрибутам pack/dir/align/orient обычного контейнера. Атрибут buttons указывает, следует ли отображать стандартные кнопки диалогового окна.

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

    Перечисленные атрибуты тега <dialog> позволяют создать все окна, показанные на рисунке 10.1, кроме последнего. При его создании был использован атрибут dlgtype, который обычно применяется с тегом <button>.

    Значением атрибута dlgtype может быть любой из стандартных типов кнопок:

    accept cancel extra1 extra2 help disclosure
    

    Атрибут dlgtype никак не влияет на отображение кнопки или другого элемента, с которым он используется. Фактически он служит указанием для объемлющего тега <dialog>. При отображении диалогового окна его содержимое просматривается на предмет тегов, имеющих атрибут dlgtype. Если такой тег найден, он используется вместо соответствующей стандартной кнопки диалогового окна. Это обеспечивает необходимую гибкость при создании диалогов, позволяя разработчику управлять размещением элементов. В качестве замены стандартных кнопок могут использоваться только элементы интерфейса, поддерживающие событие command. Если для такого элемента не задана метка, будет использоваться стандартная строка, заданная для диалогового окна в файле свойств.

    Окно, основанное на теге <dialog>, можно открыть тем же способом, что и любое другое окно. Чтобы создать модальное окно, используйте метод window.openDialog(), описанный ниже.

    Не следует в явном виде задавать размер диалогового окна при помощи атрибутов width и height.

    10.3.2. Тег <dialogheader>

    Хотя определение тега <dialogheader> (заголовок диалогового окна) включено в chrome, фактически он представляет собой не средство разметки, а разновидность содержимого. Он используется для создания заголовков разделов в диалоговом окне настроек Mozilla, и представляет собой обычный контейнер <box> с текстовым содержимым. Он не имеет специального значения в контексте диалогового окна.

    10.3.3. Тег <wizard>

    Тег <wizard> (мастер) представляет собой специализированный вариант тега <dialog>. <wizard>, а также тег <wizardpage>, обсуждаются в главе 17 "Развертывание приложений".

    10.3.4. Java, JavaScript и другие языки

    Диалоговые окна могут создаваться Java-апплетами. Фактически при этом используется платформа Java - виртуальная машина и стандартные библиотеки классов - которая не имеет ничего общего с платформой Mozilla. Такие диалоговые окна могут открываться за пределами прямоугольной области браузера, занимаемой встроенным апплетом, и существовать после уничтожения создавшего их окна. Они могут существовать в отдельных окнах подобно консоли Java.

    Диалоговые окна могут создаваться и из программ на JavaScript с использованием ресурсов XPCOM и АОМ/DOM. Некоторые способы сделать это рассматриваются ниже.

    Разработчики встраиваемых приложений также могут использовать такие языки как Perl или Python для управления окнами, которые создаются средствами платформы Mozilla. Такие подходы выходят за рамки этой книги.

    10.4. Создание окон средствами JavaScript

    Новые окна приложений можно создавать из программ на JavaScript.

    Напомним, что интерпретатор JavaScript предоставляет разработчику приложения глобальный объект. В контексте документа XUL этот объект имеет свойство window, которое фактически также является глобальным объектом. Этот объект поддерживает целый ряд методов, которые могут использоваться для создания окон.

    Следует отметить, что иерархия свойств JavaScript, доступная разработчику на платформе Mozilla, отличается от интерфейсов XPCOM. Хотя некоторые свойства JavaScript, например window и window.document выглядят идентичными соответствующим компонентам XPCOM, фактически они представляют собой самостоятельные конструкции, созданные для удобства разработчика.

    Это существенный момент. У разработчика может сложиться впечатление, что свойства объектной модели приложения (AOM), доступные из программ на JavaScript, в точности совпадают с определенными компонентами Mozilla, но это не всегда так. Окно, в котором отображается документ, является результатом взаимодействия различных компонентов платформы Mozilla. Поэтому лучше рассматривать окно и документ как отдельные системы, которые в некоторых отношениях близки определенным интерфейсам XPCOM, а не точные копии объектов платформы, доступные для JavaScript.

    Инспектор DOM, который с успехом применяется для изучения объектной модели отображаемого содержимого, не столь полезен для анализа объектов JavaScript, представляющих окно и документ. Эти объекты лучше сопоставить с компонентами XPCOM, описанными на языке XPIDL, чтобы увидеть разницу между ними.

    Объект window сообщает, что его тип - ChromeWindow. В модели XPCOM нет такого объекта, хотя существует интерфейс nsIDOMChromeWindow. Однако свойства и поведение объекта ChromeWindow в большей степени связаны с интерфейсами nsIJSWindow и nsIDOMWindowInternal.

    10.4.1. Окна браузера и окна chrome

    Механизмы работы JavaScript с окнами ориентированы, в первую очередь, на традиционного разработчика web-приложений. По умолчанию в качестве нового окна создается окно приложения Navigator. Это окно XUL, элементы которого образуют полноценный web-браузер. Оно содержит панели инструментов, другие элементы интерфейса, некоторые элементы объектной модели DOM 0, панель для отображения web-документа, а также средства защиты информации. Помимо окон браузера, можно создавать окна chrome (простые окна XUL).

    Окно браузера предоставляет web-разработчику ограниченный набор интерфейсов. Объекты window и window.document обеспечивают доступ лишь к содержимому, находящемуся в панели отображения документа. Web-разработчик не имеет доступа к содержимому XUL, формирующему интерфейс браузера; элементы интерфейса за пределами отображаемого документа являются для него "черным ящиком". Единственный способ повлиять на эти элементы - несколько параметров, передаваемых методу window.open(). Эти параметры позволяют скрыть некоторые элементы интерфейса у нового окна, например панели инструментов.

    С точки зрения разработчика XUL, окно браузера способно либо облегчить ему работу, либо оказаться серьезной помехой. Если разработчик занят незначительным усовершенствованием существующего браузера (например, добавляет к нему оверлеи), окно браузера предоставляет его приложению дополнительную функциональность. Однако при разработке нового приложения вся функциональность браузера может оказаться ненужным грузом. В этом случае несложные меры (например, использование ключа -chrome) позволяют начать "с чистого окна".

    10.4.2. window.open()

    Метод window.open() создает новое окно. Этот интерфейс DOM 0 широко используется при разработке web-приложений. В случае Mozilla его сигнатура такова:

    target = window.open(URL, name, features);
    

    URL - действительный URI (унифицированный идентификатор ресурса) документа, который должен быть загружен в новое окно. Чтобы открыть пустое окно, можно использовать пустую строку или "about:blank". Кодирование URL необязательно.

    name - имя нового окна. Чтобы создать безымянное окно, следует использовать в качестве этого параметра null или "_blank".

    features - разделенный запятыми список дополнительных параметров и их значений (строка параметров), определяющих вид и поведение нового окна.

    Функция возвращает ссылку на объект window созданного окна. При помощи этой ссылки можно получить доступ к элементам объектной модели созданного окна, если это не противоречит ограничениям, налагаемым системой защиты.

    Строка параметров применяется часто, однако возможные значения параметров документированы плохо, поэтому ниже приводится их полное описание.

    Каждый параметр передается в виде пары имя_параметра=значение, нечувствительной к регистру символов. Значение может быть либо булевым флагом, либо скалярным (числом). Для булева параметра достаточно привести его имя без части =значение или указать "имя_параметра= yes" для того, чтобы присвоить параметру значение "истина". Любое другое значение, присвоенное параметру, означает "ложь". В случае скалярного параметра значение интерпретируется как число, любые символы, следующие за числом, игнорируются. Пары разделяются запятыми, за которыми могут следовать дополнительные пробелы, хотя это может привести к проблемам при отображении HTML-документов в некоторых устаревших браузерах. Следующий пример иллюстрирует эти правила:

    "toolbar,location=yes,menubar=no,top=100, 
    left=100px,width=100cm"
    

    В этом примере новое окно будет иметь панель инструментов (toolbar) и панель адреса (location bar). Окно будет размещено на расстоянии 100 пикселей от верхнего и левого краев экрана и будет иметь ширину 100 пикселей (символы cm игнорируются).

    Строка параметров определяет тип нового окна - будет ли оно окном браузера (создается по умолчанию) или же окном chrome. Для создания последнего необходимо указать в строке параметров:

    chrome
    

    Следующие параметры имеют смысл только для окна браузера:

    toolbar location directories personalbar status menubar scrollbars 
    extrachrome
    

    Если указанные параметры или вся строка параметров отсутствуют, считается, что они имеют значение по умолчанию - "истина".

    Булев параметр extrachrome определяет, будет ли при создании нового окна браузера загружено и отображено содержимое, определяемое пользователем (в классическом браузере - боковая панель или Sidebar). С технической точки зрения этот флаг определяет возможность загрузки оверлеев, определяемых пользователем или разработчиком, и установленных в chrome. Прочие параметры традиционны для web-приложений.

    Следующие параметры могут применяться как к окнам браузера, так и к окнам chrome:

    resizable dependent modal dialog centerscreen top left height width 
    innerHeight innerWidth outerHeight outerWidth screenX screenY
    

    Значением по умолчанию, которое используется, если параметр или вся строка опущены, для параметров resizable и centerscreen является "истина", а для dependent и modal - "ложь". Однако, если текущее окно является модальным, по умолчанию создается модальное окно. Прочие параметры - скалярные и требуют численных значений.

    Если новое окно создано с параметром resizable (изменяемый размер), менеджер окон в системах Microsoft Windows или X11 создает стандартные активные области на рамке окна, позволяющие пользователю изменять его размер. Это поведение не зависит от наличия тегов <resizer> в данном окне.

    dependent (зависимое) создает дочернее окно - закрытие родительского окна приводит к закрытию вновь созданного. Новое окно всегда открывается поверх родительского (окна, код которого вызывает window.open()).

    При использовании параметра modal созданное окно будет модальным. Родительское окно не может получить фокус ввода до тех пор, пока модальное окно не закрыто.

    Если указан параметр dialog, новое окно будет создано с единственной кнопкой на заголовке окна - "Закрыть".

    Параметр centerscreen обеспечивает расположение нового окна в центре экрана.

    Прочие параметры - скаляры, определяющие размер и положение нового окна. Если из параметров top, left, screenX или screenY указан только один, соответствующий параметр для второго измерения считается равным нулю. Параметры, определяющие положение и размер окон браузера, игнорируются, если был использован атрибут persist, предназначенный для окон классического браузера.

    Следующие параметры имеют смысл только для окон, созданных с необходимыми привилегиями защиты, например из приложения, установленного в chrome:

    titlebar close alwaysLowered z-lock alwaysRaised minimizable
    

    Значение по умолчанию двух первых параметров - "истина", остальных - "ложь". titlebar обеспечивает добавление элементов окна, создаваемых менеджером окон - заголовка и рамки. close обеспечивает создание кнопки "Закрыть" на заголовке окна. Если указаны параметры alwaysLowered или z-lock, окно будет оставаться на заднем плане, получая фокус ввода; если указан параметр alwaysRaised, окно будет оставаться на переднем плане при потере фокуса. Параметр minimizable, по всей видимости, никак не меняет поведение окна.

    Если параметр close имеет значение "ложь", пользователь, тем не менее, может закрыть окно средствами менеджера окон. Так, в системе Microsoft Windows в меню окна, которое открывается при щелчке по значку в левой части заголовка окна, сохраняется пункт "Закрыть".

    10.4.3. window.openDialog()

    Метод window.openDialog() доступен лишь в том случае, если он вызывается из документа, который считается защищенным, например установленного в chrome. Этот метод принимает практически те же аргументы, что и window.open(), и приводит практически к тем же результатам.

    target = window.open(URL, name, features, arg1, arg2,...);
    

    arg1, arg2 и т.д. - любые аргументы, допустимые для функций на JavaScript. В новом окне они доступны как элементы массива window.arguments.

    Фактически, метод openDialog() эквивалентен методу window.open() с параметрами "chrome=yes, dialog=yes". Это поведение можно переопределить, присвоив какому-либо из этих параметров в явном виде значение "ложь". openDialog() также поддерживает параметр all. Если указать его в строке параметров, новое окно будет создано со всеми элементами, позволяющими пользователю управлять окном. В частности, на заголовке окна будут доступны кнопки "Закрыть" и "Свернуть".

    10.4.4. window.content, id="content" и метод loadURI()

    В окне классического браузера тегом XUL c id="content" является тег <tabbrowser>, соответствующий панели для отображения web-документа. Этот тег недоступен для web-разработчика, однако весьма полезен для разработчика приложений на основе браузера. Он предоставляет обширную функциональность, которая может быть использована в программах, и заслуживает внимательного изучения при помощи Инспектора DOM.

    Если окно является обычным окном браузера на основе XUL, указанный объект <tabbrowser> доступен как свойство content объекта window. Объект, доступный таким образом, не только реализует интерфейс nsIWebNavigation, но и имеет свойство document, указывающее на документ HTML (или XML), который отображается в текущей вкладке браузера.

    Интерфейс nsIWebNavigation содержит все методы, необходимые для управления web-документами, отображаемыми в данной панели - их загрузки, перезагрузки и перемещения между ними. Объект AOM <tabbrowser> имеет свойство webNavigation, обеспечивающее доступ к этому интерфейсу. Наиболее полезным методом является loadURI(), который во многом сходен с объектом XmlHttpRequest, речь о котором шла в главе 7 "Формы и меню". Основное различие между ними состоит в том, что XmlHttpRequest просто возвращает ответ на HTTP-запрос в виде данных, в то время как loadURI() отображает полученный документ в окне. Одновременно метод задействует другие функции классического браузера, например, добавляет полученный документ к истории посещений. Сигнатура метода loadURI() такова:

    void loadURI(uri, flags, referrer, postData, headers)
    

    uri - URI ресурса, который должен быть отображен.

    flags (по умолчанию null) - набор однобитовых флагов, определяющих поведение при загрузке документа. Отдельные флаги доступны как свойства объекта webNavigation, имеющие префиксы LOAD_FLAGS, и имеют различную семантику - не использовать копию документа из кэша, перезагрузить страницу и т.п.

    referrer (по умолчанию null) - URI ссылающегося документа для включения в HTTP-запрос. С помощью этого аргумента можно изменить значение, передаваемое платформой Mozilla.

    postData (по умолчанию null) - строка данных POST, передаваемая в составе HTTP-запроса.

    headers (по умолчанию null) - строка дополнительных заголовков HTTP-запроса.

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

    var str, C, obj, iface, arg;
    str = "put data here";
    C = Components;
    obj = C.classes["@mozilla.org/io/string-input-stream;1"];
    iface = C.interfaces.nsIStringInputStream;
    arg = obj.createInstance(iface);
    arg.setData(str, str.length);
    loadURI("page.cgi", null, null, arg, null);
    
    Листинг 10.1. Создание объекта с интерфейсом nsIInputStream на основе строки

    10.4.5. Методы alert(), confirm() и prompt()

    Эти три метода объекта window позволяют создавать простейшие диалоговые окна для взаимодействия с пользователем. Метод alert() создает окно с сообщением и единственной кнопкой. Метод confirm() позволяет пользователю сделать выбор, нажав одну из кнопок, а метод prompt() служит для получения от пользователя данных. Кроме того, метод alert() является простейшим способом создать точку прерывания в вашем коде на JavaScript - выполнение приостанавливается до того момента, когда окно будет закрыто.

    Механизм создания этих окон был переработан в процессе создания Mozilla. В Netscape 4.x и более ранних версиях этого браузера, а также в Internet Explorer эти окна могут содержать текст, возвращаемый функцией printf() в стиле языка C. В них не поддерживаются символы Unicode. В Mozilla эти окна являются полноценными окнами XUL, как видно на рисунке 10.2.

    Пунктирными контурами на рисунке показаны элементы, соответствующие тегам <description>. Чтобы изучить структуру окон, нужно добавить отладочные стили к файлу userChrome.css в каталоге профиля пользователя, а затем перезапустить платформу. Окно на рисунке было получено при помощи следующей строки кода:

    alert("Line 1\nLine2");
    

    Структура XUL диалогового окна alert().

    Рис. 10.2.  Структура XUL диалогового окна alert().

    Mozilla разбивает строку, переданную методам alert(), confirm() и prompt(), согласно символам конца строки. Каждая подстрока помещается внутрь отдельного тега <description> где, в свою очередь, может отображаться в несколько строк. Максимальная ширина тега <description> (свойство maxwidth) - 45 em. Верхний, пустой тег <description> с id="info.header" может использоваться разработчиком.

    Эти диалоговые окна определены в chrome, в файлах, имена которых начинаются с commonDialog внутри архива toolkit.jar. Для всех трех окон используется один и тот же документ XUL.

    10.4.6. nsIPromptService

    Методы alert(), confirm() и prompt() используют для создания диалоговых окон следующие компонент и интерфейс XPCOM:

    @mozilla.org/embedcomp/prompt-service;1 nsIPromptService
    

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

    Интерфейс nsIPromptService содержит обширную документацию по аргументам каждого из этих методов. Создавая приложение для установки в chrome, используйте эти методы. Простые методы, например alert(), предназначены для скриптов внутри HTML-документов.

    Таблица 10.1. Методы интерфейса nsIPromptService

    Имя методаДиалоговое окно
    alert()Обычное окно alert().
    alertCheck()Обычное окно alert(), но с дополнительной строкой, содержащей флажок и текст
    confirm()Обычное окно confirm()
    confirmCheck()Обычное окно confirm(), но с дополнительной строкой, содержащей флажок и текст
    confirmEx()Полностью настраиваемое диалоговое окно, содержащее до трех кнопок со стандартными метками или метками, определенными пользователем. Дополнительно может содержать флажок и текст
    prompt()Обычное окно prompt()
    promptUsernameAndPassword()Диалоговое окно с полями ввода для имени пользователя и пароля. Дополнительно может содержать флажок и текст
    promptPassword()Диалоговое окно с полем ввода для пароля. Дополнительно может содержать флажок и текст
    select()Диалоговое окно со списком, из которого может быть выбран один элемент. Каждый элемент списка представляет собой простой текст

    10.4.7. Специализированные диалоговые окна XPCOM

    В Mozilla определены несколько специализированных диалоговых окон, которые описаны в архиве toolkit.jar в составе chrome. Определены следующие окна: окно выбора файла; окно параметров печати; окно поиска на странице; индикатор загрузки файла.

    Каждое из этих окон имеет соответствующий компонент XPCOM и должно управляться при помощи интерфейсов XPCOM, а не посредством URL документов chrome.

    Ниже кратко рассмотрены два из них.

    10.4.7.1. FilePicker (окно выбора файла).

    FilePicker представляет собой пару из компонента и интерфейса XPCOM, а также набор диалоговых окон. В некоторых случаях эти окна основаны на XUL, но могут использоваться и стандартные окна выбора файла, предоставляемые операционной системой. В последнем случае это окно не может быть исследовано при помощи Инспектора DOM.

    Для создания окна используется следующая пара XPCOM:

    @mozilla.org/filepicker;1 nsIFilePicker
    

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

    1. Создать объект FilePicker с помощью XPCOM.
    2. Инициализировать его при помощи метода init().
    3. Добавить фильтры для файлов и указать, какой из них выбран по умолчанию.
    4. Установить другие необходимые значения по умолчанию.
    5. Вызвать метод show(). При этом будет создано модальное окно; выполнение метода завершится после того, как пользователь закроет его.
    6. Извлечь значение, выбранное пользователем, из объекта FilePicker.

    Последний этап является не вполне тривиальным, поскольку информация о выбранном файле не может быть передана в виде простой строки, содержащей путь. Это связано с тем, что в некоторых операционных системах, чтобы однозначно идентифицировать файл, следует указать не только путь, но и устройство. Специализированные объекты и интерфейсы платформы для работы с файлами описаны в главе 16 "Объекты XPCOM". Рекомендуется ознакомиться с ними, прежде чем приступать к использованию объекта FilePicker.

    В листинге 10.2 приведен пример получения от пользователя имени файла для вывода данных при помощи объекта FilePicker.

    var Cc = Components.classes;
    var Ci = Components.interfaces;
    var fp;
    fp = Cc["@mozilla.org/filepicker;1"];
    fp = fp.createInstance(Ci.nsIFilePicker);
    fp.init(window, "Example File Save Dialog", fp.modeSave);
    fp.show();
    // fp.file содержит объект nsILocalFile, указывающий на выбранный файл
    
    Листинг 10.2. Получение объекта nsiLocalFile при помощи диалогового окна выбора файла.
    10.4.7.2. PrintingPrompt.

    Платформа Mozilla предоставляет ряд объектов для взаимодействия с системой печати, а также несколько диалоговых окон на основе XUL для задания параметров печати. Примерно с версии 1.3 Mozilla позволяет распечатывать документы XUL, отображаемые в окне браузера, подобно обычным HTML-документам.

    Система печати Mozilla довольно сложна, и ее обсуждение выходит за рамки данной книги. В качестве отправных точек для самостоятельного изучения системы печати можно порекомендовать интерфейсы XPCOM nsIPrintingPromptService и nsIWebBrowserPrint.

    10.5. Панели для отображения документов

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

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

    10.5.1 <iframe>

    Тег <iframe> лежит в основе механизма включения одних документов в другие на платформе Mozilla. Он во многом подобен тегу HTML <iframe>, однако менее гибок. Между открывающим и закрывающим тегами <iframe> не может находиться никакого содержимого. Элементом интерфейса, соответствующим тегу <iframe>, является фрейм, в который может быть загружен независимый документ. При этом фокус ввода может быть передан содержимому этого фрейма. Размеры последнего можно задавать и изменять так же, как и для любого элемента-контейнера:

    <iframe minwidth="100px" flex="1" src="about:blank"/>
    

    Специфичным для <iframe> является только атрибут src, который задает URL документа для отображения в <iframe>. Также полезно указать значение атрибута name, чтобы документ, загруженный во фрейм, мог обращаться к нему.

    В главе 8 "Навигация" было отмечено, что тег <scrollbox> является особой разновидностью контейнера, которой соответствует отдельный интерфейс XPCOM. То же самое справедливо и для тега <iframe>. Это единственная реализация компонента, называемого

    @mozilla.org/layout/xul-boxobject-iframe;1
    

    Объект AOM, соответствующий тегу <iframe>, имеет свойство boxObject, как и все остальные объекты - контейнеры XUL. Как и в случае с тегом <scrollbox>, при помощи метода boxObject.QueryInterface() можно получить специализированный интерфейс, который для тега <iframe> называется nsIIFrameBoxObject. Хотя этот тег имеет единственное свойство, docShell, оно, в свою очередь, обеспечивает доступ к интерфейсу nsIDocShell, который обладает богатой функциональностью.

    DocShell означает "Document Shell", [командная] оболочка документа. DocShell является оболочкой для работы с документами подобно тому, как ksh, bash или командная строка DOS являются оболочками для доступа к командам операционной системы.

    Многочисленные свойства и методы интерфейса nsIDocShell обеспечивают доступ к основным операциям, необходимым для загрузки документа и управления его отображением. Кроме того, этот документ предоставляет доступ к другим интерфейсам, также полезным для управления документами. В некотором смысле интерфейс nsIDocShell похож на водительское кресло автомобиля - большинство средств управления находятся в непосредственной досягаемости. Этот интерфейс хорошо документирован и заслуживает хотя бы беглого ознакомления. Информация о нем содержится в загружаемых файлах, упомянутых во "Введении".

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

    Содержимое фрейма, заданного тегом <iframe>, должно иметь статус отдельного документа XML, в отличие от большинства тегов- контейнеров, содержимое которых определяется их потомками в исходном документе XUL. <iframe> является важнейшим тегом, лежащим в основе браузера Mozilla - именно с его помощью реализована панель, в которой отображаются загружаемые документы.

    Таким образом, тег <scrollbox> дополняет обычный контейнер возможностью прокрутки содержимого (часть документа XML) в отображаемой области. Дополнительные возможности тега <iframe> гораздо шире - он предоставляет различные способы управления содержимым (отдельным документом XML) и его отображением. В обоих случаях сама отображаемая область представляет собой простой прямоугольник без какого-либо дополнительного оформления.

    XBL-определение тега <iframe> содержится в файле general.xml архива toolkit.jar в chrome. Это определение задает следующие свойства для удобного доступа к часто используемым возможностям интерфейса nsIDocShell:

    docShell contentWindow webNavigation contentDocument
    

    docShell является отправной точкой для управления содержимым фрейма. Еще три свойства являются эквивалентами свойств JavaScript window, window.webNavigation и widow.document соответственно для содержимого фрейма.

    Свойство commandDispatcher, которое есть у любого документа XUL, имеет метод advanceFocusIntoSubtree(), с помощью которого можно передать фокус ввода содержимому тега <iframe>, если оно способно получить фокус.

    Если документ, содержащийся во фрейме, шире или выше, чем область отображения фрейма, будут показаны полосы прокрутки. У всякого документа XUL, отображаемого в <iframe>, корневым тегом должен быть <page>. Теги <iframe> могут быть вложенными, при условии, что каждый из них содержит самостоятельный XML-документ.

    10.5.2. Тег <page>

    Тег <page> (страница) следует использовать вместо тега <window> в том случае, когда документ XUL предназначен для отображения внутри <iframe>. Тег <page> не имеет специализированных атрибутов.

    Хотя документ с тегом <page> может отображаться в виде отдельного окна, такая практика не рекомендуется. Этот тег предназначен для документов, отображаемых во фреймах.

    10.5.3. Тег <editor>

    Тег <editor>, подобно тегу <iframe>, представляет собой специализированный контейнер для отображения отдельного документа. Единственным специализированным атрибутом этого тега является src, который указывает на URL отображаемого документа. Некоторые версии Mozilla поддерживают также атрибут editortype, который может принимать значения "html" или "txt". Кроме того, существует атрибут type, который может принимать значения "content" или "content-primary". В последнем случае свойство window.content указывает на свойство contentWindow тега <editor>. Этому тегу соответствует следующая пара XPCOM:

    @mozilla.org/layout/xul-boxobject-editor;1 nsIEditorBoxObject
    

    Интерфейс nsIEditorBoxObject поддерживает всю ту же функциональность docShell, что и тег <iframe>, а также богатую функциональность интерфейса nsIEditor, доступную через свойство editor. Интерфейс nsIEditor предоставляет все возможности, необходимые для реализации визуального редактирования HTML-документов - выделение текста, копирование и т.д. Тег <editor> лежит в основе классического Компоновщика подобно тому, как тег <iframe> лежит в основе браузера.

    Тег <editor> не предоставляет дополнительных элементов управления для редактирования документа.

    10.5.4. Тег <browser>

    <browser> - еще один специализированный тег, который, подобно тегу <iframe>, предназначен для отображения независимых документов и имеет атрибут src. <browser> является тегом-контейнером, ему соответствует следующий компонент XPCOM:

    @mozilla.org/layout/xul-boxobject-browser;1
    

    Этот компонент реализует интерфейс nsIBrowserBoxObject, во многом сходный с интерфейсом nsIIFrameBoxObject. Вообще, теги <browser> и <iframe> имеют много общего.

    Тем не менее, тег <browser> имеет отдельное XBL-определение, которое содержится в файле browser.xml архива toolkit.jar в chrome. Это определение содержит множество полезных свойств и методов. Те типичные задачи, которые при использовании тега <iframe> решаются путем нескольких обращений к различным интерфейсам, свойствам и методам, в случае <browser> часто требуют вызова единственного метода. В XBL-определении метода <browser> также предусмотрены поддержка истории просмотра документов, средств защиты и перетаскивания при помощи мыши.

    Кроме того, <browser> поддерживает режим каретки (текстового курсора), который активизируется нажатием клавиши F7. В этом режиме, как в текстовом редакторе, пользователь может перемещать по HTML- странице курсор.

    Тег <iframe> лучше использовать в тех случаях, когда нужно загрузить во фрейм единственный документ, который затем не будет изменяться. <browesr> более удобен, если предполагается последовательно загружать во фрейм разные документы или необходимо обеспечить базовые функции навигации.

    10.5.5 <tabbrowser>

    Подобно тому, как <browser> является переработанным вариантом тега <iframe>, тег <tabbrowser> (браузер с вкладками) представляет собой усовершенствованный <browser>. В отличие от двух других тегов, <tabbrowser> не имеет соответствующего компонента XPCOM. Фактически, он представляет собой одно большое XBL- определение в файле tabbrowser.xml архива toolkit.jar в chrome.

    <tabbrowser> является комбинацией тегов <tabbox> и <browser>. Каждая вкладка тега <tabbox> содержит отдельный <browser>, причем вкладки можно динамически добавлять и удалять. Именно <tabbrowser> лежит в основе области отображения web-документов в окне классического браузера.

    Тег <tabbrowser> имеет следующие специализированные свойства:

    onnewtab contenttooltip contentcontextmenu
    

    Свойство onnewtab - обработчик событий, который запускается, когда пользователь создает новую вкладку при помощи меню или специальной кнопки. Значения двух других атрибутов передаются тегам <browser>, находящимся на вкладках в качестве атрибутов tooltip и contextmenu соответственно.

    Хотя с помощью многочисленных методов можно автоматизировать работу с тегом <tabbrowser>, как правило, в этом нет практического смысла. Этот тег предназначен для пользователя, просматривающего несколько web-документов. Максимум того, что обычно бывает нужно разработчику - получить информацию о текущем состоянии системы вкладок.

    10.5.6 Теги <IFRAME> и <FRAME>

    Эти теги HTML или XHTML используются при создании web-страниц для помещения документов во фреймы. Внутри такого фрейма может отображаться и документ XUL.

    10.5.7 Игнорируемые теги и атрибуты

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

    По умолчанию в документе XUL игнорируется тег <html>. Он обрабатывается так же, как любой тег, определенный пользователем. Некоторую пользу из этого тега можно извлечь, применяя пространства имен XML, как описано ниже в разделе "Составные документы".

    Тег <window>, являющийся потомком другого тега XUL, также игнорируется. Теги верхнего уровня - <window>, <dialog>, <page> - не могут быть вложенными, за исключением того случая, когда они относятся к отдельным документам, отображаемым во фреймах <iframe>.

    Атрибут chromehidden тега <window> не имеет практического значения для разработчика приложений. Он устанавливается из метода window.open() и используется внутренним механизмом работы с панелями инструментов в классическом браузере. Атрибут windowtype, которому может быть присвоено строковое значение, используется для управления окнами (см. раздел "Управление существующими окнами"). Он не влияет на отображение окна.

    Тег <package>, который иногда упоминается в устаревшей документации, в настоящее время не используется.

    10.6. Составные документы

    Можно объединять несколько различных документов в один, не изолируя их друг от друга при помощи тега <iframe>.

    10.6.1 Различные типы документов XML в одном документе

    Очень мощная, хотя и сложная в использовании особенность Mozilla - способность отображать документ, теги которого относятся к различным стандартам (типам документов XML). Это означает, что один документ может объединять, например, содержимое HTML, SVG, MathML и XUL. Для этого достаточно добавить к документу соответствующие пространства имен XML, после чего можно использовать любые теги, относящиеся к ним. Однако следует иметь в виду, что Mozilla обрабатывает лишь то содержимое XUL, которое находится в файлах с расширением .xul или в документах, имеющих правильный тип MIME для XUL. Этот вопрос обсуждался в главе 7 "Формы и меню", где шла речь об использовании в одном документе форм XUL и HTML.

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

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

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

    Поверхностное смешивание, как правило, не создает проблем с отображением документов. При глубоком смешивании проблемы возникают довольно часто. Наименее рискованным является глубокое смешивание HTML и MathML. Смешивание XUL с HTML или MathML требует осторожности, а глубокое смешивание SVG с другим типом содержимого просто не работает, поскольку для отображения документа SVG необходима выделенная область экрана.

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

    • Для различных типов содержимого предусмотрены различные модели размещения тегов. Точный набор правил для размещения смешанного содержимого установить очень трудно. Вы можете потратить много времени на работу со стилями, пытаясь добиться нужного результата.
    • Обработка смешанного содержимого не подвергается тщательному тестированию, в отличие от соответствия каждому из отдельных стандартов. Количество тестов, необходимых для проверки совместимости хотя бы двух стандартов, огромно. Смешивание содержимого возможно благодаря продуманной архитектуре платформы. Однако, создавая сложные ситуации, вы рискуете столкнуться с эффектами, которые никто не предусмотрел и не протестировал.
    • Различные типы отображаемых документов имеют различные корневые элементы. Это означает, что для отображения документов различных стандартов используются различные объекты C/C++, реализующие интерфейсы модели DOM 1. Поэтому отображение одного и того же тега зависит от типа документа, в котором он встречается. Для документа HTML с фрагментами XUL и документа XUL с фрагментами HTML механизмы отображения различны. Если документ активно использует скрипты (XUL или DHTML), различия в программных интерфейсах могут оказаться существенными.

    Иногда возникает соблазн просто добавить к документу XUL тег HTML <A HREF=>, чтобы создать в окне справки ссылку на сайт разработчика. Вы можете добавить к документу тег HTML <FORM> и автоматически отправлять данные формы из XUL. Однако и в том, и в другом случае можно обойтись без всякого HTML. Необходимо следить за "чистотой" своего XUL.

    Более поздние стандарты DOM предусматривают такие методы, как, например, createElementNS() и getAttributeNS(). NS в их именах означает namespace (пространство имен). Эти методы позволяют при работе с тегами и атрибутами XML указывать для них конкретное пространство имен.

    10.6.2 Составные документы XUL

    Тег <overlay> подобен усложненной версии директивы #include языков C/C++. Он позволяет объединить несколько документов XUL в один, используя атрибут id. Эта технология описана в главе 12 "Оверлеи и chrome".

    10.7 Управление существующими окнами

    В процессе работы приложения может возникнуть необходимость обратиться к ранее созданным окнам. Например, команда File | Inspect a Window в меню Инспектора DOM выбирает окно для анализа и получает информацию о его объектной модели. Еще более простой пример - перечень открытых окон в нижней части меню Mozilla "Окно". Выбор одного из этих пунктов передает фокус соответствующему окну.

    Попытка жонглировать множеством независимых окон может привести к неудачной архитектуре приложения. В большинстве случаев пользователь может закрыть любое окно в любой момент. При этом удаляется вся информация о состоянии приложения, связанная с эти окном (возможно, за исключением апплетов Java и разделяемых объектов XPCOM). Довольно сложно сохранить разумную архитектуру приложения в ситуации, когда информация о его состоянии может произвольно исчезать. В идеале приложение должно иметь главное окно, от которого должны зависеть все остальные окна. Этого можно добиться, используя параметры dependent и modal в строке параметров метода window.open(). Возможно, однако, что приложение должно следовать метафоре рабочего стола, когда независимые документы находятся в независимых окнах. В этом случае либо все окна должны быть полностью независимы друг от друга без возможности взаимодействия, либо приложение должно иметь возможность установить, какие окна открыты в настоящий момент.

    Mozilla предоставляет несколько компонентов и интерфейсов для управления окнами. Простейшей парой является следующая:

    @mozilla.org/appshell/window-mediator;1 и nsIWindowMediator
    

    Этот интерфейс позволяет получить список окон, открытых в данный момент. К моменту выхода версии Mozilla 1.2.1 он не был окончательно зафиксирован (frozen), и существовала возможность того, что в будущем он несколько изменится. Различные методы этого интерфейса позволяют получить список окон в разных формах. На листинге 10.3 показано, как получить статический список окон, открытых в настоящий момент.

    var C, obj, iface, mediator, enum, windows;
    C = Components;
    obj = C.classes["@mozilla.org/appshell/window-mediator"];
    iface = C.interfaces.nsIWindowMediator;
    mediator = obj.createInstance(iface);
    enum = mediator.getEnumerator(null);
    windows = [];
    // получить список окон, используя полученный 
     объект-перечислитель (интерфейс nsISimpleEnumerator)
    while ( enum.hasMoreElements() )
       windows.push(enum.getNext());
    // сделать что-либо с первым окном
    windows[0].document.GetElementById ...
    
    Листинг 10.3. Получение списка открытых окон при помощи nsIWindowMediator.

    Чтобы отфильтровать получаемый список окон, методу getEnumerator() можно передать строку в качестве аргумента. При этом в возвращаемый список войдут только окна с корневым тегом <html>, <window>, <dialog> или <wizard>, чей атрибут windowtype совпадает с этой строкой.

    Чтобы включить в список только окна XUL, вместо метода getEnumerator() следует использовать getXULWindowEnumerator(). Обсуждаемый интерфейс также позволяет получить порядок расположения окон (очередность перекрытия). Минимизированные окна будут перечислены как находящиеся в самом низу.

    В ходе работы приложения окна могут постоянно открываться и закрываться, и может возникнуть необходимость динамически отслеживать этот процесс (как это делается для поддержания списка открытых окон в меню "Окно"). Один из способов сделать это - создать объект- приемник (listener) для соответствующих событий. Данному объекту, реализующему интерфейс nsIWindowMediatorListener, сообщается об открытии и закрытии окон, а также об изменении заголовка окна. Более сложное решение, требующее некоторого кодирования - использовать источник данных rdf:window-mediator непосредственно из XUL. Работа с RDF и источниками данных описана в главе 11 "RDF".

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

    Платформа Mozilla добавляет к системе стилей CSS2 ряд расширений, относящихся к окнам, которые создаются средствами XUL и HTML.

    В частности, внешний вид подсказки, определяемой тегом <tooltip>, как и в случае с <menupopup>, о котором шла речь в главе 7 "Формы и меню", определяется значением -moz-popup свойства display.

    Свойство -moz-appearance, которое используется для поддержки тем операционной системы (рабочей среды), может также принимать следующие значения:

    window dialog tooltip caret
    

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

    Кроме того, Mozilla поддерживает имена шрифтов и цветов, установленные спецификацией CSS2 (раздел 18.2).

    Продуманное использование этих расширений может сделать приложение XUL неотличимым от приложений, традиционных для данной среды, например написанных для Windows при помощи Visual Basic или для UNIX - на основе библиотеки GTK.

    Дополнительные значения для системных цветов, поддерживаемые Mozilla, перечислены в таблице 10.2. Актуальный список таких расширений для текущей версии можно найти в файле nsCSSProps.cpp исходного кода.

    Таблица 10.2. Расширения стилей CSS2: системные цвета

    Имя системного цветаСоответствующий элементДополнительные имена цветов для Macintosh
    -moz-fieldФон поля ввода-moz-mac-focusring -moz-mac-menuselect -moz-mac-menushadow -moz-mac-menutextselect -moz-mac-accentlightesthighlight -moz-mac-accentregularhighlight -moz-mac-accentface -moz-mac-accentlightshadow -moz-mac-accentregularshadow -moz-mac-accentdarkshadow -moz-mac-accentdarkestshadow
    -moz-fieldtextТекст в поле ввода
    -moz-dialogФон диалогового окна
    -moz-dialogtextТекст в диалоговом окне
    -moz-dragtargetzoneЦвет, которым выделяется элемент при перетаскивании над ним объекта при помощи мыши
    -moz-hyperlinktextТекст ссылки, например, на Active Desktop в Windows
    -moz-visitedhyperlinktextТекст посещенной ссылки

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

    Таблица 10.3. Расширения стилей CSS2: имена шрифтов

    Имя системного шрифта
    -moz-window
    -moz-document
    -moz-workspace
    -moz-desktop
    -moz-info
    -moz-dialog
    -moz-button
    -moz-pull-down-menu
    -moz-list
    -moz-field

    Исключением является значение -moz-fixed, которому соответствует моноширинный шрифт. Этот шрифт действительно отображается, причем для любого заданного размера и, следовательно, для любых значений свойства CSS font-size.

    10.9. Практика: диалоговые окна NoteTaker

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

    1. Заменить корневой тег <window> на <dialog> для диалогового окна Edit.
    2. Заменить обработчики событий, связанные с тегами <button>, на обработчики, связанные с <dialog>.
    3. Реализовать в главном окне команду notetaker-open-dialog для создания диалогового окна Edit при помощи метода window.openDialog().
    4. Реализовать команду notetaker-close-dialog.
    5. Выработать и реализовать стратегию обращения с данными, которые используются более чем одним окном.
    6. Решить, окном какого типа должна быть заметка NoteTaker.

    Прежде всего, обратимся к окну Edit. Заменить тег <window> на <dialog> несложно. Новый корневой тег точно так же позволяет указать текст для заголовка окна:

    <dialog xmlns="http://www.mozilla.org/keymaster/
     gatekeeper/there.is.only.xul"
       id="notetaker.dialog"
      title="Edit NoteTaker Note"
      onload="execute('notetaker-load')">
    

    Нам больше не нужно вручную создавать кнопки для окна, поскольку для <dialog> они создаются автоматически. Однако в то же время мы кое-что теряем - мы не можем просто использовать тег <command> для <dialog>, поскольку с каждым тегом можно связать лишь одну команду. При желании можно было бы отключить автоматическое создание кнопок и сохранить старые теги <button> с <command> для каждого из них. Однако логично использовать собственные кнопки диалогового окна, имеющие стандартный вид на каждой из платформ. Вместо команд мы можем добавить следующие обработчики событий:

    ondialogaccept="execute('notetaker-save');
     execute('notetaker-close-dialog');"
    ondialogcancel="execute('notetaker-close-dialog');"
    

    Поскольку диалоговое окно автоматически закрывается при нажатии кнопки Cancel или кнопки "Закрыть" на заголовке окна, в этих случаях мы можем обойтись без вызова команды notetaker-close-dialog. В дальнейшем при необходимости мы сможем добавить обработчик onclose, а пока нам необходим только ondialogaccept.

    Таким образом, нам осталось реализовать команды -open- и -close-. Пока у нас нет полностью интегрированной панели инструментов, но мы можем использовать фрагмент XUL для тестирования команд. Функция action() панели инструментов нуждается в очень простом улучшении:

    if ( task == "notetaker-open-dialog" )
    {
      window.openDialog("editDialog.xul","_blank","modal=yes");
    }
    

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

    Столь же простое усовершенствование требуется и для функции action() диалогового окна Edit:

    if (task == "notetaker-close-dialog")
      window.close();
    

    Наконец, мы должны позаботиться об управлении данными. NoteTaker позволяет создавать не более одной заметки для каждого URL и в каждый момент работать только над одной заметкой. Однако само наше приложение уже содержит два окна. Как панель инструментов, так и диалоговое окно содержат поля, в которые пользователь может вводить данные. Какое из окон должно хранить состояние текущей заметки?

    Ответ зависит от того, каким образом хранится это состояние. В последующих главах мы познакомимся с хранением данных в формате RDF. Этот механизм не привязан к конкретному окну. В этой главе мы будем хранить данные при помощи простого объекта JavaScript. Такой объект существует в контексте определенного окна. Мы будем использовать для хранения состояния заметки окно браузера (частью которого является панель инструментов), поскольку в этом окне отображается web-страница, к которой относится заметка.

    var note = {
      url : null;
      summary : "",
      details : "",
      chop_query : true, home_page : false,
      width : 100, height : 90, top : 80, left : 70
    }
    

    Для доступа к этому объекту из диалогового окна Edit используется следующий простой синтаксис:

    window.opener.note
    

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

    При использовании свойства opener следует быть осторожным. Хотя с его помощью мы получаем доступ к другому окну, код JavaScript продолжает выполняться в контексте текущего окна, которому принадлежит исходный скрипт. Такие вспомогательные функции, как setTimeout(), setAttribute() и другие всегда применяются к текущему окну даже в том случае, когда их вызывает функция, определенная в другом окне. Листинг 10.4 демонстрирует логику функции action(), определенной в диалоговом окне.

    if (task == "notetaker-save")
    {
      var field, widget, note = window.opener.note;
      for (field in note)
      {
        widget = document.getElementById("dialog." + field.replace(/_/,"-");
        if (!widget) continue;
        if (widget.tagName == "checkbox")
          note[field] = widget.checked;
        else
          note[field] = widget.value;
      }
    }
    if (task == "notetaker-load" )
    {
      var field, widget, note = window.opener.note;
      for (field in note)
      {
        widget = document.getElementById("dialog." + field.replace(/_/,"-");
        if (!widget) continue;
        if (widget.tagName == "checkbox")
          widget.checked = note[field];
        else
          widget.value = note[field];
      }
    }
    
    Листинг 10.4. Сохранение данных диалогового окна в главном окне и загрузка данных в диалоговое окно.

    Первая и вторая половины этого листинга выполняют противоположные действия. Оператор continue позволяет игнорировать те свойства объекта note, которые неизвестны диалоговому окну. Более тщательно подбирая имена свойств, мы могли бы избежать необходимости замены символов (с учетом того, что символ "-" является недопустимым в именах свойств JavaScript), но в данном случае это несущественно. Теперь объект note основного окна является "официальным" представлением заметки, а диалоговое окно способно "загружать" данные из этого объекта и "сохранять" их в нем. В дальнейшем нам понадобится расширить логику приложения для того, чтобы сохранять эти данные во "внешнем мире".

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

    Такая заметка могла бы быть реализована с помощью XUL, XBL и JavaScript. Как известно, web-страница в браузере отображается внутри тега <iframe>, который является содержимым тега <tabbox>, а тот, в свою очередь, является содержимым тега <tabbrowser>. Если бы <iframe> был "завернут" в тег <stack>, мы могли бы расположить нашу заметку в этом стеке поверх web-страницы. Мы могли бы задать размер и положение заметки при помощи относительного позиционирования CSS, и web-страница была бы видна всюду за исключением того места, где она перекрыта заметкой. Заметка могла бы быть любым простым тегом XUL, например тегом <box> с рамкой, фоном и содержимым. Представьте себе записку, приклеенную к окну, - вы можете видеть сад за окном, хотя часть стекла закрыта запиской.

    Однако эта стратегия потребовала бы от нас изменить XBL-определение тега <tabbox>. Технически это возможно, однако переопределение одного из стандартных тегов XUL - серьезный шаг, который требует значительного тестирования. Фактически, нам пришлось бы проверить корректность работы нового тега со всеми приложениями, выполняемыми на платформе Mozilla, включая сам браузер, - слишком много труда для нашего несложного приложения.

    Поэтому мы используем другую стратегию - создание заметки средствами HTML и CSS. Из приложения, установленного в chrome, мы можем получить доступ к объектной модели отображаемой web-страницы. Средствами DHTML мы можем добавить к странице тег <span> с необходимым содержимым. При помощи стилей может быть задано абсолютное позиционирование тега, а также большое значение свойства z-index, которое обеспечит отображение заметки поверх страницы. Существует незначительная вероятность -около одной миллиардной, - что заметка окажется перекрыта частью страницы, однако для наших целей этой величиной можно пренебречь. Данная стратегия хороша тем, что она не затрагивает остального chrome, и мы будем использовать именно ее.

    Внешний вид заметки NoteTaker показан на Рисунке 10.3. В браузер загружена обыкновенная web-страница.

    Следует с осторожностью подходить к выбору используемых возможностей HTML, поскольку мы не знаем, какому именно стандарту будет соответствовать отображаемая страница. В частности, это означает, что код HTML и XML должен быть действительным с формальной точки зрения, поскольку страница может отображаться в режиме строгого соответствия стандартам. В то же время, мы можем использовать любые расширения HTML, характерные для Mozilla, поскольку наше приложение предназначено для данной платформы. Эта ситуация отличается от традиционного подхода к разработке web-страниц, рассчитанных на отображение в различных браузерах. Код HTML для заметки, показанной на рисунке, представлен в листинге 10.5.

    Пример заметки NoteTaker, реализованной на основе HTML.

    Рис. 10.3.  Пример заметки NoteTaker, реализованной на основе HTML.

    <span id="notetaker-note">
      <span id="notetaker-note-summary">
        Note Summary
      </span>
      <span id="notetaker-note-details">
        All the details go here
      </span>
    </span>
    
    Листинг 10.5. Код HTML для заметки NoteTaker

    Строго говоря, нам следовало бы выполнить некоторые дополнительные действия для того, чтобы этот код, добавленный к web-документу, всегда относился к правильному пространству имен. Однако сейчас мы не будем вдаваться в подробности. Стили CSS для этого кода приведены в листинге 10.6.

    #notetaker-note {
      display : block;
      position : absolute;
      z-index : 2147483646; /* на один уровень ниже, чем всплывающие меню */
      overflow : auto;
      background-color : lightyellow;
      border : solid;
      border-color : yellow;
      width : 100px;
      height : 90px;
      top : 80px;
      left : 70px;
    }
    #notetaker-note-summary {
      display : block;
      font-weight: bold;
    }
    #notetaker-note-details {
      display : block;
      margin-top : 5px;
    }
    
    Листинг 10.6. Заметка NoteTaker: код CSS

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

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

    "... width : 100px ..."
    

    представлена как

    "... width : {width}px ..."
    

    С помощью регулярных выражений JavaScript мы можем подставить в эту строку значения, введенные пользователем в панели инструментов или диалоговом окне Edit. Имея готовую строку, мы можем создать заметку, как показано на листинге 10.7.

    function display_note()
    {
      var style = generate_style();
      var html = generate_html();
      var doc = window.content.document;
    
      var stree = doc.getElementById("notetaker-styles");
      if ( !stree ) // add the topmost <style>
      {
        stree = doc.createElement("style");
        stree.setAttribute("id","notetaker-styles");
        var head = doc.getElementsByTagName('head').item(0);
        head.appendChild(stree);
      }
      stree.innerHTML = style;
      var htree = doc.getElementById("notetaker-note");
      if ( !htree ) // add the topmost <span>
      {
        htree = doc.createElement("span");
        htree.setAttribute("id","notetaker-note");
        var body = doc.getElementsByTagName('body').item(0);
        body.appendChild(htree);
      }
      htree.innerHTML = html;
    }
    
    Листинг 10.7. Создание заметки NoteTaker средствами динамического HTML

    В этом коде используется функция getElementsByTagName() для того, чтобы получить теги <head> и <body> web-документа - мы не знаем идентификаторов (id) этих тегов. Затем код создает теги для стилей и заметки, которые добавляет к содержимому тегов <head> и <body> соответственно. Затем специальное свойство innerHTML, поддерживаемое Mozilla, используется для того, чтобы добавить остальное содержимое заметки, существующее в форме строки. Для простоты мы полагаем, что отображаемая страница не является системой фреймов (frameset), а также содержит теги <head> и <body>. Мы могли бы обойти эти ограничения, но для этого нам пришлось бы лишь написать больше кода DHTML, не узнав ничего нового о Mozilla. Функция generate_html(), представленная на листинге 10.8, тривиальна; функция generate_style() устроена аналогичным образом.

    function generate_html() {
      var source =
        '<span id="notetaker-note-summary">{summary}</span>' +
        '<span id="notetaker-note-details">{details}</span>';
      source = source.replace(/\{summary\}/, note.summary);
      source = source.replace(/\{details\}/, note.details);
      return source;
    }
    
    Листинг 10.8. Добавление данных заметки к шаблону средствами DHTML

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

    Для этого нужно скопировать файл navigator.xul, находящийся в архиве comm.jar в каталоге chrome, в подкаталог notetaker/content каталога chrome. Теперь, запустив Mozilla при помощи следующей команды:

    mozilla -chrome chrome://notetaker/content/navigator.xul
    

    мы получим обычное окно браузера. Именно эту копию мы и будем модифицировать. Прежде всего, нужно добавить теги вида <script src=> для всех необходимых скриптов. Затем следует найти строку вида:

    <toolbar id="nav-bar" ...
    

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

    <toolbarbutton label="Test" onclick="display_note()"/>
    

    После того, как мы сохраним и вновь запустим измененный файл, к панели навигации браузера добавится новая кнопка. Нажатие на эту кнопку приведет к открытию заметки при условии, что в окно браузера загружена web-страница. Мы можем использовать для этой кнопки любой обработчик события onclick, включая обращения к execute(), action() и любым другим методам. При желании мы можем поместить в этот файл даже тег <toolbar> приложения NoteTaker со всем его содержимым.

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

    function content_poll() {
      if ( !window.content ) return;
      var doc = window.content.document;
      if ( !doc ) return;
      if ( doc.getElementsByTagName("body").length == 0 ) return;
      if ( doc.location.href == "about:blank" ) return;
      if ( doc.visited ) return;
      display_note();
      doc.visited = true;
    }
    setInterval("content_poll()", 1000);
    

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

    Итак, посмотрим, чего мы достигли к настоящему моменту. Мы создали окна, которые используются для взаимодействия NoteTaker с пользователем. Текущая заметка представлена в памяти объектом JavaScript. Мы создали логику, связывающую отображаемую заметку с этим объектом, а также обеспечили определенное взаимодействие между окнами. Для того чтобы этот механизм обрел завершенную форму, нам нужно поработать над связью данных, вводимых пользователем, и объектом JavaScript, представляющим заметку. Кроме того, в приложении пока отсутствует корректная работа с URL.

    Предполагается, что каждой web-странице соответствует отдельная заметка. Наше приложение хранит заметки на web-сервере и загружает их оттуда. Заметка даже перезагружается при перезагрузке страницы. Существующий механизм подразумевает, что мы должны отправить запрос web-серверу, чтобы получить текст заметки - это не слишком эффективно. Единственная альтернатива, которой мы располагаем к настоящему моменту, - хранить заметки в локальном текстовом файле. Однако платформа Mozilla предусматривает более эффективное решение - хранение заметок в виде данных RDF. Мы обсудим этот вариант во второй части книги.

    10.10 Отладка: диагностика окон

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

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

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

    При анализе работы сложного приложения ничто не может заменить информации о состоянии программы, которая в реальном времени выводится в специальное окно. Платформа Mozilla позволяет добиться этого различными способами.

    Простейший из них - использовать метод dump(), описанный в главе 5, "скрипты". Вывод этого метода отображается в текстовой консоли, которая открывается при запуске Mozilla с ключом - console.

    Почти столь же просто изучать работу приложения при помощи многочисленных панелей отладчика JavaScript. Сначала запустите отладчик вручную. Для знакомства с ним можно открыть все возможные панели, используя меню Вид | Показать / Скрыть. Как можно раньше по ходу исполнения скриптов JavaScript в документе HTML или XUL, который вы хотите отлаживать, добавьте команду:

    debugger;
    

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

    В HTML объект document предоставляет методы open(), close() и write(). Поскольку содержимое начинает отображаться до окончательной загрузки документа, на основе этих методов можно организовать последовательный вывод диагностической информации. Окно HTML можно открыть из другого окна при помощи метода window.open(), а затем по мере необходимости добавлять к нему содержимое при помощи метода document.write().

    XUL не поддерживает последовательного отображения загружаемых данных в стиле HTML, однако сходного результата можно достичь другими средствами. При помощи метода window.open() необходимо создать окно для вывода диагностической информации на основе простейшего документа XUL. Этот документ не должен иметь никакого содержимого помимо <window orient="vertical">. Для добавления содержимого в это окно следует использовать код, показанный в листинге 10.9:

    var win = window.open( :new window :);
    
    function logger(message)
    {
      var obj = win.document.createElement("description");
      var txt = win.document.CreateTextNode(message);
      obj.appendChild(txt);
      win.document.appendChild(obj);
    }
    
    Листинг 10.9. Вывод диагностической информации в новое окно XUL

    Нужно иметь в виду, что элементы нового документа создаются с использованием свойств и методов данного, а не исходного документа. Эту систему можно дополнить полосами прокрутки и другими элементами управления. Если приложение считается защищенным (т.е. установлено в chrome или защищено другим способом), столь же просто использовать для диагностики консоль JavaScript. Пример работы с консолью приведен в листинге 10.10:

    // Find the console
    var C = Components;
    var obj = C.classes["@mozilla.org/consoleservice;1"];
    var iface = C.interfaces.nsIConsoleService;
    var cons = obj.getService(iface);
    // Log a message
    cons.logStringMessage("test message");
    
    Листинг 10.10. Вывод сообщений на консоль JavaScript.

    Аналогичным образом можно организовать вывод на консоль Java. Преимущество этого метода состоит в том, что консоль Java не является окном XUL. Для ее использования не требуется браузера, собранного с возможностью отладки, а также текстовой консоли операционной системы (которая нужна для вывода при помощи dump()). Сообщения могут выводиться на консоль Java, не нарушая состояния существующих окон XUL. Эта консоль не видна при получении списка открытых окон средствами XUL. Для вывода сообщения непосредственно на консоль Java можно использовать следующую старомодную строку, хорошо знакомую разработчикам со времен Netscape 4.x (здесь имеет место вызов статического метода класса):

    window.java.lang.System.out.println("my message");
    

    Защищенное приложение может самостоятельно создать консоль Java, как показано в листинге 10.11.

    var C = Components;
    var obj = C.classes["@mozilla.org/oji/jvm-mgr;1"];
    var iface = C.interfaces.nsIJVMManager;
    var cons = obj.getService(iface);
    if (cons.JavaEnabled) cons.showJavaConsole();
    
    Листинг 10.11. Открытие консоли Java из скрипта

    Прежде чем открыть окно, этот код проверяет, не отключил ли пользователь подсистему Java в целом.

    10.11 Итоги

    Система управления окнами в Mozilla разработана под значительным влиянием технологии, используемой в традиционных браузерах. Применение метода window.open() и ряда специализированных тегов XUL позволяет достичь значительных результатов. Эти теги представляют интерес, в первую очередь, для разработчиков, чьи приложения подобны браузеру.

    Архитектура XPCOM содержит целый ряд интересных объектов для управления отображаемыми документами, среди которых следует особо отметить DocShell. Эти объекты насыщены функциональностью, необходимой для сложной работы с содержимым.

    Стили CSS обеспечивают дополнительные возможности настройки окон Mozilla. При помощи стилей разработчик приложения может придать окнам вид, характерный для данной платформы, чтобы приложение не выглядело чужеродным.

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


    об авторе

    Администрация сайта не несет ответственности за содержание и соблюдение копирайта на материалы,
    найденные в свободном доступе на просторах интернета без указания авторских прав на них.
    Документация предоставляется, размещается и публикуется пользователями сайта с максимально известной информацией об источнике.
    Если Вы являетесь правообладателем представленных статей, и не хотите их здесь видеть - напишите нам, и мы с радостью их удалим с сайта





    Сайт создан в системе uCoz