Опубликован: 10.12.2007 | Доступ: свободный | Студентов: 822 / 20 | Оценка: 5.00 / 5.00 | Длительность: 58:33:00
Лекция 2:

Верстка с XUL

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> обсуждается в "Навигация" , "Навигация". <wizard> - в "Система распространения и установки - XPInstall" , "Установка приложений". Тег <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>, их функциональность описана в "Списки и Деревья" , "Списки и деревья".