Часть 3. Структурируем тулбар

Практически все расширения для FF пишутся на языке XUL (произносится как "zool"), языке разметки для написания пользовательских интерфейсов (XUL = XML User Interface Language — язык пользовательских интерфейсов XML). Красота XUL — это так называемые "динамические надстройки" (dynamic overlays). За счет них можно изменять поведения интерфейса окна, не внося изменений в исходники этого интерфейса. Таковая возможность не может не радовать, поскольку позволяет сосредоточиться на наших собственных кодов, избавляя нас от необходимости очередной раз изобретать велосипед.

В этом разделе мы рассмотрим XUL-разметку, которая нам понадобится для создания тулбара. Помните, что XUL — это всего лишь средство построения структуры нашего тулбара. Другими словами, это не то, что позволит "оживить" его. А для того, чтоб реализовать всю функциональность нашего расширения, мы будем использовать JavaScript, но об этом — в следующих сериях.

(Здесь и далее я буду использовать слово "надстройка" везде, где встречается "overlay". Буквально — это некий "верхний слой", т.е. нечто, "перекрывающее" функциональность браузера по умолчанию. Я решил, что "надстройка" подойдет. Может это и недопустимая вольность, однако "оверлей" выглядит просто идиотски, так что пусть идет в газенваген. Я не прав?... — прим.пер.).

Наш первый XUL-файл будет использован для создания надстройки браузера. Мы расположим его в папке content — там же, где лежит contents.rdf. Обычно этот файл называется так же, как и все расширение, в нашем случае — gbltutorial.xul. Структура папок теперь выглядит так:

+- GBLTutorial/
   +- install.rdf
   +- chrome/
      +- content/
         +- contents.rdf
         +- gbltutorial.xul

Поскольку XUL-файл в сущности своей является XML, надо дать соответсвующее объявление в первой строчке:

<?xml version="1.0"?>

Далее, создаем саму надстройку. Для этого добавляем элемент overlay, который будет корневым для нашего файла:

<overlay id="GBLTut-Overlay"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
</overlay>

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

Второй атрибут, xmlns, определяет пространство имен, которое я буду испольвозать в надстройке. Представленное значение — это URL пространства имен, который никогда не изменится. То есть, всегда используйте это значение.

Отдохнем, сходим пописать и налить еще кофя (какой кодер без кофя, да?). Рекламная пауза =)

Закажите web сайт с flash и приходите.
этажный стеллаж, консольные стеллажи

Тулбокс и Тулбар

Все тулбары для FF должны располагаться внутри так называемого тулбокса (toolbox). Элемент toolbox — просто контейнер для тулбаров, и должен располагаться внутри элемента overlay, который мы только что создали. Выглядит он так:

<toolbox id="navigator-toolbox">
</toolbox>

Опять мы видим атрибут id в действии. На этот раз, однако, представлено специальное значение "navigator-toolbar". Оно представляет тулбокс, содержащий панель меню Firefox, панель навигации и панель закладок. Указывая на этот конкретный тулбокс, мы располагаем наш тулбар в этой славной компании прочих тулбаров, как нам и хотелось. Все созданные вами тулбары должны использовать этот специальный ID для элемента toolbox. Не единой совместимости ради, но также для того, чтоб нахаляву добавить наше детище в меню Вид -> Панели инструментов (что позволит его быстро прятать-показывать). Круто, да?

Следующим действием мы добавляем элемент toolbar, располагая его в только что созданном toolbox. Пишем:

<toolbar id="GBLTut-Toolbar" accesskey="T" class="chromeclass-toolbar"
         context="toolbar-context-menu" toolbarname="GBL Tutorial Toolbar"
         hidden="false" persist="hidden">
</toolbar>

У нас появилось несколько новых атрибутов, давайте изучим их более престрастно:

Более подробное описание атрибутов элемента toolbar вы найдете на XUL Planet.

Давайте остановимся и взглянем, что у нас получилось на данный момент: [XUL, Вариант 1]

Кнопки тулбара

Есть три типа кнопок, которые мы можем помещать на нашем тулбаре: обычные кнопки, кнопки меню и кнопки "кнопока-меню" (buttom-menu buttons — какая ересь! — прим. пер.)). Давайте взглянем на каждый тип отдельно. И помните, что все это добро нужно класть внутрь элемента toolbar, который мы давеча создали.

