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

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

    XUL расшифровывается как XML User-interface Language, язык описания интерфейсов на основе XML. В этой главе описываются основы этого языка. В частности, речь пойдет о его структурных аспектах, от которых зависят все прочие более интересные особенности языка. Без понимания основной структуры использование других, более заметных и подчас несколько сбивающих с толку, возможностей языка не может быть успешным. Поэтому мы и начнем с самого начала.

    Основная структура XUL - система визуальной разметки документа, которая определяет геометрическое положение всех прочих данных в формате XUL. Это позиционирование в основном определяется тегом <box> и еще несколькими аналогичными.

    На схеме в начале главы показана область действия этих основных функций XUL в Mozilla. Неудивительно, что на диаграмме все эти функции находятся на стороне графического интерфейса (правая часть диаграммы). Система визуализации определяет, где на мониторе появится содержимое XUL-документа, но для этого, в основном, используются всего две большие структуры в памяти: фреймы и DOM. Эти структуры отвечают за расположение элементов и данные XUL-документа. Многие фундаментальные W3C-стандарты влияют на эти функции. Для наглядности рассмотрим несколько маленьких файлов.

    DOM не так интересен с точки зрения отображения; мы едва замечаем его вообще. Именно систему фреймов программисты используют ежедневно, чтобы создать множество XUL-тегов для нового интерфейса. Хотя работа с ней идет не напрямую, каждый тег содержит информацию, которая ею используется.

    В листинге 2.1 еще раз приведен пример "hello, world" из главе 1, "Основные концепции".

    <?xml version="1.0"?>
    <!DOCTYPE window>
    <window xmlns= "http://www.mozilla.org/keymaster/gatekeeper/
      there.is.only.xul">
      <box>
        <description>hello, world</description>
      </box>
    </window>
    
    Листинг 2.1. "hello, world" еще раз

    Внешний тег <window> - подсказка для нас; он означает, что документ должен появиться в отдельном окне, но это только подсказка. Его основная функция - быть корневым тегом документа, так как стандарт XML требует, чтобы у всех документов был корневой тег. А вот тег <box> уже говорит нам о том, как будет отображаться содержимое документа. По большому счету, изучение XUL - это изучение блочных контейнеров типа <box>. На самом деле корневой тег (<window>) - тоже в каком-то смысле действует как <box>, но обладает более скромными возможностями визуальной организации данных, по сравнению с <box>.

    Чтобы эффективно работать с материалом этой главы, требуется некоторое знание XML и CSS. Директивы <?xml?> и <!DOCTYPE>, а также атрибут xmlns вместе определяют, с документом какого типа мы имеем дело. Так что первые три строчки листинга 2.1 гарантируют, что содержимое документа будет размещено на экране в соответствии с системой визуальной разметки XUL, а не HTML. Правила визуализации можно замещать и менять в любом месте документа с помощью правил стилей CSS 2. Для правил CSS 2 используется простой синтаксис:

    селектор { свойство : присваиваемое-выражение; }
    

    Селектором может быть тег, класс или уникальный для документа идентификатор. Правила стилей CSS 2 сами по себе не являются частью стандарта XML и поэтому должны храниться как XML-атрибуты или в отдельном файле с расширением .css. Чтобы загрузить таблицу стилей из внешнего файла в XML-документ, необходимо использовать директиву <?xml-stylesheet?>. Пример использования этой директивы:

    <?xml-stylesheet href="rules.css" type="text/css"?>
    

    Эта строчка должна помещаться после тега <?xml?>.

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

    window { display : -moz-box; }
    

    Смысл данной строчки подробно объясняется далее в этой главе. Чтобы узнать о более традиционном применении CSS 2 (вместе с HTML), следует обратиться к стандартам на сайте www.w3c.org или исследовать любую web-страницу или окно Mozilla с помощью Инспектора DOM.

    2.1 XUL - это блоки

    При изучении HTML обычно начинают с тегов вроде <P> и <H1>. И только получив некоторый опыт, мы понимаем, как полезен незаметный тег <SPAN>. Тег <H1>, например, можно легко заменить тегом <SPAN> с соответствующими CCS-стилями, например: display:block и font-size:large. И так можно поступить со многими тегами, не только с этим - всего лишь использовать <SPAN> и несколько правил стилей. Изучение HTML обычно не начинают со <SPAN>, поскольку кажется, что сам по себе он "ничего не делает"; обычно он никак не проявляется.

    В XUL тег <box> играет ту же роль, что и <SPAN> в HTML, только вот научиться пользоваться <box> нужно с самого начала. Важно, чтобы вы как можно быстрее научились работать с XUL-блоками. В листинге 2.2 приведен фрагмент кода на XUL, демонстрирующий типичное использование блоков для структурирования данных.

    <box orient="horizontal">
      <box orient="vertical">
        <description>Яблоки</description>
        <description>Апельсины</description>
      </box>
      <box orient="vertical">
        <description>HTML</description>
        <box orient="horizontal">
          <description>XUL</description>
          <description>XBL</description>
        </box>
      </box>
    </box>
    
    Листинг 2.2. Фрагмент кода на XUL, иллюстрирующий использование блоков для структурирования их содержимого

    В этом примере тегов <box> так же много, как и "настоящих" тегов. Для XUL это нормально. Нужно привыкать использовать их практически "на автомате". На рисунке 2.1 показано, как эти данные могли бы выглядеть в Microsoft Windows, если бы документ был завершен.

    Визуализация блоков

    Рис. 2.1.  Визуализация блоков

    На этом снимке окна вместе с разметкой XUL использовались простые правила стилей CSS, чтобы блоки выглядели нагляднее. В каждом блоке есть два тега, и их содержимое отображается или друг за другом или друг над другом. Такое расположение - цель использования <box>. Обычно видимые границы имеют только один или два блока. В листинге 2.3 приведены правила стилей, использовавшиеся для примера.

    box { 
      border : solid;
      border-color: grey;
      padding: 4px;
      margin: 2px;
    }
    
    Листинг 2.3. Простая таблица стилей для отображения границ блоков.

    Очевидно, что разметка с помощью XUL и оформление с помощью CSS очень похожи на аналогичные процедуры с HTML - по крайней мере, в основном. Но насколько они похожи? Начать изучение с блоков означает освоить правила визуального форматирования. Изучив их, мы сможем экспериментировать с CSS-стилями - таким образом можно узнать о разметке с помощью XUL очень многое.

    2.2 Принципы верстки XUL

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

    Правила визуальной организации HTML-данных описывают, в частности, модель представления документов в виде блоков, определенную в стандарте CSS 2, раздел 8 (см. http://www.w3.org/TR/REC-CSS2). HTML и XUL используют несколько общих стилей CSS 2, в том числе правила оформления блоков. Несложно догадаться, что такая модель представления также используется XUL. Но это еще не все. Блоки так важны для нас, что лучше прояснить все с самого начала.

    Прежде всего, блоки из модели представления и <box> не эквивалентны. Многие теги XUL соответствуют модели представления в виде блоков, но сам <box> описывается ею не полностью.

    Кроме того, хотя эта модель определяет одну концепцию визуального форматирования, она не определяет всю стратегию. Для стратегии форматирования необходимо устройство вывода и система, отображающая форматируемое содержимое на это устройство. Если таким устройством является компьютер, требуется модель визуального форматирования (см., например, главы 9 и 10 стандарта CSS 2, абстрагируясь от модели блоков). Для модели форматирования, используемой CSS 2, наиболее важными являются понятия блока (block, не box) и строкового блока (тоже block). Первый представляет собой всего лишь прямоугольную область на экране. Если его содержимое занимает более одной строки, то каждая его строка будет строковым блоком.

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

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

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

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

    • и HTML-, и XUL-элементы следуют правилам модели представления документа в виде блоков;
    • для HTML и XUL используются разные модели визуального форматирования; строковые блоки меняются в размерах в HTML и XUL по-разному;
    • некоторые HTML-теги похожи на строковые контейнеры CSS 2, а некоторые XUL-теги похожи на строковые контейнеры XUL. <box> - строковый контейнер XUL, но он также следует правилам модели представления в виде блоков;
    • у большей части HTML- и XUL-тегов есть свой блок CSS 2 (block), прямоугольная область, в которой находятся тег и его содержимое, но это сбивающий с толку термин. В Mozilla термин "блок" в таком значении используется только для HTML, а для XUL мы его будем применять как эквивалент контейнеру box. "Фрейм" - более глубокое понятие, относящееся и к HTML, и к XUL. Говоря об отображении тегов лучше использовать слово "фрейм", а не "блок";
    • и в XUL, и в HTML содержимое может выходить за пределы блока CSS 2 (block) своего тега. Это усложняет ситуацию, но лучше не вдаваться в подробности переполнения, пока все остальное не станет ясно, или вообще не задумываться об этом.

    Самый простой способ увидеть разницу между XUL и HTML - поэкспериментировать. Для этого мы возьмем код из листинга 2.2 и заменим все теги box на <DIV>. Внесем соответствующие изменения в таблицу стилей. Полученный код вставим в документ XHTML 1.0 и загрузим этот файл в окно chrome. Попробуем изменить размеры окна и сравнить реакцию XUL- и HTML-окон на это действие. Она будет разной. О том, насколько она различается, речь пойдет дальше.

    2.2.1. Отображение одного тега

    Отображение одиночного XUL-тега подразумевает использование модели представления в виде блоков из CSS 2. Большая часть XUL-тегов, в том числе box, оформляются таким образом. На рисунке 2.2 показана эта модель, основанная на схеме из главы 8.1 описания стандарта.

    Модель представления в виде блоков, CSS 2

    Рис. 2.2.  Модель представления в виде блоков, CSS 2

    На рисунке 2.2 показан текст (слово "Anything") как содержимое блока, но вообще его содержимым может быть буквально что угодно: текст, изображение, кнопка, полоса прокрутки или флажок. Глава 8, "Модель представления документа в виде блоков", и глава 14, "Цвета и фон", - единственные главы стандарта CSS 2, которые полностью соответствуют XUL.

    Стандартные правила вычисления размеров также можно применять к XUL-элементам. Поддерживаются свойства:

    minwidth width maxwidth minheight height maxheight
    

    Если тег одиночный, то эти правила действуют так же, как и для HTML, но внешний по отношению к рассматриваемому тег может расширить или сузить область, занимаемую элементом, немного не так, как это делается в HTML. То есть вычисления размеров, предложенные в CSS 2, могут быть недостоверными. Свойства top и left работают только в отдельных случаях; свойства bottom и right не применяются вообще. Понимание причин этого неизбежно приводит к вопросу позиционирования. Свойства top и left также обсуждаются в разделе "Стеки и колоды".

    Согласно CSS 2, тег-блок можно позиционировать - помещать в определенное место. Позиционирование XUL-тегов гораздо проще, чем позиционирование HTML-тегов, но при этом используются те же самые свойства стилей. В CSS 2 позиционирование выполняется с помощью четырех свойств: display, position, float и visibility.

    • display: в CSS 2 это свойство может принимать множество значений. Но в XUL из них поддерживаются только none и inline. При этом использование none корректно, но лучше применять XUL-атрибут hidden, хотя результат будет один и тот же. Свойство display со значением none применимо ко всем XUL-тегам, тогда как inline используется только для того, чтобы сообщить текущему тегу, что он находится внутри некоторого <box>. В XUL также есть множество собственных значений для свойства display, примерно по одному на каждый элемент, и их назначение часто настолько непонятно, что они просто бесполезны. Одно из этих значений, -moz-box, например, описывается чуть ниже.
    • position: в XUL не поддерживается абсолютное и фиксированное позиционирование. Их следует избегать, так как они могут вызвать аварийное завершение работы Mozilla. Предусмотрена поддержка относительного позиционирования, но только если тег, к которому применяется данное правило стиля - непосредственный потомок тега <stack> или <bulletinboard>.
    • float: в XUL не поддерживается вообще.
    • visibility: со значением hidden это свойство делает элемент невидимым. Хотя это и работающее решение, рекомендуется использовать XUL-атрибут hidden. В XUL нет таблиц, но если присвоить этому свойству значение collapse, эффект будет аналогичный: границы "сожмутся", и элемент не будет виден. Опять же, вместо этого свойства рекомендуется использовать атрибут collapsed, не отличающийся по эффекту от vsibility:collapse. Оба метода можно использовать для всех тегов XUL, кроме <menuitem>, которому доступен только атрибут hidden.

    В XUL самым общим из правил стилей является display: -moz-box, особый тип отображения, использующийся в Mozilla. Это значит, что все существующие XUL-теги и теги, определенные пользователем данного документа, будут вести себя как <box>, если для них не указаны собственные стили. Вот почему блоки в XUL так важны. Значение -moz-box делает поведение XUL-тегов непохожим на поведение HTML-тегов.

    В chrome есть стандартный архив под названием toolkit.jar. В нем содержится файл xul.css, в котором определены основные стили для всех тегов XUL. Эти стили применяются к XUL-документу прежде всех прочих стилей, в том числе глобальных и стилей отдельных тем. Именно в этой таблице стилей задано значение -moz-box.

    2.2.2. Отображение группы тегов

    Чтобы отобразить в XUL группу тегов, следует поместить их внутрь <box>. Есть и другие способы, но этот - простейший. Проблема заключается в том, что <box> ведет себя не так, как может вести себя "настоящий" контейнер, например, коробка. На рисунке 2.3 показано, какими способами можно визуально организовать одни элементы внутри других.

    Разные варианты хранения одних объектов внутри других

    Рис. 2.3.  Разные варианты хранения одних объектов внутри других

    Очевидно, что любая коробка двумерная, а полка нет. <box> больше похож на полку. На полке может размещаться только один ряд элементов. Если значение атрибута orient - "vertical", <box> больше похож на стеллаж с несколькими полками. В стеллаже, имитируемом элементом <box>, на одной полке может храниться только один объект, как, например, в подставке для компакт-дисков.

    Многие HTML-теги тоже похожи на полки, но это сходство обманчиво, так как большая их часть поддерживает перенос, так что если ряд объектов слишком длинен, он разбивается на два и более. В XUL такого обычно не бывает. В XUL при недостатке места слишком длинная строка, например, будет просто усекаться. Если открыть какую-нибудь стандартную программу Microsoft Windows, например, Paint, и начать сжимать окно, мы увидим, что элементы из строки меню переорганизуются в две строки. Если попытаться сжать окно Mozilla, часть строки меню просто исчезнет, а не переместится ниже. Это происходит потому, что <box> не поддерживает перенос строки для своего содержимого, равно как и другие аналогичные теги.

    Из этого правила есть два исключения: теги <description> и <label> поддерживают перенос строк по необходимости. Содержимое тега <description> отображается примерно так же, как содержимое большинства HTML-тегов.

    Горизонтально ориентированный <box> и его содержимое аналогичны строковым блокам HTML. Основное различие между ними заключается в подсчете размеров. И в HTML, и в XUL строковый блок должен быть достаточно большим, чтобы вместить все содержимое, но возможны исключения. В HTML расчет свободного места, необходимого для размещения содержимого тега, производится до тех пор, пока все объекты не будут размещены. Если размер окна уменьшится, содержимое тега может быть разбито на две строки вместо одной. В XUL же производится расчет необходимого места и выделяется ровно такое количество площади, какое было рассчитано. Содержимое должно разместиться внутри выделенной области. В XUL перенос строк обычно не поддерживается, так что если размер окна уменьшится, <box> попытается сжать свое содержимое так, чтобы оно уместилось в оставшуюся площадь. Если достигнуты минимальные размеры содержимого, ничего не остается, кроме как выйти за границы выделенной области и отсечь эти "выступающие" части. Такое поведение диктуется моделью визуального форматирования.

    Вертикально ориентированный <box> аналогичен стопке строковых блоков CSS 2, размещенных один на другом. К ним применяются те же правила, что и к горизонтальным контейнерам <box>, но каждый строковый блок может содержать только одного непосредственного потомка.

    2.2.3. Основные атрибуты размещения блоков

    Как и в HTML, размещение можно оставить браузеру, а можно заняться им самому. Для группирования содержимого тега <box> используется стандартный набор атрибутов. Эти атрибуты применимы к любому блоку, так как многие XUL-элементы ведут себя как блоки. На рисунке 2.4 схематично изображено действие этих атрибутов.

    В данном примере значением orient является "horizontal", для <box> это значение по умолчанию. Чтобы понять, как будет выглядеть случай с orient="vertical", поверните эту книгу на 90 градусов по часовой стрелке. Каждое слово на схеме - атрибут XUL, влияющий на то, как будет размещаться содержимое тега. Каждый объект, содержащийся в <box>, сам должен быть XUL-тегом.

    Исторически некоторые из этих атрибутов происходят от свойств из стандарта CSS 2. И скоро стало казаться странным, что эти XUL-атрибуты и CSS-свойства совершенно независимы друг от друга. В частности, CSS- свойство valign использовать не рекомендуется, хотя оно и поддерживается до сих пор. Ниже приведен список корректных атрибутов размещения. На рисунке 2.5 проиллюстрировано их действие.

    • orient = "horizontal" | "vertical". Этот атрибут определяет, должно ли содержимое размещаться по горизонтали или по вертикали, а также задает основное направление: вправо по умолчанию для horizontal или вниз - для vertical. По умолчанию orient="horizontal".
    • dir = "ltr" | "rtl" | "normal" | "reverse". Этот атрибут похож на одноименный атрибут в HTML и определяет основное направление для размещения содержимого: слева направо или наоборот. Значение normal эквивалентно ltr, а reverse - rtl. В случае вертикального ориентирования "слева направо" значит размещение сверху вниз, а "справа налево" - снизу вверх. По умолчанию dir="ltr".
    • pack = "start" | "center" | "end". Этот атрибут выравнивает содержимое контейнера относительно основного направления, его действие похоже на действие команды "Выровнять" в текстовых процессорах. start соответствует выравниванию влево или вверх, center - по центру, end - вправо или вниз. Обычно блок может расширяться, чтобы занять все доступное место, в таких случаях атрибут pack может оказаться полезным. Если блок не может расширяться, этот атрибут не имеет никакого эффекта. Возможность расширения зависит от значения атрибута align. По умолчанию pack="start".

    Стандартные атрибуты верстки тегов-контейнеров.

    Рис. 2.4.  Стандартные атрибуты верстки тегов-контейнеров.

    • align = "start" | "center" | "end" | "baseline"| "stretch". Данный атрибут выравнивает содержимое блока относительно направления, перпендикулярного основному. В этом направлении всегда можно выравнивать только один объект, поэтому атрибут просто смещает каждый объект вверх/вниз или вправо/влево. Его стоит использовать, только если ширина блока по направлению, перпендикулярному основному, больше ширины содержимого. В случае горизонтального ориентирования значение baseline смещает содержимое до уровня нижней базовой линии шрифта, как и в CSS 2: текст смещается до нижней базовой линии, а все остальные объекты смещаются к нижней границе блока. Значение stretch предполагает полное выравнивание, но так как выравнивать можно только один объект, он просто увеличивается, пока не достигнет границ. Это относится ко вложенным блокам, изображениям, элементам управления, но не к тексту. По умолчанию align="stretch".
    • equalsize = "always". Если значение этого атрибута - always и у всех тегов-потомков есть атрибут flex, всем объектам текущего тега будет задан один и тот же размер относительно основного направления. Это свойство часто используется для табличного размещения (например, с помощью grid). Любое другое значение отключает эту функцию.

    Mozilla также поддерживает атрибут ordinal, он записывается автоматически, когда Mozilla сохраняет и восстанавливает информацию о XUL-документах при помощи атрибута persist. Механизм сохранения свойств документа обсуждается в главе 12, "Оверлеи и chrome". Для нас это пока не особенно важно, но знать его основные принципы работы полезно.

    ordinal относится ко всем потомкам любого данного тега; значением этого атрибута может быть целое неотрицательное число. Оно определяет порядок следования потомков внутри данного тега. Обычно отсчет ведется автоматически и соответствует порядку следования тегов в XUL- документе. Атрибут ordinal часто используется для записи состояния столбцов тега <tree>.

    Для всех этих атрибутов значение inherit эквивалентно значению inherit в свойствах CSS: значение атрибута будет таким же, как у аналогичного атрибута родительского тега. Однако значение inherit может быть задано только с помощью правил CSS 2, эквивалентных перечисленным XUL-атрибутам (см. раздел "Альтернатива: таблицы стилей"). На рисунке 2.5 показано, как будут выглядеть элементы с применением тех или иных атрибутов.

    Для создания снимка окна на этом рисунке понадобилось 82 тега <box>, хотя размещение, приведенное там, и кажется несколько надуманным и чрезмерно сложным. Другие часто используемые атрибуты можно применять ко всем элементам, а не только к блочным контейнерам. Вот эти атрибуты:

    • collapsed = "true" | "false". Если значение данного атрибута - true, тег будет "свернут" так, как если бы к нему применили правило CSS 2 visibility: collapse. Он не будет занимать на экране никакого места, что повлияет на размещение остальных объектов внутри внешнего по отношению к нашему тегу контейнера. Если его значение - false или любое другое, отличное от true, элемент снова станет виден. Динамическая смена значений collapsed приводит к полной перерисовке документа, а это достаточно трудоемкий процесс для Mozilla. Кроме того, следует помнить, что в CSS 2 используется свойство collapse (без "d" на конце), а в XUL - атрибут collapsed (с "d" на конце).
    • hidden = "true" | "false". Если значение этого атрибута - true, тег исчезнет с экрана, как при использовании правила CSS 2 display: none. Тег будет невидим, но занимаемое им место не освободится. Если его значение - false или любое другое, отличное от true, тег снова станет виден. Динамическая смена значений hidden не приводит к перерисовке всего документа.
    • flex = "integer". Если значение этого атрибута - натуральное число, тогда тег, для которого определен данный атрибут, может занимать больше места, чем необходимо. При этом эффект от использования атрибута pack для внешнего контейнера сводится к нулю, если, конечно, границы, до которых может расширяться наш тег, не ограничены каким-либо образом. flex рассматривается в разделе "Элементы размещения блоков" настоящей главы. Эквивалент этому атрибуту в CSS 2 - расширение -moz-box-flex.
    • debug = "true". Если значение данного атрибута - true, вам будет доступна вся информация о структуре размещения содержимого текущего тега. Этот атрибут подробнее рассматривается ниже в разделе "Отладка". Важно помнить, что при использовании этого атрибута внешний вид документа не будет соответствовать "настоящему".

    Стандартные варианты размещения XUL-блоков

    Рис. 2.5.  Стандартные варианты размещения XUL-блоков

    Многие другие атрибуты также влияют на размещение, но эти - самые важные. Чтобы продолжить анализ системы размещения, нам нужно вернуться к системе стилей Mozilla.

    2.2.4. Понятие фрейма и расширение стилей

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

    2.2.4.1. Что такое фрейм

    Фрейм - это модель реализации, используемая внутри платформы Mozilla и управляющая видимым состоянием одного тега. В сложных случаях одному тегу могут соответствовать несколько фреймов или вообще ни одного, но на практике лучше руководствоваться правилом "один фрейм, один тег". Фрейм с содержащейся в нем информацией - модель, дополняющая "объекты", описанные в стандартах W3C DOM. Объекты DOM, а на самом деле просто интерфейсы к объектам, - внутренние представления XML-сущностей, обычно целого тега. Они позволяют рассматривать теги с точки зрения содержащихся в них данных. Фреймы - внутренние представления CSS-стилей, связанных с целыми тегами. Почти всем тегам соответствуют фреймы, которые дают нам пространственную, визуальную и геометрическую интерпретацию этих тегов. Фреймы включают в себя и стандартные стили CSS, и их расширения Mozilla.

    Фреймы важны для XUL, так как (очевидно) вам нужно знать, есть ли у данного элемента фрейм: у тегов <box>, например, всегда есть фрейм.

    При каскадном наследовании стилей, изменении размеров окна и динамическом обновлении тега именно фреймы отвечают за координирование изменений в отображении документа. Все это происходит внутри Mozilla автоматически, как и обработка событий, определенных стандартом DOM.

    С точки зрения прикладного программирования фреймы - более абстрактное понятие, чем интерфейсы DOM, и работать с ними напрямую необязательно. Все нужные действия по обработке фреймов выполнит механизм визуализации Gecko. Фреймы важны, только если запутаться в проблемах, связанных с отображением документа. Тогда будет полезно вспомнить правило "нет фрейма - нет нормального размещения". Будет визуальному элементу соответствовать фрейм или нет, зависит от программной реализации Mozilla, но обычно верно следующее: у каждого видимого элемента, находящегося на уровне z-index:0 и занимающего на экране отдельный прямоугольный участок, есть фрейм. У многих других видимых элементов, например, абсолютно позиционируемых HTML-элементов, также есть фреймы. У всплывающих подсказок фреймов нет. У XUL-тегов <tree> очень сложная система соответствия фреймам.

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

    2.2.4.2. Стили и расширения стилей, влияющие на состояние и содержимое фреймов

    В Mozilla к стандарту CSS 2 добавлен набор дополнительных свойств. Все эти свойства (расширения стандарта) начинаются с префикса "-moz" или ":-moz". Это могут быть уникальные собственные расширения, скрытые внутренние функции, экспериментальные или отладочные функции или просто свойства, которые могут войти в будущий стандарт. Некоторые из них дополняют модель отображения стилей, а некоторые предназначены скорее для программистов.

    Свойства и расширения стилей определены в исходном коде в заголовочных файлах C/C++. Можно заглянуть в файлы, чьи имена заканчиваются на List.h, например, в nsCSSPropList.h, и убедиться, что список расширений просто огромен. Почему же их так много?

    Все дело в реализации. Набор стандартных свойств CSS 2 можно представить как большой конечный автомат, так как у каждого отображаемого элемента или фрейма есть конечный набор состояний. Набора состояний, соответствующего свойствам из CSS 2, может быть достаточно для описания отображаемых данных, но недостаточно для полной системы отображения CSS 2. В такой системе должна храниться дополнительная служебная информация. Например, свойств CSS 2 может быть достаточно для описания внешнего вида кнопки, но системе отображения CSS 2 внутри Mozilla нужно также знать, содержит ли XML- код этой кнопки описание элемента управления из какого-либо набора графических элементов. Если да, то нужно работать с этим элементом управления. Вот эта дополнительная информация (используется ли данный элемент управления) также может храниться как расширение стиля Mozilla, например, -moz-gc-wrapper-block. Этот пример на самом деле представляет интерес только для разработчиков Mozilla.

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

    Похожее разделение на внешнее и внутреннее относится и к содержимому, к которому применяются стили. Содержимое данного тега, даже если в нем нет тегов-потомков, можно разбить на несколько независимых частей. У этих внутренних частей могут быть собственные стили оформления, пусть даже недоступные извне. Пример: буквица, первый символ абзаца. Хотя в стандарте CSS 3 к стилю этой буквы можно получить доступ через псевдокласс :initial-letter, в Mozilla он реализован как внутренний фрейм. Такие внутренние части элемента скрыты от программиста, как и внутренние расширения стилей. В системе отображения это основные компоненты самого низкого уровня, специфичные для Mozilla и, вероятно, несколько меняющиеся со временем. По возможности следует стараться использовать только внешние функции, хотя бы потому, что они проще и более понятны.

    Эти последние несколько абзацев можно рассматривать как предупреждение. Если только вы не хотите помочь в поддержке самой платформы Mozilla, копаться в ее низкоуровневых "внутренностях" ни к чему.

    Пример полезного внешнего расширения - сокращенная строка из таблицы стилей html.css, входящей в установку Mozilla. В ней есть и новое свойство стиля, и новое значение. Mozilla может не поддерживать напрямую свойство outline из CSS 2, но у нее есть расширение с похожей функциональностью:

    input:focus {-moz-outline: 1px dotted -moz-FieldText;}
    

    -moz-outline значит "показывать контур". -moz-FieldText значит "использовать для контура стандартный цвет текста в полях форм".

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

    <mybox align="start"> ... </mybox>
    

    Все английские слова в приведенном коде (mybox, align, start) дают нам подсказки относительно размещения содержимого. Самое простое, что можно сделать с этими ключевыми словами - превратить их в свойства стиля. Действие многих расширений стилей в Mozilla эквивалентно действию какого-либо ключевого слова XUL. Поведение некоторых XUL- тегов полностью зависит от этих стилей, так что смысл тега фактически определяется стилем. Приведенный выше код XUL можно переписать так:

    mybox { -moz-box-align: start; }
    

    Для элемента <mybox> нет C/C++-кода: весь элемент полностью зависит от стилей.

    В Mozilla, кроме новых свойств стиля, есть и новые правила стилей.

    2.2.4.3. Дополнительные состояния доступа к расширениям правил стиля

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

    В разделе этой главы (и многих других) под названием "Альтернатива: таблицы стилей" исследуются доступные расширения стилей Mozilla, относящиеся к обсуждаемой теме. В этой главе рассматриваются расширения, отвечающие за основное расположение объектов. Описываются и расширения свойств, и расширения правил стилей.

    2.3. Теги для размещения данных в виде блоков

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

    2.3.1. Блоки

    Как уже было сказано, ко всем тегам XUL, включая неизвестные, применяется правило display: -moz-box. Затем для некоторых из элементов это правило переопределяется разработчиком, а все остальные остаются аналогичными <box>. То есть <xyzzy>/ и <happysad> - тоже теги XUL и тоже блоки, хоть это и неочевидно. В качестве стандартных блоков предлагаются три элемента.

    1. <box>. Содержимое этого блока выравнивается по горизонтали, а его атрибуты по умолчанию описаны выше в разделе "Основные атрибуты размещения блоков".
    2. <hbox>. Горизонтальный блок. Выполняет те же функции, что и <box>. Его имя просто напоминает о его функциях.
    3. <vbox>. Вертикальный блок. Выполняет те же функции, что и <box orient="vertical">, только <vbox> набирается быстрее. Имя также служит для упрощения чтения кода.

    Тег <vbox> - не больше, чем какой-либо не зависящий от формата, определенный пользователем тег <xyzzy> с расширением стиля -moz-box-orient:vertical. Это расширение эквивалентно использованию атрибута orient="vertical" и является основной чертой <vbox>. Можно, конечно, сказать, что <vbox> следует стилю, а не наоборот. Тег <vbox> не совсем полноправен.

    Другой источник блоков - корневые теги XUL-документов. <window>, <dialog>, <page> и <wizard> - все они ведут себя как блоки и будут обсуждаться подробнее в главе 10, "Окна и панели", кроме <wizard>, который мы рассмотрим отдельно в главе 17, "Установка приложений". С точки зрения размещения объектов, эти теги ведут себя как <box> с атрибутом flex, описанным ниже.

    2.3.2. Атрибут flex и элементы-разделители

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

    2.3.2.1. flex= и align=

    Единственный механизм для "растягивания" XUL-тегов - применение атрибутов flex и align. flex и align могут использоваться со всеми тегами, выполняющими функции блока; flex также может использоваться с несколькими специальными тегами. align описывался в разделе "Основные атрибуты размещения блоков". Вот типичный пример использования flex:

    <hbox flex="1"> ... content ... </hbox>
    

    Значение этого атрибута не наследуется потомками от родительского тега.

    Тег с атрибутом flex может "растягиваться" в обоих измерениях: по x и по y. Тем не менее, добавление flex="1" или align="stretch" не гарантирует того, что занимаемая тегом площадь увеличится: это зависит от внешнего, объемлющего тега (то есть от родительского тега). Для любого данного тега правила "растягивания" по горизонтали и по вертикали различны. Вспомним, что родительский тег определяет основное направление размещения объектов. Перпендикулярное основному направление, как легко догадаться, находится под прямым углом к основному. Вот правила для "растягивания" относительно оси основного направления:

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

    Правило "растягивания" относительно оси перпендикулярного направления:

    • если у родительского тега есть атрибут align="stretch" (или если этот атрибут отсутствует), тег сможет растягиваться в перпендикулярном направлении.

    Из этих правил следует, что если тег должен менять размеры в обоих направлениях, когда пользователь меняет размеры окна, у этого тега и всех его предков должны быть атрибуты flex и/или align="stretch". Обычно это означает, что атрибут flex нужно добавлять к очень большому числу тегов.

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

    Если <box> содержит несколько тегов, все эти теги могут расширяться относительно оси основного направления по-разному. Пустое место внешнего блока будет разделено между ними согласно следующему алгоритму. Все значения атрибутов flex суммируются, а все свободное место делится на количество частей, равное этой сумме. Затем каждому тегу выделяется дополнительное пространство, чей объем пропорционален значению его атрибута flex. Пример, более наглядно объясняющий этот принцип, показан в листинге 2.4.

    <box width="400px">
      <box id="one" flex="1"/>
      <box id="two" flex="2"/>
      <box id="three" flex="3"/>
    </box>
    
    Листинг 2.4.

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

    • Количество свободного места: 400 - 100 = 300 пикселов.
    • Сумма значений атрибутов flex у внутренних блоков: 1 + 2 + 3 = 6.
    • Свободное место для тега с flex="1": 300 / 6 = 50 пикселов.

    Тогда размеры всех трех внутренних блоков изменятся так:

    • Блок "one" получает дополнительно 1 * 50 = 50 пикселов.
    • Блок "two" получает дополнительно 2 * 50 = 100 пикселов.
    • Блок "three" получает дополнительно 3 * 50 = 150 пикселов.

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

    2.3.2.2. <spacer> и другие теги-разделители

    В разделе "Основные атрибуты размещения блоков" рассказывалось о том, как пользоваться XUL-атрибутами для выравнивания содержимого блоков. Но таким образом не удастся отделить друг от друга два блока, если только не использовать для этого несколько тегов <box>. Создать дистанцию между двумя блоками можно с помощью тега <spacer> и атрибута flex.

    Тег <spacer> - обычный определенный пользователем тег. Он не обрабатывается каким-либо особым образом, к нему не применяются никакие стили. Его использование - всего лишь дань традиции XUL, и в словарь XUL он попал только поэтому. Используется он примерно так:

    <hbox flex="1"><box/><spacer flex="1"/><box/><box/></hbox>
    

    Этот код соответствует горизонтальному блоку, содержащему четыре тега. Чтобы понять, как он будет отображаться, вам нужно знать только описанные выше правила. Только у <spacer> есть атрибут flex, позволяющий ему занимать свободное место, поэтому если оно появится, он займет его полностью. Таким образом: слева будет блок, потом пустое место, а потом два блока справа. <spacer> отделяет блоки справа и слева друг от друга.

    <spacer> вообще никак не проявляется визуально, если у него отсутствует атрибут flex="1" и атрибуты ширины и высоты. Он может казаться бесполезным, но он позволяет динамически сжимать свободное пространство между элементами, если это нужно. Некоторые считают, что к <spacer> следовало бы автоматически применять стиль со свойством flex. Пока этого еще нет. На рисунке 2.6 показаны результаты различных значений flex для предыдущей строки кода. Правило стиля border: solid thin было добавлено, чтобы можно было сразу понять, где находится <spacer>. Обычно он невидим.

    Варианты использования <spacer> и разных значений атрибута flex.

    Рис. 2.6.  Варианты использования <spacer> и разных значений атрибута flex.

    Есть и другие XUL-теги, выполняющие те же функции, что и <spacer>. Вот их неполный список: <separator>, <menuseparator>, <toolbarseparator>, <treeseparator> и <spring>. На самом деле любой определенный пользователем тег с атрибутом flex="1" будет вести себя как разделитель. Но для чего тогда нужны перечисленные теги?

    <separator> и <toolbarseparator> - пользовательские теги с определенными стилями. Они нужны больше для упрощения оформления, чем для внесения дополнительной функциональности. Они делают то же, что и <spacer>, но у них особая роль, и каждая тема для Mozilla должна предоставлять стили для них. <toolbarseparator> - объект, к которому можно применить стили, появляющийся между кнопками на панели инструментов, а <separator> можно вставлять между панелями инструментов и любым другим обычным содержимым. Наличие этих элементов открывает дополнительные возможности для оформления тем. Они чем-то похожи на <HR> в HTML или прозрачных GIF-изображениях размером 1х1 пиксел. Единственные люди, заинтересованные в этих тегах - дизайнеры тем. Для таких тегов атрибут flex не используется.

    <menuseparator> - то же самое, только для выпадающих меню. Он отображается как прямая вроде <HR>, проходящая поперек меню и разделяющая его на две части. Меню обсуждаются в главе 7, "Формы и меню", и главе 8, "Навигация".

    Из этих элементов выделяется <treeseparator>, который будет описан в главе 13, "Списки и деревья". Как можно понять из имени тега (tree separator - разделитель для деревьев), он относится к деревьям. Не следует использовать <treeseparator> отдельно.

    Наконец, <spring> - тег, который также применяется для упрощения оформления, но только в классическом Компоновщике. Поведение XUL- блоков с атрибутом flex должно искоренить использование объектов <spring>, но в некоторых случаях без них обойтись трудно. Компоновщик - единственный компонент Mozilla, в котором переход на <spacer> еще не завершен. Тега <spring> следует избегать не только потому, что он значительно усложнит разметку, но и потому, что как концепция XUL он более не приветствуется. Если вы считаете, что вам нужен тег <spring> или <strut>, прежде всего, следует прочитать раздел "Отладка" этой главы.

    2.3.3. Стеки и колоды

    Теги XUL можно помещать друг поверх друга, но XUL не поддерживает абсолютное или фиксированное позиционирование CSS 2. Так что размещение поверх других элементов выполняется с помощью техники, использовавшейся еще во времена HyperCard для компьютеров Macintosh в 80-е годы: прямоугольник экрана представляется как самая верхняя карта из колоды игральных карт, в которой все карты расположены рубашкой вниз. XUL-содержимое рисуется на картах и видно, если смотреть на колоду сверху.

    Mozilla поддерживает "колоды" двух типов: <stack> и <deck>. Первые похожи на колоду карт, напечатанных на прозрачной пленке. Вторые - колода карт, напечатанных на обычной бумаге, причем каждый раз видна только одна карта. В обоих случаях длина и ширина колод равны размерам самых больших карт в колоде. Следовательно, изначально у всех карт один и тот же размер, даже если содержимое некоторых из них занимает меньше места. Стандартный размер может быть уменьшен для любой карты, если она позиционируется относительно. В этом случае верхний левый угол карты немного смещается относительно верхнего левого угла остальных карт, а ее размеры уменьшаются на использованное смещение.

    Другими вариантами <stack> и <deck> являются <bulletinboard>, <tabbox> и <wizard>.

    2.3.3.1 Тег <stack>

    В листинге 2.5 показан рабочий пример использования <stack>.

    <stack>
      <image src="spade.gif"/>
      <box style="left:30px; top:30px;">
        <description>Другая карта</description>
      </box>
      <description top="10" left="10">Я карта</description>
    </stack>
    
    Листинг 2.5. Пример использования <stack>.

    XUL-атрибуты left и top по своим свойствам аналогичны left и top CSS 2. Задействовать встроенные стили не рекомендуется, лучше пользоваться отдельной таблицей стилей. Здесь мы применяли встроенные стили, только чтобы проиллюстрировать действие описанной техники. Каждый тег-потомок тега <stack> формирует отдельную карту, так что в итоге у нас три карты. Карты, которые появляются наверху, накрывают карты, лежащие ниже, если их содержимое непрозрачно, как чаще всего и бывает. Последний тег - самая верхняя карта, поэтому при создании стека нужно начинать с самого нижнего слоя содержимого. Самая широкая часть - текст, но самая высокая - изображение, поэтому конечный размер карт будет высотой с изображение и шириной с самую длинную строку текста. На рисунке 2.7 показан результат нашего кода. Для наглядности были использованы некоторые простые стили.

    Использование стека для размещения трех объектов.

    Рис. 2.7.  Использование стека для размещения трех объектов.

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

    Есть и другое ограничение на анимацию: перетасовывать карты в стеке сложно. Их порядок не привязан к свойству CSS 2 z-index, поэтому его нельзя изменить с помощью динамического HTML. То есть одна карта всегда находится поверх других. Две карты не могут менять положение с помощью CSS-стилей, однако это можно сделать с помощью JavaScript и DOM: изменить порядок следования тегов внутри <stack>. Для этого приходится выполнять операции удаления и вставки. Все это требует сложной обработки внутри Mozilla. Оптимальным решением будет повторное использование содержимого тега так, как показано в листинге 2.6.

    <stack>
      <description id="a2">Первая рыба</description>
      <description id="b1">Вторая рыба</description>
      <description id="a1" hidden="true">Первая рыба</description>
    </stack>
    
    Листинг 2.6. Дублирование карт в стеке.

    В этом стеке самый верхний элемент - "Вторая рыба", а под ним находится "Первая рыба". Если видимый тег "Первая рыба" скрыт (hidden="true"), а предыдущий невидимый тег стал видимым, порядок видимых карт в стеке меняется. При использовании этой методики для N элементов требуется NAA-1 тегов, что довольно много уже при N, равном 10 или более. Уменьшить это количество можно, представив, что мы имеем дело с плоскостями, а не с отдельными картами. Каждая карта принадлежит какой-то плоскости. Обычно нужна самая нижняя плоскость (фон), плоскость для основных элементов анимации (космических кораблей и пришельцев), промежуточная плоскость (для бомб и бонусов) и, конечно, плоскость для эффектов (взрывов). С помощью такой системы можно избежать использования всех сочетаний элементов; в худшем случае придется дублировать всего лишь часть анимации. Таким образом, можно контролировать движение с помощью JavaScript, CSS-стилей и в гораздо меньшей степени - DOM 1.

    Если требуется анимировать только один элемент сцены, можно использовать или GIF или сделать эту карту стека также стеком. Вложенные теги <stack> поддерживаются.

    Расширение стиля Mozilla -moz-opacity можно использовать, чтобы сделать содержимое карты стека полупрозрачным. Обычно прозрачна только та часть карты, в которой нет содержимого.

    Атрибут selectedIndex тега <deck> (мы рассмотрим его ниже) не работает со стеками. Если атрибут flex="1" добавить к любому тегу-потомку стека, он также не окажет никакого действия.

    2.3.3.2. Тег <deck>

    Тег <deck> очень похож на <stack>, но в нем в каждый момент времени может быть видимой только одна карта. Все остальные не находятся под ней, они полностью "вытаскиваются" из колоды. Или можно сказать, что они по-прежнему в колоде, но невидимы. Позади видимой карты находится любое содержимое, окружавшее тег <deck>. В листинге 2.7 приведен пример того же содержимого, что и в более раннем примере для <stack>.

    <deck selectedIndex="1">
      <image src="spade.gif"/>
      <box style="left:30px; top:30px;">
        <description>Другая карта</description>
      </box>
        <description top="10" left="10">Я карта</description>
    </deck>
    
    Листинг 2.7. Пример использования <deck>

    В <deck> порядок следования объектов не такой, как в <stack>. Теги-потомки <deck> нумеруются сверху вниз, начиная с нуля. По умолчанию первый непустой элемент находится наверху, так что порядок следования карт в <deck> - обратный порядку следования карт в <stack>. На самом деле <deck> дает меньше возможностей упорядочивания карт, чем <stack>. В <deck> "наверху" находится только одна карта. Индексные номера, данные отдельным картам, выполняют функции идентификаторов. Если значением атрибута selectedIndex является идентификатор несуществующей карты, отображается пустая карта. В листинге 2.7 атрибут selectedIndex используется, чтобы был виден второй непустой тег, а не первый. На рисунке 2.8 показан результат этого кода.

    Использование колоды для размещения трех объектов.

    Рис. 2.8.  Использование колоды для размещения трех объектов.

    Анимация и другие сложные эффекты выполнять с помощью <deck> довольно бессмысленно. Единственное, что можно попытаться сделать - пробежаться по всем картам, меняя значение selectedIndex. При работе с картами маленькой площади это может проходить довольно быстро даже без использования очень мощного компьютера.

    2.3.3.3. Теги <bulletinboard>, <tabbox> и <wizard>

    Когда <stack> был впервые добавлен в Mozilla, относительное позиционирование его потомков еще не поддерживалось. Тогда был придуман элемент <bulletinboard>, поддерживающий атрибуты left, top и стили. Представьте себе пробковую доску, на которую пришпилены бумажки с объявлениями - это доска объявлений (по-английски "bulletin board"). В конце концов, поддержка этих атрибутов и соответствующих стилей была добавлена в <stack>, как уже было сказано выше, так что <bulletinboard> оказался лишним. Он все еще прячется в стандартных таблицах стилей Mozilla, но у него больше нет какого-то особого предназначения. Вместо него следует использовать <stack>, тем более что синтаксис остается таким же.

    Более серьезная проблема возникла с <deck>. Как, работая с ним, пользователю выбирать отдельные карты? Обычный элемент <deck> не дает ответа на этот вопрос, придется добавлять какие-нибудь кнопки или скрипты (или еще что-то в этом роде).

    <tabbox> и <wizard> - сложные XUL-теги, решающие эту проблему: <tabbox> обертывает <deck> так, что до каждой карты колоды можно добраться, один раз щелкнув мышью по пиктограмме. <wizard> обертывает <deck> так, что для перехода между картами можно использовать кнопки "Назад" и "Далее". Оба эти тега автоматизируют процесс выкладывания отдельной карты поверх стопки, чтобы сделать ее видимой.

    <tabbox> обсуждается в главе 8, "Навигация". <wizard> - в главе 17, "Установка приложений". Тег <wizard> обычно служит для того, чтобы дать конечному пользователю возможность установить и настроить дополнительное ПО для браузера Mozilla.

    2.3.4. Таблицы

    При использовании обычного <box> нельзя добиться того, чтобы визуально элементы выравнивались и горизонтально, и вертикально, если только вы не собираетесь задействовать кучу дополнительных тегов. Поэтому <box> сам по себе не эквивалентен табличной верстке HTML. Для организации элементов в двух измерениях в XUL используется тег <grid>. С его помощью можно отображать статические и динамические таблицы, матрицы и т.д. Есть и другие, более специализированные теги: <listbox> и <tree>.

    Таблицу в XUL можно создать с помощью пяти элементов:

    <grid> <columns> <column> <rows> <row>
    

    XUL-документы хранят информацию в иерархическом виде, а иерархические системы - неуклюжий способ представления двумерных структур. Используемый в XUL метод поэтому также уродлив, но свое дело он делает и его даже можно назвать гибким. Таблица - это всего лишь набор блоков <vbox> и <hbox>, расположенных друг поверх друга, плюс некоторая дополнительная поддержка, чтобы сделать это нагромождение? более похожим на таблицу.

    Создание таблицы происходит так: нужно указать все столбцы и все строки и для точки пересечения каждой строки и каждого столбца использовать один непустой тег. Фактически этот тег - ячейка. В нем самом может содержаться какое угодно число XUL-тегов. При этом возникает проблема: куда помещать тег-ячейку: внутрь тегов строк или столбцов? В XUL рабочими будут оба варианта, но первый лучше. При этом неважно, что в коде будет идти сначала: строки или столбцы - важно, где будут ячейки. В листинге 2.8 показан пример таблицы 2х3, реализованный в обоих вариантах.

    <grid>
      <columns>
        <column/>
        <column/>
        <column/>
      </columns>
      <rows>
        <row>
        <description>One</description>
        <description>Two</description>
        <description>Three</description>
      </row>
        <row>
          <description>Four</description>
          <description>Five</description>
          <description>Six</description>
        </row>
      </rows>
    </grid>
    <grid>
      <rows>
      <row/><row/>
    </rows>
      <columns>
        <column>
          <description>One</description>
          <description>Four</description>
        </column>
        <column>
          <description>Two</description>
          <description>Five</description>
        </column>
        <column>
        <description>Three</description>
        <description>Six</description>
        </column>
      </columns>
    </grid>
    
    Листинг 2.8. Два варианта одной таблицы

    Хотя некоторые теги пусты (<column> в первом примере и <row> - во втором), их все равно нужно объявить. Так мы даем системе визуализации знать, каков будет конечный размер таблицы - та же проблема, что и с таблицами в HTML. В XUL нет атрибутов, с помощью которых можно указать размер таблицы. Также у таблиц нет заголовков, названий и прочих подобных признаков. Они так же просты, как и <stack>.

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

    Разные размещения объектов с использованием таблиц.

    Рис. 2.9.  Разные размещения объектов с использованием таблиц.

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

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

    Наконец, можно добавлять содержимое и в строки, и в столбцы. Если это сделать, каждая ячейка будет получать один тег с содержимым внутри <row> и один - внутри <column>. Эта ячейка будет вести себя как двухэлементный стек, причем первый (в порядке следования) элемент будет находиться внизу, под вторым. Это бесполезная функция, если, конечно, нет какой-то специальной цели для ее использования. Если нужен стек в ячейке, следует просто поместить в нее <stack>.

    Основная функция <grid> - размещение элементов графического интерфейса. При частом использовании flex для тегов <column> и <row> таблицы их содержимое само аккуратно разместится в окне. В окне поиска Mozilla (вызывается из меню "Правка") для выравнивания объектов используется таблица.

    Вместо тега <grid> можно применить <listbox> и <tree>, их функциональность описана в главе 13, "Списки и деревья".

    2.4. Улучшение блока: теги <groupbox> и <caption>

    В этой главе была описана основная структура и теги, с которыми работают в XUL. Так о чем же пойдет речь в оставшейся части курса? Дело в том, что основная технология - <box> - усовершенствована огромным количеством способов. Простейший пример - теги <groupbox> и <caption>. Похожий на них тег <radiogroup> описывается в главе 5, "Скрипты".

    <groupbox> и <caption> в XUL - примерно то же, что и <fieldset> с <legend> в HTML. Они позволяют окружить одной границей набор некоторых непустых элементов. Это точно такая же граница, которую можно создать с помощью CSS 2, только в нее может быть встроен заголовок. Цель создания <groupbox> - оформлять элементы визуально. Организовав несколько связанных друг с другом объектов, мы создаем из них один больший объект и упрощаем их восприятие. Они также применяются для идентификации области окна, все элементы которой служат одной цели. Это тоже помогает восприятию. В листинге 2.9 показан пример использования <groupbox>.

    <groupbox>
      <caption image="menu.png" label="Меню на сегодня"/>
      <description>Первое блюдо: кнопочный суп</description>
      <description>Второе блюдо: стейк из кнопок</description>
      <description>Десерт: мороженое с кнопками</description>
    </groupbox>
    
    Листинг 2.9. Пример использования <groupbox>

    Три элемента в этом меню можно было бы расположить лучше, если бы мы использовали больше блоков, например, справа у нас мог быть указан порядок блюд, а слева - их названия. Все содержимое такого типа можно поместить в тег <groupbox>. На рисунке 2.10 показаны результаты.

    Результат использования <groupbox> без применения темы

    Рис. 2.10.  Результат использования <groupbox> без применения темы

    Существует несколько основных правил использования тега <caption>. Если он пуст, его содержимое должно указываться с помощью атрибутов label и/или image. Оба они необязательны. Содержимое, указанное с помощью label, не может быть разметкой XUL, это должен быть обычный текст. Изображение всегда появляется перед текстом, если, конечно, не указан атрибут dir="rtl". Если <caption> - непустой тег, в задаваемом им заголовке может быть любое содержимое. <caption> должен быть первым потомком <groupbox>.

    <caption> можно использовать и отдельно от <groupbox>, хотя оснований для этого немного. Например, если требуется отдельный заголовок, который будет выглядеть так же (с такими же стилями), что и заголовки внутри <groupbox>. Можно также изменить вид заголовка, добавив стандартные атрибуты pack и align.

    Помимо очевидных возможностей использования, <groupbox> вводит еще несколько новых принципов, появляющихся в XUL.

    Во-первых, очевидно, что <groupbox> - уже что-то новое. Никакая очевидная комбинация упоминавшихся выше элементов не может воспроизвести его функциональность. Поэтому <groupbox> должен быть реализован в C/C++-коде. С другой стороны, его очень легко испортить: достаточно добавить атрибуты выравнивания блока (например, pack). Такая хрупкость больше похожа на реализацию с помощью стилей. Истина, как всегда, находится посередине. Основная часть <groupbox> реализована на C/C++, но обработка особых атрибутов выполнена на XBL и содержится в удобном для чтения XML-документе. Многие XUL-теги реализованы похожим образом. XBL описывается в главе 15, "Связи XBL".

    Во-вторых, требование особого порядка содержимого - тоже что-то новое. Первым тегом внутри <groupbox> должен быть <caption>. Это предписание очень часто используется в более сложных тегах XUL и также присутствует в XBL.

    Наконец, на рисунке 2.10 мы видим изображение без темы. Оно не соответствует ни теме Classic, ни теме Modern. Можно не применять стили вообще, но это бессмысленно, так как при использовании тем у вас будет отличный результат с минимальными затратами. Чтобы не применять стили, достаточно просто не указывать одну или две важных таблицы стилей.

    На этом мы закончим обсуждение основных тегов для структурирования данных в XUL. Все, что остается до главе 3, "Статическое содержимое", это прояснить некоторые туманные места и give XUL a spin (складно никак не выходит).

    2.5. Общие атрибуты XUL

    XUL - это приложение XML, похожее на HTML. Неудивительно, что некоторые атрибуты, знакомые нам по HTML, также используются и в XUL.

    • id. XML поддерживает возможность использования идентификатора тегов. В HTML этот атрибут называется id. В XUL он также называется id.style. Встроенные стили в XUL можно указывать так же, как в HTML.
    • class. Как и в HTML, синтаксис CSS позволяет легко применять правила стилей к элементам определенного класса (ко всем элементам одного и того же класса).
    • Обработчики событий. В XUL поддерживается основная часть обработчиков событий DOM вроде onclick. Их очень много, и они описываются в главе 6, "События".

    В XUL предусмотрен собственный набор общих атрибутов, например, flex, debug, height и width, описанные выше. Единственный атрибут, который мы еще не рассмотрели, - persist.

    Этот атрибут применяется в браузере Mozilla, чтобы сохранять информацию о данном XUL-документе. Самый очевидный пример использования атрибута persist - сохранение позиции окна по x и по y на экране: когда оно откроется в следующий раз, оно будет находиться там же, где и ранее. persist можно задействовать для сохранения значения любого атрибута XUL, и эта информация будет доступна и после перезапуска браузера. Она хранится на жестком диске в RDF-файле и загружается при каждом запуске браузера. Все это выполняется автоматически после указания атрибута.

    На самом деле существует множество атрибутов с особым поведением вроде persist. Это, например, observes, command, key, uri и commandupdater. Каждый из них будет рассматриваться в этой книге позже, когда мы продолжим исследование особенностей XUL.

    2.6. Хороший стиль кодирования на XUL

    Разработка XUL-приложений подразумевает создание XML-документов. Лучше всего делать это вручную, так как хороших визуальных редакторов XUL пока еще нет. Очень важно, что здесь недопустима небрежность, которую можно было себе позволить в HTML. В листинге 2.10 показан пример не соответствующего стандартам HTML-кода.

    <HTML><HEAD>
    <STYLE>
    P { font-size : 18pt; }
    </STYLE>
    <SCRIPT>
    function set_case(obj) {
      if (obj.value)
        obj.value = obj.value.toUpperCase();
      return true;
    }
    </SCRIPT>
    </HEAD>
    <BODY BGCOLOR="yellow">
      <P>Enter a name</P>
      <FORM>
        <INPUT TYPE="text" ONCHANGE="set_case(this)">
      </FORM>
    </BODY>
    </HTML>
    
    Листинг 2.10. Плохо структурированный HTML

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

    1. Всегда пользуйтесь XML-синтаксисом. В любом случае в XUL не применяется синтаксис вроде HTML.
    2. Избегайте использования встроенных скриптов. Вынесите все скрипты в отдельный файл .js.
    3. Избегайте применения встроенных таблиц стилей. Вынесите всю информацию о стилях в отдельный файл .css.
    4. Не переусердствуйте в использовании обработчиков событий. Одного обработчика onLoad достаточно. Задействуйте остальные из JavaScript с помощью addEventListener() (как это делается, рассказано в главе 6, "События").
    5. Избегайте использования встроенных стилей. Задавайте все стили с помощью таблицы стилей.
    6. Избегайте обычного текста в XUL-документе. Для этого применяйте сущности, определенные в собственном DTD-файле.

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

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

    <!-- text.dtd -->
    <!ENTITY text.label "Enter a name">
    /* styles.css */
    p { font-size : 18pt; }
    body { background-color : yellow; }
    // scripts.js
    function load_all() {
      document.getElementbyId("txtdata").
      addEventListener("change",set_case,0);
    }
    function set_case(e) {
      if (e.target.value)
        e.target.value = e.target.value.toUpperCase();
      return true;
    }
    <!-- content.html -->
    <?xml version="1.0"?>
    <?xml-stylesheet href="styles.css" type="text/css"?>
    <!DOCTYPE html [
    <!ENTITY % textDTD SYSTEM "text.dtd">
    %textDTD;
    ] >
    <html>
    <head>
      <script src="scripts.js"/>
    </head>
    <body onload="load_all()">
      <p>&text.label;</p>
      <form>
        <input id="txtdata" type="text"/>
      </form>
    </body>
    </html>
    
    Листинг 2.11. Структурированный HTML

    Вместо 18 строк код стал занимать 28 и размещается теперь в четырех файлах, но собственно HTML-разметка занимает только 14 строк, и из них только 8 строк имеет какое-то содержимое. Это очень важный момент: содержимое или вынесено отдельно, или сведено к минимуму. При написании кода на XUL нужно будет поступать именно так.

    Этот пример структурирования показывает, как следует работать с XUL с самого начала. Первый шаг - создать файлы .xul, .css, .js и, возможно, .dtd. Директива <?xml-stylesheet?> - стандартная часть XML, доступная всегда: она чем-то похожа на #include из C. Добавление DTD в HTML обычно не используется, но это очень часто происходит в XUL.

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

    Ловушка XML-синтаксиса связана с терминаторами. И в HTML, и в приложениях Mozilla XML элемент <script> содержит код, обычно на JavaScript. В случае HTML, если этот код по какой-то причине включает строку "</script>", она будет считаться закрывающим тегом. Решение: разбить строку на две части:

    var x = "</scr" + "ipt>";
    

    Эта проблема актуальна для поддержки HTML, XML и XUL в Mozilla.

    Более серьезная проблема связана с использованием операторов && и & в JavaScript. XML- и XUL-документы воспринимают & как начало ссылки на XML-сущность. Это также может привести к неправильному разбору документа. Похожим образом операторы << и < воспринимаются XML и XUL как начало тега.

    В подобных случаях следует использовать литералы CDATA так, как показано в листинге 2.12.

    <script><![CDATA[
    if ( 1 < 2 ) {
      var x = "harmless </script>";
    }
    ]]>
    </script>
    
    Листинг 2.12. Использование литералов CDATA в XML для включения скриптов

    Но и у этого решения есть недостатки. Следующая строка кода может привести к неправильному разбору документа, так как содержит подстроку "]]>":

    if ( a> 0 ) { return; }
    

    При создании приложений Mozilla единственным действительным решением этих проблем может быть только не использовать встроенные скрипты вообще.

    Есть и вторая ловушка, связанная со скриптами в XML. В HTML было особое согласование между HTML и JavaScript. Если первая строка JavaScript-кода начиналась как тег комментария:

    <!--
    

    использовался особый режим обработки, в котором JavaScript-код был доступен интерпретатору. Использование таких комментариев в XUL- или XML-документах приведет к полному сокрытию JavaScript-кода от интерпретатора.

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

    2.7. Альтернатива: таблицы стилей

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

    Эти стили определяют, чем именно является данный тег XUL. К сожалению, эти стили не всегда можно применить к пользовательским элементам вроде <mystack>. В C/C++-коде Mozilla порой встречаются предположения, связывающие имя элемента с характером его отображения. Одной из целей проекта Mozilla является избавление от таких мест, и в версии 1.4 почти все они исчезли. Так как же определить, будет ли тег с именем <mystack> вести себя так же, как и <stack>, если стиль отображения у него -moz-stack? Ответ: попробуйте и узнаете.

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

    Модель визуального форматирования, используемая в Mozilla, местами может быть очень сложной. В XUL, HTML и MathML используется некоторая общая функциональность, и ситуация осложняется наличием режима совместимости для старых версий HTML. В итоге существует несколько стилей, которые "подсказывают" системе стилей, как должен выглядеть тот или иной объект. В чистом XUL и даже в смеси XUL и HTML это последнее средство для решения проблем с размещением объектов. Возможно, вы просто что-то чрезмерно усложняете. Эти расширения стилей описаны в таблице 2.3.

    Как уже упоминалось, CSS 3 все еще находится в разработке, и в Mozilla этот будущий стандарт поддерживается частично. В CSS 3 будет включена модель границ блока из IE 6.0, которую противники Microsoft часто называют "корявой моделью блока". В конечном счете, Mozilla, вероятнее всего, будет ее поддерживать.

    Таблица 2.1. Значения свойства display, соответствующие структурирующим тегам

    Значение CSS-свойства "display:"Эквивалентный XUL-тег
    -moz-box<box>
    -moz-stack<stack>
    -moz-deck<deck>
    -moz-grid<grid>
    -moz-grid-group<columns> или <rows>
    -moz-grid-line<column> или <row>
    -moz-groupbox<groupbox>
    Таблица 2.2. Свойства стилей, соответствующие атрибутам размещения блоков

    Новое CSS-свойствоЭквивалентный XUL-атрибут
    -moz-box-alignalign=
    -moz-box-directiondir=
    -moz-box-orientorient=
    -moz-box-packpack=
    -moz-box-flexуникальное значение flex=
    -moz-box-flex-groupequalsize=
    Таблица 2.3. Расширения стилей - подсказки для системы стилей Mozilla

    СвойствоЗначениеОписание
    -moz-box-sizingborder-box, content-box, padding-boxДает указание системе визуализации, какую часть элемента использовать для вычисления его краев
    -moz-float-edgeborder-box, margin-box, content-box, padding-boxОпределяет, какой внешний ограничитель для перемещаемого элемента должен использоваться при размещении вокруг него остального содержимого

    2.8. Практика: наброски Notetaker

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

    2.8.1. Процесс верстки интерфейса

    Требуемое диалоговое окно должно появляться при нажатии на кнопку Edit на панели инструментов NoteTaker. На рисунке 2.11 показана модель этого диалога.

    Схема диалога

    Рис. 2.11.  Схема диалога

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

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

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

    Схема диалога с направляющими для выравнивания

    Рис. 2.12.  Схема диалога с направляющими для выравнивания

    Пунктирные линии отмечают границы размещения содержимого. Двунаправленные стрелочки показывают, как, по нашему мнению, может растягиваться содержимое. Это не формальная нотация, просто набросок на бумаге. Это что-то вроде разметки, но здесь не нужна формальность. Это всего лишь помогает навести порядок в голове.

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

    Посмотрев на эти registration lines (как их иногда называют), мы можем представить нужные блоки практически без усилий. Блок всего диалога - <vbox>, в котором содержатся три элемента <hbox>. Во втором из них, в свою очередь, находятся еще два <vbox> и т.д. Реализация этих блоков очень проста. В листинге 2.13 показано схематичное размещение объектов окна.

    <vbox>
      <hbox></hbox>
      <hbox>
        <vbox></vbox>
        <vbox>
          <groupbox>
            <caption/>
              <grid>
                <rows><row/><row/></rows>
                <columns>
                  <column></column><column></column>
                </columns>
              </grid>
          </groupbox>
          <groupbox>
            <caption/>
              <grid>
                <rows><row/><row/><row/><row/></rows>
                <columns>
                  <column></column>
                  <column></column>
                  <column></column>
                </columns>
              </grid>
          </groupbox>
        </vbox>
      </hbox>
      <hbox></hbox>
    </vbox>
    
    Листинг 2.13. Разбиение диалога NoteTaker на блоки

    В начале этой главы говорилось о том, как важны блоки для приложений Mozilla. Этот довольно простой пример делает наши выводы очевидными. Добавим несколько правил стиля - толстые границы для блоков, тонкие - для таблиц и элементов <groupbox>. Результат приведен на рисунке 2.13.

    Результат разбиения диалога NoteTaker на блоки

    Рис. 2.13.  Результат разбиения диалога NoteTaker на блоки

    Пока глаз не привыкнет к верстке XUL, в этом нагромождении вы не сразу сможете увидеть необходимое размещение объектов. После того как мы добавим нескольким элементам атрибут flex, все станет иначе. Единственные теги, которым этот атрибут понадобится, расположены в верхней части окна (см. листинг 2.14).

    <vbox flex="1">
      <hbox>
      </hbox>
      <hbox flex="1">
        <vbox flex="1">
    ...
    
    Листинг 2.14. Добавление атрибута flex некоторым блокам

    На рисунке 2.14 показан результат наших изменений.

    Результат разбиения диалога NoteTaker на блоки с атрибутами flex

    Рис. 2.14.  Результат разбиения диалога NoteTaker на блоки с атрибутами flex

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

    Этот простой документ также может быть установлен в chrome и запущен оттуда. Для этого нужно скопировать XUL-файл сюда, если вы в Microsoft Windows:

    C:\Program Files\Mozilla\chrome\notetaker\content\editDialog.xul
    

    или сюда, если вы в UNIX:

    /usr/local/lib/mozilla-1.7/chrome/notetaker/content/editDialog.xul
    

    Теперь этот файл можно просматривать, обратившись к нему через URL chrome://notetaker/content/editDialog.xul, если вы выполнили инструкции, описанные в разделе "Практика" первой главы, "Основные концепции". Сейчас, если нам нужно, мы можем открыть отдельное окно приложения, указав в командной строке параметр -chrome. Мы можем просмотреть этот URL и в обычном окне браузера.

    2.8.2. Завершение регистрации

    Мы зарегистрировали NoteTaker в главе 1, "Основные концепции", как имя пакета, но мы не зарегистрировали этот пакет в реестре Mozilla chrome. Данный реестр, описанный более подробно в главе 12, "Оверлеи и chrome", позволяет нашему приложению пользоваться темами, языковыми настройками и оверлеями. Сейчас нам все это не нужно, но рано или поздно перечисленные функции понадобятся, так что мы должны быть готовы. Сейчас при редактировании XUL-документов нам придется в то же время редактировать и RDF-файл.

    Если мы хотим использовать реестр chrome, нужен дополнительный файл contents.rdf. Его требуется поместить в этот подкаталог:

    chrome/notetaker/content/contents.rdf
    

    Этот путь частично совпадает с путем, добавляемым нами в файл installed-chrome.txt (см. лекцию 1, "Основные концепции"). Этот файл - XML-документ, содержащий RDF-ntub. RDF обсуждается, начиная с главе 11, "RDF".

    Все, что должно быть в этом файле для регистрации компонента NoteTaker в реестре chrome, приведено в листинге 2.15.

    <?xml version="1.0"?>
    <RDF:RDF
      xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
      <RDF:Seq about="urn:mozilla:package:root">
        <RDF:li resource="urn:mozilla:package:notetaker"/>
      </RDF:Seq>
      <RDF:Description about="urn:mozilla:package:notetaker"
        chrome:displayName="NoteTaker"
        chrome:author="Nigel McFarlane"
        chrome:name="notetaker">
      </RDF:Description>
    </RDF:RDF>
    
    Листинг 2.15. Файл contents.rdf, необходимый для регистрации расширения NoteTaker

    Тег <Seq> добавляет NoteTaker к списку расширений; <Description> добавляет запись с административной информацией. Это стандартная форма записи, ее можно использовать и для других расширений - нужно просто заменить слово "notetaker" везде в этом файле на соответствующее имя расширения.

    Чтобы это изменение вступило в силу, необходимо сохранить файл installed-chrome.txt еще раз так, чтобы дата его последнего изменения стала текущей. При следующем запуске платформы реестр chrome прочитает наш файл contents.rdf, но пока что ничего особенного этот файл не делает: он просто сообщает о том, что расширение NoteTaker существует.

    2.9. Отладка: обнаружение ошибок в XUL

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

    Большую часть полезных программисту инструментов можно найти в меню "Инструменты" | "Web-разработки".

    Отличный способ запускать Mozilla и в Linux, и в Windows - из командной строки. Это особенно удобно при загрузке документов в собственные окна с помощью параметра -chromе, потому что журнал команд позволяет обновлять окно документа всего лишь парой нажатий клавиш. Цикл тестирование-отладка-исправление особенно удобен для XUL, так как это интерпретируемый язык, а быстрая работа с клавиатурой избавит вас от бессмысленной возни.

    Чтобы работать с командной строкой DOS в более ранних версиях Microsoft Windows, понадобится программа doskey. doskey позволяет вести журнал команд и доступна для всех старых версий Windows: в последних версиях эта функциональность встроена в обработчик команд. Следует отредактировать файл C:\autoexec.bat, добавив в него строку "doskey". При желании это можно сделать и в графическом интерфейсе, хотя нужный алгоритм может немного отличаться от указанного здесь: это зависит от версии ОС и установленных инструментов. Выберите Пуск | Программы | Стандартные | System Tools | System Information (Start | Programs | Accessories | System Tools | System Information). В открывшемся окне выберите Tools | System Configuration Utility (Tools | System Configuration Utility). Выберите вкладку autoexec.bat, нажмите New и введите doskey. А теперь нажмите OK и скептически покачайте головой.

    В UNIX-системах практически все командные оболочки, в частности и bash, сохраняют последовательность вводимых команд после того, как вы добавите команду set -o vi или set -o emacs в файл ~/.bash_profile. Тогда вам станут доступны клавиши быстрого доступа vi или Emacs соответственно (подробнее см. man-страницы readline(3) или bash(1)).

    2.9.1. Предупреждения и их отсутствие

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

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

    Основное сообщение об ошибке

    Рис. 2.15.  Основное сообщение об ошибке

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

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

    • имя тега, атрибута или значение атрибута неизвестны;
    • селектор, свойство или значение свойства стиля неизвестны;
    • значение атрибута id не уникально;
    • свойство стиля встретилось в одном правиле более одного раза;
    • указанное значение атрибута или атрибут неприменимы к данному тегу;
    • тег не может содержать данные такого типа.

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

    2.9.2. Атрибут debug, пружинки и распорки

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

    <hbox flex="1" debug="true">
      <box flex="1"><text value="One"/></box>
      <box><text value="Two"/></box>
    </hbox>
    <vbox debug="true">
      <box flex="1" debug="true"><text value="One"/></box>
      <box><text value="One"/></box>
    </vbox>
    
    Листинг 2.16. XUL-теги с атрибутом debug

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

    XUL-документ с пружинками и распорками для блоков с атрибутом debug

    Рис. 2.16.  XUL-документ с пружинками и распорками для блоков с атрибутом debug

    Этот снимок увеличен в два раза, чтобы можно было различить мелкие детали отладочных подсказок. Прямоугольник с толстой границей сверху - <hbox debug="true">. Прямоугольник с толстой границей слева - <vbox debug="true">. Из предыдущего листинга видно, что атрибут debug наследуется, так как у прямоугольников внутри тега <hbox> тоже есть характерные границы, но сам атрибут для них не указан. Содержимое толстой границы дает дополнительную подсказку о характере размещения объектов.

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

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

    Эту информацию можно использовать, чтобы ответить на вопрос: какой тег занимает свободное место? Чтобы понять, как это сделать, посмотрим еще раз на наш пример. У <hbox> в верхней части окна есть одна пружинка и одна распорка. Следовательно, первый <box> внутри - переменной длины, а второй - нет. Проверив код, мы убедимся, что это так. Глядя на первый прямоугольник, мы видим, что его размер изменился, так как его содержимое обозначается распоркой, но она короче пружинки на внешнем прямоугольнике. Область справа от распорки - свободное место, которое было занято тегом. Оно увеличивается или уменьшается в соответствии с размерами окна.

    Обратите внимание, что для <hbox> в направлении, перпендикулярном основному, нет никаких подсказок. Это так, потому что обычно блоки всегда могут растягиваться в этом направлении.

    Информацию, полученную с помощью debug, можно использовать и для ответа на такой вопрос: почему размеры этого блока не изменились? В нашем примере внутри <vbox> в нижней части окна есть один блок с переменными размерами и один - с фиксированными. Это также соответствует коду. Если бы внутри <vbox> находились другие теги <vbox>, ситуация была бы аналогичной предыдущей, с <hbox>. Исследовав прилегающие границы, вы увидите, что свободное место не разделяется между внутренними блоками, вне зависимости от размеров окна. Другими словами, у внешнего блока должен быть атрибут flex, но его нет. Этот вывод также соответствует коду, но так его делать гораздо проще.

    Случай с <vbox> на самом деле более сложен, так как его содержимое - не <vbox>. Вместо этого в нашем примере используется <hbox> (по умолчанию <box> эквивалентен <hbox>). Поэтому у нас нет соответствующих подсказок, но мы можем пользоваться упомянутым ранее правилом: блоки всегда могут растягиваться в направлении, перпендикулярном основному. Следовательно, оба контейнера должны растягиваться по направлению <vbox>, независимо от того, что говорят распорки и пружинки. Так как при увеличении размеров окна этого не происходит, можно снова сделать вывод, что у <vbox> нет атрибута flex.

    Принцип пружинок и распорок - основной для любых графических интерфейсов, где можно менять размеры каких-либо объектов. В большинстве систем графического интерфейса есть что-то подобное. Автоматическое увеличение занимаемого XUL- и HTML-тегами места - по- настоящему система управления этими пружинками-распорками. Вам не нужно беспокоиться о том, что они из собой представляют на более низком уровне, потому что "умная" система размещения объектов сделает всю работу самостоятельно. Вот почему теги <spring> и <strut> - шаг назад. Используйте вместо них автоматическое размещение.

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

    2.10. Итоги

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

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

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

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


    об авторе

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





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