Обычные кнопки

Обычные кнопки — это просто: стандартные кнопки меню, кнопки как кнопки, ничего особенного. Разметка такова:

<toolbarbutton id="GBLTut-TB-Web" tooltiptext="Search the Web"
        label="Web Search" 
        oncommand="GBLTut_Search(event, 'web')" />

Как видите, что создать обычную кнопку, надо использовать элемент toolbarbutton. Исследуем новые атрибуты:

Более полное описание атрибутов элемента toolbarbutton вы найдете на XUL Planet.

Кнопки меню

Второй доступный тип кнопок — это кнопки меню. Кнопки такого типа отображают выпадающее меню, когда на них нажимают. Разметка для создания таких кнопок во многом похожа на то, что мы уже видели. Однако, мы добавляем вложенный элемент menupopup. Дабы не раздувать размер кода, нижеприведенный пример содержит лишь 2 пункта меню.

<toolbarbutton id="GBLTut-MainMenu" type="menu"
               tooltiptext="GBL Tutorial Toolbar Main Menu">
  <menupopup>
    <menuitem label="Google Home Page" accesskey="G"
              tooltiptext="Browse to the Google home page"
              oncommand="GBLTut_LoadURL('http://www.google.com/')" />
    <menuseparator />
    <menuitem label="Born Geek Website" accesskey="B"
              tooltiptext="Visit the Born Geek website"
              oncommand="GBLTut_LoadURL('http://www.borngeek.com/')" />
  </menupopup>
</toolbarbutton>

Заметьте, в атрибутах элемента toolbarbutton произошло 2 важных изменения. Первое — появился новый атрибут type, которому в нашем примере присвоили значение "menu". Второе — отсутствует атрибут oncommand. Поскольку теперь наша кнопка лишь отображает меню, нам не надо, чтоб она исполняла какой-то код.

Кроме того, мы добавили некоторую разметку между тегами элемента toolbarbutton. Обратите внимание на новые элементы menupopup, menuitem и menuseparator. Элемент menupopup отвечает за создание и отображение всплывающего окна со всеми пунктами меню (считайте его контейнером, в котором расположены все элементы menuitem). Элемент menuseparator так же прост: он всего лишь помещает горизонтальный разделитель в выпадающее меню.

Элемент menuitem немного сложнее. Вот новые атрибуты, обозначенные в примере:

Подробнее об атрибутах элемента menuitem читайте на XUL Planet Как видите, в создании кнопок меню нет ничего сложного. Обратим свой взор к третьему, более сложному, типу кнопок.

Кнопки "кнопка-меню"

Кнопки "кнопка-меню" — это именно то, о чем вы могли подумать: кнопки тулбара, которые ведут себя и как кнопки, и как меню. Кнопки навигации "Вперед" и "Назад" в FF как раз относятся к кнопкам этого типа. Реализовать это не так уж сложно:

<toolbarbutton id="GBLTut-TB-Combined" label="Search"
     type="menu-button" tooltiptext="Combined Search Menu"
     oncommand="GBLTut_Search(event, 'web')">
 <menupopup>
   <menuitem id="GBLTut-TB-Combined-Web" label="Web Search"
     class="menuitem-iconic" tooltiptext="Search the Web"
     oncommand="GBLTut_Search(event, 'web'); event.preventBubble();" />

   <menuitem id="GBLTut-TB-Combined-Image" label="Image Search"
     class="menuitem-iconic" tooltiptext="Search Images"
     oncommand="GBLTut_Search(event, 'image'); event.preventBubble();" />
 </menupopup>
</toolbarbutton>

Эта кнопка меню представляет собой комбинацию двух предыдущих типов, и включает одно значительное изменение: атрибут type принимает значение "menu-button". Так, вы заметите, что этот элемент включает атрибут oncommand (как обычная кнопка), также как и вложенные элементы menupopup и menuitem (как кнопка меню). Все остальное должно само себя объяснять. Вы, возможно, заметили дополнительный код в атрибуте oncommand каждого элемента menuitem. Причины его появления обсудим в разделе про скрипты.

Теперь, когда мы добавили несколько кнопок на наш тулбар, давайте взглянем на наш XUL еще раз: [XUL, Вариант 2]

Единственное отличие от конечного варианта — в порядке расположения кнопок. В конечном варианте сначала идет кнопка меню, потом кнопка "кнопка-меню", а потом просто кнопка. Такое решение принято исключительно из соображений стилевого оформления.

Выпадающее поле ввода

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

<toolbaritem id="GBLTut-SearchTerms-TBItem" persist="width">
<menulist id="GBLTut-SearchTerms" editable="true" flex="1"
          minwidth="100" width="250"
          onkeypress="if(event.which == 13) { GBLTut_Search(event, 'web'); }">
  <menupopup id="GBLTut-SearchTermsMenu" onpopupshowing="GBLTut_Populate()" />
</menulist>
</toolbaritem>

Мы начинаем с элемента toolbaritem. Присваиваем ему ID и просим FF запомнить его ширину, используя атрибут persist. Элемент toolbaritem нужен, чтоб выделять объекты, не являющиеся кнопками (в нашем случае — поле ввода).

Внутри элемента toolbaritem находится элемент menulist, который, собственно, и делает то, что нам надо. В этом примере употребляется несколько новых атрибутов:

Более подробное описание атрибутов элемента menulist ищите на XUL Planet.

Наконец, внутри элемента menulist располагается элемент menupopup. Как и в случае с кнопками меню, это контейнер, который в итоге будет содержать все элементы menuitem. Событие onpopupshowing случается непосредственно перед тем, как пользователю будет показано низпадающее меню. Далее в этом руководстве мы научимся динамически наполнять это меню. Если вы хотите расположить здесь статически какие-то пункты меню, просто добавьте их так же, как мы это делали с кнопками меню.

Теперь еще раз остановимся и взгланем на наш XUL: [XUL, Вариант 3]. Обратите внимание, что я расположил поле ввода между кнопкой главного меню и кнопкой комбинированного поиска — опять же, чисто дизайнерское решение. Наше расширение начинает преобретать форму!

Resizing Gripper

(элемент интерфейса для изменения размера поля ввода =) — прим.пер.)

Теперь мы добавим "resizing gripper", с помощью которого пользователь сможет изменять размер поля ввода. Это делается так:

<splitter id="GBLTut-ResizeSplitter" state="open" collapse="none"
          resizebefore="closest" resizeafter="farthest"
          tooltiptext="Resize the Search Box" />

("Splitter" — это что-то вроде бегунка, этот самый "resizing gripper". Будем называть его просто "сплиттер" — прим.пер.).

Вот список атрибутов элемента splitter, которые мы использовали в вышеприведенном примере (кроме тех, с которыми уже разобрались):

Подробнее об атрибутах элемнта splitter — XUL Planet.

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

<toolbaritem flex="0">
</toolbaritem>

Мы хотим, чтоб этот элемент окружал наши поисковые кнопки (кнопки "кнопка-меню" и обычную кнопку). Так что располагаем открывающий тег перед разметкой для кнопки "кнопка-меню", а закрывающий — после разметки для обычной кнопки. В результате получаем следующий код: [XUL, Вариант 4]

Дабы избавиться от раздражающих проблем косметического плана с resizing gripper-ом, нужно поместить еще один элемент toolbaritem вокруг нашего первого toolbaritem-а (в нашем случае, кнопки меню). Это предотвратит выталкивание кнопки меню с левой стороны тулбара, когда gripper перетаскивается совсем влево. Раз уж мы добавляем этот элемент, давайте пойдем дальше и добавим еще парочку. Во-первых, вставим элемент toolbarseparator между двумя последними кнопками (из косметических соображений). Во-вторых, расположим элемент toolbarspring прямо после последнего элемента toolbaritem. Это позволит нам перетаскивать ресайзер вправо до конца. Разметка проста до безобразия:

<toolbarseparator />
<toolbarspring />

После внесения всех этих изменений, конечный XUL будет выглядеть следующим образом: [XUL, Вариант 5]. Это наше расширение приобретает форму, внатуре!