Создание тулбара для Mozilla FireFox - часть 6

Posted by admin on September 2nd, 2008 — Posted in Программирование, Тулбары

Упаковываем тулбар

Для того, чтобы установить расширение в Firefox, мы должны сначала упаковать все файлы расширения. Всего нам понадобится создать 2 архива: JAR-файл и XPI-файл (кроссплатформенный инсталлятор). Не позволяйте расширениям .jar и .xpi себя одурачить: оба файла — это простые zip-архивы. Соответственно, нам понадобится какой-нибудь zip-архиватор, подойдет любой, желательно чтоб у него была поддержка командной строки.

Создаем JAR файл

Первый архив, который мы создадим — это JAR-файл расширения. Он будет содержать все наши XUL-файлы, файлы JavaScript, таблицы стилей CSS и картинки. Помните, что нужно назвать этот файл тем именем, которое вы использовали в декларации установки в разделе 2. В нашем примере это “gbltutorial.jar” (в нижнем регистре, без пробелов). Этот файл создается в директории chrome:

+- GBLTutorial/
   +- install.rdf
   +- chrome/
      +- gbltutorial.jar
      +- content/
         +- contents.rdf
         +- gbltutorial.xul
         +- gbltutorial.js
      +- skin/
         +- contents.rdf
         +- tut_main.gif
         +- tut_combined.gif
         +- tut_web.gif
         +- tut_image.gif
         +- tut_overlay.css

Создайте новый zip архив и добавьте в него все содержимое папки chrome. Важно, чтоб относительные пути сохранились, то есть, содержимое архива должно выглядеть вот так:

+- content/
   +- contents.rdf
   +- gbltutorial.xul
   +- gbltutorial.js
+- skin/
   +- contents.rdf
   +- tut_main.gif
   +- tut_combined.gif
   +- tut_web.gif
   +- tut_image.gif
   +- tut_overlay.css

А теперь просто поменяйте расширение с .zip на .jar.

Создаем XPI файл

Второй архив, который мы создадим — это кроссплатформенный инсталлятор. Как и JAR файл, это не более, чем zip-архив. Этот файл будет содержать созданный нами JAR-файл и декларацию установки (install.rdf). Он должен располагаться в верхней папке нашего расширения:

+- GBLTutorial/
   +- gbltutorial.xpi
   +- install.rdf
   +- chrome/
      +- gbltutorial.jar
      +- content/
         +- contents.rdf
         +- gbltutorial.xul
         +- gbltutorial.js
      +- skin/
         +- contents.rdf
         +- tut_main.gif
         +- tut_combined.gif
         +- tut_web.gif
         +- tut_image.gif
         +- tut_overlay.css

Создаем новый zip, помещаем туда jar-файл и install.rdf, меняем расширение на .xpi. Вот структура XPI-файла:

+- install.rdf
+- chrome/
   +- gbltutorial.jar

Устанавливаем наш тулбар

Теперь все готово для установки расширения. Запускам FireFox, выбираем Файл -> Открыть файл… (или просто жмем Ctrl+O). Находим нах XPI-файл и выбираем его. Если вы сделали все верно, появится установщик расширения. Устанавливаем, закрываем браузер, запускаем снова, любуемся нашим творением. Поздравляю, вы создали свое первое расширение для FireFox!

Тестирование и отладка тулбара

Что делать, если FireFox сломался?

Однажды с вашим расширением может случиться такая серьезная ошибка, в результате которой FireFox откажется работать. Если такое произойдет, сперва проверьте, что процесс firefox запущен и “висит”. Если так, просто убейте этот процесс. После того, как процесс остановлен, запустите Firefox в безопасном режиме. Есть несколько способов сделать это:

  • Использовать ярлык “Запустить Firefox в безопасном режиме”, созданный при установке браузера. В Windows XP он расположен в Пуск -> Все программы -> Mozilla Firefox -> Mozilla Firefox (Safe Mode)
  • Добавить параметр -safe-mode к уже существующему ярлыку FireFox
  • Я делаю проще — жмем виндовая кнопка + R (или Пуск -> Выполнить…) и вводим команду firefox.exe -safe-mode. ИМХО так проще и быстрее —

В безопасном режиме FireFox загрузится без расширений и тем. Раз FireFox запустился, теперь вы можете открыть Инструменты -> Расширения и удалить свое сглючившее расширение. После перезапуска браузера все должно быть нормально.

Ведение лога в консоли JavaScript

Один удобный способ тестировать JavaScript код — выводить отладочные значения в консоль JavaScript, которая доступна через Инструменты -> Консоль JavaScript. Для этого нужно получить доступ к экземпляру nsIConsoleService интерфейса. Используйте следующий код:

const GBLTut_ConsoleService =
      Components.
          classes['@mozilla.org/consoleservice;1'].
              getService(Components.interfaces.nsIConsoleService);

Обратите внимание, что я добавил префикс “GBLTut_” к имени переменной, как делал ранее с именами функций. Поскольку имена функций и переменных доступны из глобальной области видимости, они должны быть уникальными, чтобы не конфликтовать с другими расширениями. Соответственно, в своем расширении используйте в качестве префикса несколько букв имени вашего расширения. Так вот. Получив доступ к интерфейсу консоли, мы можем посылать в консоль сообщения. Следующая функция сделает все за нас:

function GBLTut_Log(aMessage)
{
    GBLTut_ConsoleService.logStringMessage('My_Extension: ' + aMessage);
}

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

GBLTut_Log("The value of the URL variable is: " + URL);

ВСЁ!

No Comments »

Создание тулбара для Mozilla FireFox - часть 5

Posted by admin on September 2nd, 2008 — Posted in Программирование, Тулбары

Создаем скин для тулбара

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

Обновляем структуру файлов

Для начала мы должны создать папку, в которой будут храниться все файлы, относящиеся к скину. Эту папку нужно назвать skin и поместить в папку chrome. Теперь дерево файлов выглядит так:

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

Убедитесь, что папка skin находится на том же уровне, что и папка content. Теперь, когда мы имеем папку для хранения файлов скина, нужно отметить (… эй, на седьмом ряду с портвейном! наливай! — прим. пер.)… нет, зарегистрировать этот факт в декларации установки (install manifest).

Обновляем декларацию установки

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

<em:file>
  <Description about="urn:mozilla:extension:file:gbltutorial.jar">
    <em:package>content/</em:package>
  </Description>
</em:file>

Единственный путь, зарегистрированный в этом примере — папка content. Для того, чтоб использовать созданную папку skin, ее нужно тоже зарегистрировать, вот так:

<em:file>
  <Description about="urn:mozilla:extension:file:gbltutorial.jar">
    <em:package>content/</em:package>
    <em:skin>skin/</em:skin>
  </Description>
</em:file>

На этот раз, вместо элемента em:package мы используем em:skin. Не забудьте прямой слэш после слова skin — он указывает, что речь идет о папке, а не о файле.

Второй файл contents

Дальше нам надо создать файл contents для папки skin (как мы это уже делали для папки content во втором разделе). Соответственно, делаем файл contents.rdf в папке skin. Файл имеет следующее содержание:

<?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:skin:root">
      <RDF:li resource="urn:mozilla:skin:classic/1.0" />
   </RDF:Seq>

   <RDF:Description about="urn:mozilla:skin:classic/1.0">
      <chrome:packages>
         <RDF:Seq about="urn:mozilla:skin:classic/1.0:packages">
            <RDF:li resource="urn:mozilla:skin:classic/1.0:gbltutorial" />
         </RDF:Seq>
      </chrome:packages>
   </RDF:Description>

</RDF:RDF>

Синтаксис для этого файла тот же, что и для файла contents.rdf из раздела 2, так что не будем повторяться. Нам нужно только добавить имя нашей сборки (package) после “classic/1.0” — и можно приступать к созданию стилей для тулбара.

Добавляем картинки

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

  • Картинка 1 (tut_main.gif): кнопка главного меню
  • Картинка 2 (tut_combined.gif): кнопка комбинированного поиска
  • Картинка 3 (tut_web.gif): Кнопка простого веб-поиска
  • Картинка 4 (tut_image.gif): Кнопка поиска по картинкам

Все эти картинки мы складываем в папку skin.

Применяем изображения при помощи CSS

Теперь нужно добавить изображения к нашим кнопкам. Для этого мы воспользуемся каскадными таблицами стилей (CSS) — замечательной технологией, применяемой для хранения информации о стилях. Если вы не знакомы с CSS, очень рекомендую почитать W3Schools’ CSS Tutorial — он научит всем тонкостям этого великолепного механизма описания стилей.

Как и все предыдущие файлы (за вычетом картинок, разумеется), файл CSS — это простой текстовый файл. Все файлы CSS мы будем хранить в папке skin, вместе с картинками. Давайте придумаем простое имя для нашего CSS файла, например tut_overlay.css, и посмотрим, как выглядит дерево файлов на данном этапе работы:

+- GBLTutorial/
   +- install.rdf
   +- chrome/
      +- content/
         +- contents.rdf
         +- gbltutorial.xul
         +- gbltutorial.js
      +- skin/
         +- contents.rdf
         +- tut_main.gif
         +- tut_combined.gif
         +- tut_web.gif
         +- tut_image.gif
         +- tut_overlay.css

Перед тем, как я начну объяснять что-либо про этот файл, взгляните на его содержание:

#GBLTut-MainMenu {
    list-style-image: url("chrome://gbltutorial/skin/tut_main.gif");
}

#GBLTut-TB-Web,
#GBLTut-TB-Combined-Web {
    list-style-image: url("chrome://gbltutorial/skin/tut_web.gif");
}

#GBLTut-TB-Combined-Image {
    list-style-image: url("chrome://gbltutorial/skin/tut_image.gif");
}

#GBLTut-TB-Combined {
    list-style-image: url("chrome://gbltutorial/skin/tut_combined.gif");
}

#GBLTut-TB-Combined > .toolbarbutton-menubutton-button {
    -moz-box-orient: horizontal;
}

Тут все как обычно просто. Вспомните раздел 3: создавая кнопки тулбара, мы назначали им ID — “GBLTut-MainMenu“, “GBLTut-TB-Web” и так далее. Соответственно, в таблице стилей мы используем селекторы ID (таким селекторам предшествует знак #решетки), чтоб обозначить правило для каждого элемента. Обратите внимание, что второе правило применяется к двум элементам, их ID разделены запятыми.

Чтоб установить каждое изображение, мы используем свойство CSS list-style-type. В этом свойстве мы указываем chrome-путь до картинк, которая нам нужна. Например, в правиле для кнопки “GBLTut_MainMenu” мы передаем chrome-путь до файла tut_main.gif. Напомню, как задается chrome-путь:

chrome://<packagename>/skin/<image_filename>

Приведенные выше правила сразу добавят картинки для элементов toolbarbutton. А вот элементы menuitem не такие сговорчивые. Сначала надо сообщить Firefox’у, к каким пунктам меню мы хотим добавить иконки. Помните загадочный атрибут class, который мы использовали в одном из элементов menuitem в разделе 3?

class="menuitem-iconic"

Этот атрибут указывает FireFox’у, какой класс CSS мы хотим применить для этого конкретного пункта меню. Вы наверно заметили, что в нашем CSS нигде не упомянут класс “menuitem-iconic“. Конечно, мы можем создавать собственные классы, но в данном случае мы используем встроенный класс Firefox. Класс “menuitem-iconic” позволяет связывать иконку с пунктом меню — как раз то, что нам нужно.

Последнее правило в приведенной выше таблице стилей устанавливает свойство -moz-box-orient в “horizontal“. Благодаря этому правилу, у кнопок “кнопка-меню” текстовый лэйбл будет располагаться справа от картинки, а не под ней. Вам оно может и не понадобится, но вообще — не повредит использовать это свойство для всех кнопок “кнопка-меню”.

Обратите внимание, что для элементов тулбара может использоваться любое допустимое свойство CSS. Можно изменять отступы, границы, цвета фона и текста, и вообще все, что угодно. Единственная хитрость относится к элементу toolbarbutton: имейте ввиду, что для управления внешним видом такой кнопки (кроме простого добавления картинки, как в нашем примере), вы должны включить следующее правило в свою таблицу стилей:

-moz-appearance: none;

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

Таблицу стилей мы создали, теперь надо сообщить об этом XUL файлу.

Применяем таблицу стилей

Для этого нам понадобится разместить в XUL файле (gbltutorial.xul) всего лишь одну строчку кода. Она должна располагаться прямо перед объявлением директивы XML:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://gbltutorial/skin/tut_overlay.css"
                 type="text/css"?>

Эта строка указывает chrome-путь до нашего CSS-файла. Атрибут type просто сообщает обработчику, что файл, на который мы ссылаемся — это CSS. В результате таблица стилей станет доступна нашему расширению, и ее правила будут применены к соответствующим элементам.

No Comments »

Создание тулбара для Mozilla FireFox - часть 4

Posted by admin on September 2nd, 2008 — Posted in Программирование, Тулбары

Создание скриптов. JavaScript. - 2

Единственное, о чем мы не сказали — как заставить каждый пункт меню выполнять какой-то код, будучи выбранным. Это делаеся очень просто: еще раз вызываем функцию setAttribute(), передаем ей событие и код, который хотим с ним связать. Вот пример для события oncommand:

tempItem.setAttribute("oncommand", "GBLTut_SomeFunction()");

Вот и все, что нужно для динамического заполнения меню! Штука очень полезная и легко реализуемая.

Динамически добавляем кнопки тулбара

(Эта тема не включена в код учебного тулбара)

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

<toolbaritem id="GBLTut-DynButtonContainer" />

Теперь можно добавить элементы toolbarbutton при помощи такой вот функции (в этом примере мы добавим 5 кнопок, так же, как сделали это с пунктами меню):

function GBLTut_AddDynamicButtons() {
    var container = document.getElementById("GBLTut-DynButtonContainer");

    for(i=container.childNodes.length; i > 0; i--) {
        container.removeChild(container.childNodes[0]);
    }

    for(var i=0; i<5; i++) {
        var tempButton = null;
        tempButton = document.createElement("toolbarbutton");
        tempButton.setAttribute("label", "Button " + i);
        tempButton.setAttribute("tooltiptext", "Button " + i);
        tempButton.setAttribute("oncommand", "GBLTut_SomeFunction()");
        container.appendChild(tempButton);
    }
}

Единственное отличие этой функции от использованной для заполнения меню — первый цикл. Я просто показываю другой способ удалять предыдущие элементы. Все остальное — также. Но вот события onpopupshowing у нас нет. Так как же нам эту функцию вызвать?

А просто. Всякий раз, когда данные обновляются, можно вызвать функцию создания кнопок. Например, по событию oninput, когда пользователь начинает вводить текст в поисковую форму. (Пример, опять же, бестолковый, однако показвает, что есть пространство для воображения — прим. пер.).

Динамически включаем-выключаем кнопки

(Эта тема не включена в код учебного тулбара)

Часто возникают ситуации, когда нужно динамически сделать кнопку тулбара доступной или недоступной. Например, кнопка подсветки в Googlbar Lite должна быть недоступна, если нет поисковых слов, которые надо подсветить. Как только такие слова появляются, кнопка подсветки должна автоматически становиться доступной.

В следующем примере мы создадим пункт меню, который будет переключать статус обычной кнопки между доступным и недоступным. Вот разметка:

<menuitem label="Toggle Web Button" tooltiptext="Toggle Web Button"
          oncommand="GBLTut_ToggleWebButton()" />

А вот код функции GBLTut_ToggleWebButton():

function GBLTut_ToggleWebButton() {
    var button = document.getElementById("GBLTut-TB-Web");
    var value = button.disabled;
    if(value == "true")
        button.disabled = false;
    else
        button.disabled = true;
}

Сначала получаем доступ к интересующей нас кнопке, используя getElementById(). Далее, выясняем ее текущее состояние, используя свойство disabled объекта button. Если оно установлено в true, меняем на false, и наоборот. FireFox сам делает кнопку недоступной, и теперь по ней хоть кликай, хоть не кликай — ничего не произойдет. (При этом картинка серой не сделается — об этом нужно позаботиться отдельно, работая со скином, об этом в следующем разделе). Полезная фишка, пригодится в любом тулбаре, а выполнить ее просто, как и все остальные.

Динамически прячем-показываем кнопки

(Эта тема не включена в код учебного тулбара)

Googlebar Lite позволяет пользователю выбирать, какие кнопки он хочет видеть на своем тулбаре. Т.е. тулбар дожен уметь динамически показывать-прятать кнопки. Как и предыдущие, эта возможность реализуется крайне просто. Вот кусок JavaScript-кода, который сделает все, что нужно:

var TB_Web = document.getElementById("GBLTut-TB-Web");
TB_Web.setAttribute("hidden", !GBLTut_TB_ShowWeb);

Я опять использую функцию getElementById(), чтоб получить интересующую меня кнопку. Потом вызываю функцию setAttribute, чтоб изменить значение атрибута hidden. Обратите внимание, я присваиваю ему значение, противоположенное значению переменной GBLTut_TB_ShowWeb. Это булева переменная, в которой хранится информация, хочет ли пользователь видеть кнопку “web search”. Ее значение устанавливается где-то в коде Googlebar Lite, после чтения опции “Web Search Button” из пользовательских настроек. Читайте дальше, если интересно, как это делается.

Читаем и сохраняем настройки пользователя

(эта тема не включена в код учебного тулбара)

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

const GBLTut_PrefService =
      Components.
	    classes["@mozilla.org/preferences-service;1"].
		  getService(Components.interfaces.nsIPrefService);

Когда у нас есть эта переменная, мы можем получить доступ к ветке настроек для нашего расширения:

const GBLTut_Branch = GBLTut_PrefService.getBranch("gbl_tutorial.");

Все настройки нашего расширения начинаются с “gbl_tutorial.” (обратите внимание на точку на конце), поэтому такое значение передается функции getBranch() (встроенная функция FireFox). Наконец, вот код, используемый для считывания пользовательских настроек:

if(GBLTut_Branch.prefHasUserValue("buttons.web"))
    GBLTut_TB_ShowWeb = GBLTut_Branch.getBoolPref("buttons.web");
else
{
    GBLTut_Branch.setBoolPref("buttons.web", false);
    GBLTut_TB_ShowWeb = false;
}

Сначала я проверяю, существует ли такая запись в дереве настроек. Если да, я использую функцию getBoolPref(), чтоб прочитать ее значение и сохранить в переменную GBLTut_TB_ShowWeb. Если нет, устанавливаю значение по умолчанию — и для дерева настроек, и для нашей глобальной переменной.

Сохранение настроек производится также, как их чтение. Вот код, записывающий только что считанное значение:

GBL_Branch.setBoolPref("buttons.web", GBLTut_TB_ShowWeb);

No Comments »

Создание тулбара для Mozilla FireFox - часть 3

Posted by admin on September 2nd, 2008 — Posted in Программирование, Тулбары

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

В то время как XUL нужен для того, чтоб задать структуру надстройки для нашего тулбара, JavaScript — это то, что наш тулбар оживит. К счастью, JavaScript — это язык программирования, с которым просто разобраться, если раньше с ним никогда не сталкивались . Тем, кто уже имеет опыт работы с JavaScript, наши дальнейшие действия покажутся достаточно скучными.

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

Я рекомендую к имени каждой переменной и функции добавлять префикс, состоящий из начальных букв имени вашего расширения. В нашем случае, все переменные и функции снабжаются префиксом “GBLTut_”. Например, имя поисковой функции — “GBLTut_Search“. Добавив этот префикс, мы удостоверимся, что все наши переменные и функции имеют действительно уникальные имена и не будут конфликтовать с остальными.

Имя файла скрипта для нашего пример — “gbltutorial.js“. Он должен располагатсья в папке content вместе с XUL файлом, о котором шла речь в предыдущем разделе. На данный момент, вся файловая структура должна представлять из себя следующее:

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

Этот файл содержит необходимый код, который оживит наш тулбар. Перед тем, как исследовать файл скрипта, давайте разберемся, как связать XUL и JavaScript.

Связываем XUL и JavaScript

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

<script type="application/x-javascript"
        src="chrome://gbltutorial/content/gbltutorial.js"/>

Этот элемент надо расположить внутри элемента overlay в нашем XUL файле (я вставляю его прямо после открывающего тега overay). После добавления элемента script наш XUL стал вот таким:


<?xml version="1.0"?>

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

<script type=”application/x-javascript” src=”chrome://gbltutorial/content/gbltutorial.js”/>

<toolbox id=”navigator-toolbox”>

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

Как видите, атрибут type указывает, что мы работаем с JavaScript, а src просто содержит chrome-путь до используемого файла.

Добавляем функциональность к нашим кнопкам

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

oncommand="GBLTut_Search(event, 'web')"

Вот та же разметка в контексте обычной кнопки:

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

Значение, представленное в этом примере, показывает вызов JavaScript-функции GBLTut_Search(event, ‘web’). При активации этой кнопки будет вызвана функция GBLTut_Search() и, соответственно, выполнен ее код.

Вот собственно и все добавление функциональности к кнопкам. Просто, не так ли? Используя событие oncommand, вы можете выполнять любой код, какой захотите. Кстати, есть еще много всяких доступных для вас событий (например, упомянутый ранее onclick). Полный список событий лежит на XUL planet, так что — не стесняйтесь, выбирайте то, что вам надо.

Специальное замечание про кнопки “кнопка-меню”.

Перед тем как перейти к следующей теме, надо сделать важное замечание касательно кнопок “кнопка-меню”. Вспомните, что этот тип кнопок совмещает и простую кнопку, и всплывающее меню (например, кнопки навигации “вперед” и “назад”). Следовательно, этот тип кнопок состоит из элемента toolbarbutton, в который вложен элемент menupopup (который, в свою очередь, содержит несколько элементов menuitem). У элемента toolbarbuttom, как и у всех элементов menuitem, имеется атрибут oncommand. Когда кнопка активируется (пользователь на ней кликает), как вы догадываетесь, выполняется код, указанный в атрибуте oncommand элемента toolbarbutton. А вот что будет, если пользователь активирует один из элементов menuitem?

Предположив, что в этом случае просто сработает событие oncommand элемента menuitem, вы будете отчасти неправы. Хотя это событие и сработает, вместе с ним сработает и событие oncommand элемента toolbarbutton! А поскольку событие для кнопки сработает последним, будет выполнен код, связанный именно с ним.

Комбинированное меню поиска Googlebar Lite — это кнопка “кнопка-меню”. Когда вы кликаете по этой кнопке, выполняется обычный поиск. Различные пункты меню из всплывющего меню позволяют пользователю выполнять другие типы поиска. Если бы событие oncommand для каждого menuitem было оформлено неправильно, выбор любого пункта меню приводил бы к тому же обычному поиску (поскольку выполнялось бы событие oncommand для элемента toolbarbutton). Так как же быть?

К счастью, есть решение проблемы через удобную функцию DOM (объектной модели документа):

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

Добавляя вызов event.preventBubble() в конец кода, мы можем предотвратить распространение события oncommand вверх по дереву DOM. Именно из-за этого эффекта у нас всегда выполнялся код для элемента toolbarbutton. Поскольку toolbarbutton — предок каждого menuitem, он перехватывает событие oncommand и оно передается вверх по дереву DOM.

Короче говоря, всегда помните следующее правило: создавая кнопку типа “кнопка-меню”, обязательно добавляйте event.preventBubble() к атрибуту oncommand каждого элемента menuitem.

Динамически заполняем меню

Возможность динамически заполнять меню пунктами черезвычайно полезна. В качестве примера возьмем меню поля ввода нашего тулбара. Это меню нужно обновлять каждый раз, когда пользователь переходит к новой странице (не понял, зачем? — прим. пер.). К счастью, динамическое наполнение меню — задача простая. Добавим пять динамических пунктов к выпадающему меню нашего тулбара. Вот разметка, которую мы обсуждали в части 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>

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

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

Сначала мы определяем элемент, с которым собираемся работать, используя функцию getElementById() объектной модели документа. Обратившись к этому элементу, мы удаляем все пункты меню, указанные ранее. Мы проходим по списку потомков элемента, делая вызов простой DOM-функции removeChild, чтоб удалить все пункты меню.

Теперь, очистив меню, можно начать заполнять его новыми пунктами. В этом примере мы для начала создаем массив, содержащий пять поисковых запросов. Из него будут динамически загружаться пункты меню. Мы проходим по всему массиву и создаем пункт меню для каждого элемента, используя функцию createElement(). Функция setAttribute() нужна для того, чтоб установить атрибуты label и tooltiptext для каждого пункта меню. Наконец, при помощи функции appendChild() мы добавляем в меню только что созданный пункт.

Добавим получившуюся функцию в наш файл JavaScript, в результате чего он станет вот таким:

function GBLTut_Search(event, type)
{
    // Create a variable and assign it the value of our document window
    var win = window._content.document;

    // Create a few other handy variables
    var URL = "";
    var isEmpty = false;

    // Get a handle to our search terms box
    var searchTermsBox = document.getElementById("GBLTut-SearchTerms");

    // Get the value in the search terms box, trimming whitespace as necessary
    var searchTerms = GBLTut_TrimString(searchTermsBox.value);

    // If there are no search terms, than we set isEmpty to true
    // Otherwise, we convert the search terms to a safe URI version
    if(searchTerms.length == 0) { isEmpty = true; }
    else { searchTerms = GBLTut_ConvertTermsToURI(searchTerms); }

    switch(type)
    {
    // Build up the URL for an image search
    case "image":
        if(isEmpty) { URL = "http://images.google.com/“; }
        else        { URL = “http://images.google.com/images?q=” + searchTerms; }
        break;

    // Build up the URL for a web search
    case “web”:
    default:
        // Build up the URL that we should visit when we search
        if(isEmpty) { URL = “http://www.google.com/“; }
        else        { URL = “http://www.google.com/search?q=” + searchTerms; }
        break;
    }

    // Load the URL in the browser window using the GBLTut_LoadURL function
    GBLTut_LoadURL(URL);
}

function GBLTut_TrimString(string)
{
    // Return empty if nothing was passed in
    if (!string) return “”;

    // Efficiently replace any leading or trailing whitespace
    var value = string.replace(/^\s+/, ”);
    value = string.replace(/\s+$/, ”);

    // Replace any multiple whitespace characters with a single space
    value = value.replace(/\s+/g, ‘ ‘);

    // Return the altered string
    return value;
}

function GBLTut_ConvertTermsToURI(terms)
{
    // Split up the search terms based on the space character
    var termArray = new Array();
    termArray = terms.split(” “);
    var result = “”;

    // Loop through the search terms, building up the result string
    for(var i=0; i<termArray.length; i++)
    {
        if(i > 0) { result += “+”; }

        // Call the built-in function encodeURIComponent() to clean up
        // this search term (making it safe for use in a URL)
        result += encodeURIComponent(termArray[i]);
    }

    // Return the result
    return result;
}

function GBLTut_LoadURL(URL)
{
    // Set the document’s location to the incoming URL
    window._content.document.location = URL;

    // Make sure we get the focus
    window.content.focus();
}

function GBLTut_Populate()
{
    // Получаем доступ к элементу menu, с которым будем работать
    var menu = document.getElementById(”GBLTut-SearchTermsMenu”);

    // Удаляем текущие пункты меню
    for(var i=menu.childNodes.length - 1; i>=0; i–) {
        menu.removeChild(menu.childNodes.item(i));
    }

    // Эта строка содержит пять поисковых запросов, разделенный двойным символом “труба” (||)
    var terms = “Googlebar Lite||Firefox web browser||Mozilla Foundation||Homestar Runner||They Might Be Giants”;

    // Создаем массив из вышеупомянутой строки
    var termArray = new Array();
    termArray = terms.split(”||”);

    // Загружаем поисковые запросы в наше меню
    for(var i=0; i<termArray.length; i++)
    {
        // Для каждого запроса создаем элемент menuitem
        var tempItem = null;
        tempItem = document.createElement(”menuitem”);

        // Добавляем элементу menuitem различные атрибуты:
        // label - сам поисковый запрос;
        // tooltip - всплывающая подсказка, содержит текст “Dynamic Item #”, где # - это номер пункта

        tempItem.setAttribute(”label”, termArray[i]);
        tempItem.setAttribute(”tooltiptext”, “Dynamic Item ” + (i+1));

        // Добавляем пункт к нашему меню
        menu.appendChild(tempItem);
    }
}

No Comments »

Создание тулбара для Mozilla FireFox - часть 2

Posted by admin on September 2nd, 2008 — Posted in Программирование, Тулбары

Структурируем тулбар

Практически все расширения для 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 пространства имен, который никогда не изменится. То есть, всегда используйте это значение.

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

Все тулбары для 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>

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

  • accesskey — определяет букву, которая будет подчеркнута в имени тулбара, поскольку будет клавишей доступа с клавиатуры. Для нашего тулбара это будет большая “T”. Хотя этот атрибут и необязательный, очень рекомендуется им пользоваться.
  • class — определяет класс стиля, который надо применить к этому тулбару. Указанное значение (chromeclass-toolbar) — имя класса для стандартного вида тулбара Firefox. Опять же, этот атрибут необязательный, но рекомендуемый.
  • context — определяет контекстное меню, которое нужно использовать, когда юзер делает правый клик по нашему тулбару. Можете указать ID вашего собственного меню, или сослаться на стандартный вид, как это сделано в нашем примере.
  • toolbarname — тут указываем имя нашего тулбара (текст, видимый пользователю в Вид -> Панели инструментов).
  • hidden — определяет, должен ли тулбар быть спрятан. Мы устанавливаем значение в false, таким образом наш тулбар по умолчанию будет отображаться.
  • persist — вы заметите, что я выставил значение этого атрибута в hidden. По сути, я говорю FF, что ему следует запоминать значение атрибута hidden между сеансами работы браузера. Фишка сего механизма в том, что FF сделает все за вас. Все, что вам надо сделать — указать, какие атрибуты браузер должен запомнить. Кстати, здесь можно указать больше одного атрибута, разделив имена атрибутов пробелами.

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

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

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

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

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

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

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

  • tooltiptext — указываем текст всплывающей подсказки, которая возникает, когда пользователь наводит курсор на кнопку
  • label — указываем текст, написаный на кнопке
  • oncommand — значение этого атрибута — это код, который должен быть выполнен, когда пользователь надавит кнопку. В нашем примере я вызываю тренировочную функцию GBLTut_Serach(). Написание скриптов для тулбара — это тема для следующего раздела.

Более полное описание атрибутов элемента 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 немного сложнее. Вот новые атрибуты, обозначенные в примере:

  • label — определяет текст, отображаемый для данного пункта меню
  • tooltiptext — это то же, что мы уже видели раньше, но с одной оговоркой. Из-за досадной ошибки в FireFox 1.0, этот атрибут обязателен. Вы можете оставить его пустым, но будет появляться пустая подсказка, когда юзер будет наводить мышь на пункт меню. Учитывая, что пункты меню традиционно не имеют всплывающих подсказок, эта “особенность” выглядит неаккуратно и зело раздражает. Будем надеяться, что в следующих версиях FF баг поправят.

Подробнее об атрибутах элемента 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. Причины его появления обсудим в разделе про скрипты.

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

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

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

<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, который, собственно, и делает то, что нам надо. В этом примере употребляется несколько новых атрибутов:

  • editable — когда установлен в true, пользователь может вбивать текст в поле ввода
  • flex — указывает, что элемент может растягиваться. Значение атрибута — целое число, определяющее способность к растягиванию по сравнению с другими элементами тулбара (т.е. элемент со значением атрибута flex равным 100 может занимать больше, чем элемент с flex=’1′).
  • minwidth — указывает минимальную допустимую ширину элемента в пикселах
  • width — указывает исходную ширину в пикселах
  • onkeypress — это событие происходит когда пользователь нажимает клавишу на элементе (например, начинает вбивать текст в поле ввода)

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

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

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

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, которые мы использовали в вышеприведенном примере (кроме тех, с которыми уже разобрались):

  • state — определяет, будет ли splitter иметь свернутое содержимое. Значение “open” указывает, что содержимое после или перед сплиттером (в нашем случае — с обоих сторон) будет видимым.
  • collapse — определяет, какая сторона сплиттера свернута. Мы выставляем “none“, поскольку все отображается.
  • resizebefore — указывает, какой элемент слева от сплиттера должен изменить размер при перемещении сплиттера. Мы выставляем “closest“, поскольку хотим, чтоб размер изменяло поле ввода, т.е. ближайший к сплиттеру элемент.
  • resizeafter — указывает, какой элемент справа от сплиттера должен изменять размер, когда пользователь двигает сплиттер. В нашем расширении Googlebar Lite я использую значение “farthest“, поскольку хочу, чтоб изменялся размер свободного пространства на правом краю тулбара.

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

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

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

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

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

<toolbarseparator />
<toolbarspring />

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

<?xml version="1.0"?>

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

<toolbox id=”navigator-toolbox”>

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

        <toolbaritem flex=”0″>

            <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>

        </toolbaritem>

        <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>

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

        <toolbaritem flex=”0″>

            <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>

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

        </toolbaritem>

        <toolbarspring />

    </toolbar>
</toolbox>
</overlay>

No Comments »

Создание тулбара для Mozilla FireFox - часть 1

Posted by admin on September 2nd, 2008 — Posted in Программирование, Тулбары

Учебные загрузки

В этом учебном пособии мы создадим основу Googlebar Lite.
Чтобы помочь процессу обучения, рабочие версии нашего учебного тулбара доступны для скачивания.
Вам предлагается 2 файла:

  • Учебный тулбар в формате XPI -
    этот файл является XPI-инсталлятором для тулбара, который мы создадим. Как вы увидите далее, этот файл содержит все исходные коды и прочие необходимые файлы.
    Если вы знаете, как распаковывать файлы XPI (а делать это надо зипом - прим.пер.), этого файла вам будет достаточно.
    Чтобы установить тулбар, просто сохраните файл к себе на хард, откройте FF и перетащите файл в окошко FF.

  • Исходный код учебного тулбара.
    Этот zip-файл содержит всю файловую структуру нашего учебного тулбара. Как я уже упомянал, все эти файлы доступны в файле XPI. Данный файл позволяет получить доступ ко всему, что нам нужно, более простым способом - без необходимости распаковывать XPI.

Подготовка

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

Начиная писать GoogleBar Lite, я искал руководства, как создавать тулбары для FF. И хотя мне удалось найти несколько блестящих пособий, рассказывающих о создании расширений вообще, я не нашел ничего относительно создание тулбаров. Поэтому, покопавшись порядком в существующих тулбарах, таких как GoogleBar, Webdevoloper или Ultrabar, я решил взяться за написание собственного руководства, чтобы другим было с чего начать. В конце концов, почему каждый должен изобретать велосипед заново?

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

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

Устройство файловой структуры.

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

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

+- GBLTutorial
   +- chrome
      +- content

Инструменты, которые нам понадобятся

Перед тем как начать, скажу о нескольких инструментах, которыми нам придется пользоваться на протяжении всего обучения. Все файлы, которые мы будем редактировать вручную (за исключением картинок) — это простые текстовые файлы. Так что убедитесь, что у вас есть хороший текстовый редактор (разумеется, MSWord отдыхает, Wordpad — тоже дурацкая идея, но уже лучше). Желательно, чтоб редактор мог подсвечивать синтаксис XML и автоматически расставлять отступы. Таких полно, например можно использовать Crimson Editor или J Creator (вполне бесплатные).

Второй инструмент, с которым предстоит работать — какой-нибудь ZIP (лично я использую Winzip (лично я тоже =) — прим.пер.)). Он понадобится нам для запаковывания нашего расширения. Рекомендую найти что-нибудь с поддержкой интерфейса командной строки, ибо так проще. Вариантов хватает, выбирайте любой, который больше нравится.

Создаем каркас (Framework)

Аббревиатура RDF расшифровывается как Resourse Description Framework — карскас описания ресурса. RDF-файлы используются для описания структуры расширения. Есть два RDF-файла, представялющих для нас интерес: install.rdf и contents.rdf. Первый сообщает, как наше расширение должно быть установлено в FF, в то время как второй описывает структуру архива с расширением. Опять же, эти данные в этих файлах хранятся в простом текстовом формате, и их можно править любым текстовым редактором, только не забудьте сохранять их с расширением .rdf.

RDF номер раз: install.rdf

Первый файл, который мы создадим, будет называться install.rdf. Этот файл необходимо разместить в корневой директории расширения (в нашем случае — RDFTutorial). Этот файл, также известный как декларация установки (”install manifest”), ответственен за описание нашего расширения для менеджера расширений (extension manager) FF. В нем сообщается с какими версиями FF совместимо наше расширение, и другая важная информация. Все строки, которые нам нужно отредактировать, подсвечены, в то время как строки, общие для всех расширений, отображаются обычным текстом.

<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  <Description about="urn:mozilla:install-manifest">
    <em:creator>Jonah Bishop</em:creator>
    <em:description>
       A Firefox toolbar tutorial based on Googlebar Lite.
    </em:description>
    <em:homepageURL>http://www.greenclassic.ru/freescripts/</em:homepageURL>
    <em:id>{d5617e3d-5bfe-4be1-a7b8-add67015d92f}</em:id>
    <em:name>Dubr Toolbar Tutorial</em:name>
    <em:version>1.0</em:version>
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>1.0</em:minVersion>
        <em:maxVersion>1.0</em:maxVersion>
        </Description>
    </em:targetApplication>
    <em:file>
       <Description about="urn:mozilla:extension:file:gbltutorial.jar">
         <em:package>content/</em:package>
       </Description>
    </em:file>
  </Description>
</RDF>

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

В ней представлено множество полезной информации, описывающей наше расширение. Обратите внимание, что порядок представления информации в этом блоке не имеет значения, другими словами, вы можете расположить строки кода так, как вам больше нравится. Я располагаю их в простом алфавитном порядке, поскольку мне так больше нравится (и не впадлу ему это порядок рассчитывать??? — прим.пер.). Первая строка определяет автора расширения (в данном случае — меня), с помощью тега <em:creator>, как вы могли заметить. Далее я привожу описание расширения. Описание — это короткое предложение, сообщающее, что расширение делает, которое появится в менеджере расширений. Третья строка содержит указание на домашнюю страницу расширения (будет по умолчанию использована в диалоговом окне “О расширении”).

Четвертая строка в этом блоке, заключенная в теги <em:id> — это самая важная строка во всем файле. Значение, которое должно быть указано здесь — это уникальный идентификатор вашего расширения. Есть много бесплатных веб-сервисов, которые сгенерируют для вас такой идентификатор. Я рекомендую следующие:

Когда вы сгенерируете собственный ИД, поместите его между тегами <em:id>, как это показано выше. Следующий тег — <em:name> — это просто имя вашего расширения, которое появится в менеджере расширений. Не нужно добавлять номер версии к имени, поскольку для этого есть специальный тег <em:version>. Очевидно, будет необходимо обновлять его всякий раз, когда вы будете готовы представить общественности очередную версию своего творения. Для тех, кто работал со скриптами, не соствит труда автоматизировать этот процесс. Лично я использую в этих целях скрипт на Perl.

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

<em:targetApplication>
  <Description>
    <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
    <em:minVersion>1.0</em:minVersion>
    <em:maxVersion>1.0</em:maxVersion>
  </Description>
</em:targetApplication>

Здесь описывается целевое приложение, для которого наше расширение написано. Обратите внимание, здесь мы видим еще один тег <em:id> — не тот который мы сгенерировали ранее. Он содержит уникальный идентификатор браузера FireFox, и не должен меняться, раз уж мы пишем расширение для FF. Мы также видим два элемента версии: minVersion и maxVersion. Они указывают, с какими версиями FF совместимо наше приложение. В данном примере я просто использую 1.0 в качестве минимальной и максимальной версии. Разработчикам расширений следует обновлять значение maxVersion всякий раз с выходом новой версии браузера.

Обратите внимание, что версия браузера, которую вы указываете, должна следовать общей конвенции. Поэтому версия “1.0 Preview Version” будет воспринята неправильно. Версия FF должна быть указана в следующем формате:

major.minor.release.build[+]

Все поля, кроме “major“, не являются обязательными, поэтому такие версии, как 1, 1.0, 1.0.3 или 1.0.3.20050405 — все допустимы. Для получения дополнительной информации по этому вопросу, обратитесь к статье о присвоении номеров версий на сайте mozilla.org.

Остался последний блок в этом файле, который надо исследовать. Вот он:

<em:file>
  <Description about="urn:mozilla:extension:file:gbltutorial.jar">
    <em:package>content/</em:package>
  </Description>
</em:file>

Этот блок описывает структуру JAR-файла нашего расширения (который мы создадим немного позже). Элемент Description содержит имя JAR-файла в атрибуте about. Вы можете заметить, что в нашем примере имя JAR-файла — gbltutorial.jar. В случае вашего собственного расширения имя этого файла скорее всего будет другим, и оно должно идеально соответствовать имени вашего расширения. Элемент package, показанный в данном примере, отражает структуру JAR-файла. На данный момент у нас есть единственная папка в папке chrome — ее имя “content”. Поэтому мы располагаем только один элемент package, который отражает сей факт. Обратите внимание на слеш после слова “content”. Он необходим, поскольку мы указываем на директорию, которую будет содержать JAR-файл, если слеш не использовать — могут произойти всякие непредвиденные и странные события.

Вот и все, что нужно знать об этом файле. Довольно просто, не так ли? Теперь давайте посмотрим на файл contents.rdf, который не менее прост.

RDF-файл нумер два: contents.rdf

Файл contents.rdf описывает, каким образом хранится содержимое нашего расширения. И снова это просто текстовый документ, который можно создать в любом редакторе. Этот файл необходимо разместить в папке content. Соответственно, после создания этого файла структура папок будет выглядеть как-то так:

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

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

<?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:gbltutorial"/>
  </RDF:Seq>

  <RDF:Description about="urn:mozilla:package:gbltutorial"
    chrome:extension="true" chrome:name="gbltutorial"/>

  <RDF:Seq about="urn:mozilla:overlays">
    <RDF:li resource="chrome://browser/content/browser.xul"/>
  </RDF:Seq>

  <RDF:Seq about="chrome://browser/content/browser.xul">
   <RDF:li>chrome://gbltutorial/content/gbltutorial.xul</RDF:li>
  </RDF:Seq>
</RDF:RDF>

Вы снова можете обнаружить, что это простой XML-файл. И опять мы имеем элемент RDF в качестве корня, но если вы внимательнее посмотрите, то обнаружите, что его атрибуты отличаются от тех, что мы видели в файле install.rdf (изменены пространства имен). Теперь давайте рассмотрим первый блок кода:

<RDF:Seq about="urn:mozilla:package:root">
  <RDF:li resource="urn:mozilla:package:gbltutorial"/>
</RDF:Seq>

Первое, что мы делаем — обозначаем сборку (package) нашего расширения (которая сделает его уникальным среди всех прочих расширений). Для имени сборки лучше всего использовать имя расширения. В вышепреведенном примере я использовал просто “gbltutorial“.
Далее нужно создать описание сборки нашего расширения:

<RDF:Description about="urn:mozilla:package:gbltutorial"
  chrome:extension="true" chrome:name="gbltutorial"/>

Вы видите, что мы еще раз указываем имя сборки в качестве первого атрибута элемента. Далее мы покажем, что это действительно расширение, присвоив атрибуту chrome:extension значение true. А потом (снова, а нафига? =) — прим.пер.) укажем имя сборки в атрибуте chrome:name. Имейте ввиду, что из-за ошибки в FF 1.0 значение атрибута chrome:name должно быть указано в нижнем регистре.

Все видимые элементы браузера FF разработаны на языке XUL, и все вместе они называются “chrome”.
http://www.mozilla.org/xpfe/ConfigChromeSpec.html
Следующий блок кода сообщает браузеру, который из chrome-файлов наше расширение будет расширять. Почти всегда это будет файл browser.xul (хотя могут быть и другие, но мы пока сделаем как попроще).

<RDF:Seq about="urn:mozilla:overlays">
  <RDF:li resource="chrome://browser/content/browser.xul"/>
</RDF:Seq>

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

<RDF:Seq about="chrome://browser/content/browser.xul">
  <RDF:li>chrome://gbltutorial/content/gbltutorial.xul</RDF:li>
</RDF:Seq>

Сперва мы указываем, к какому файлу относится расширение, поместив соответствующий chrome-путь в атрибут about. Элемент RDF:li содержит chrome-путь к нашему файлу-надстройке (overlay file), который мы очень скоро начнем писать. В примере выше chrome-путь устроен вот так:

chrome://<packagename>/content/<overlayfilename>.xul

В вашем собственном расширении изменятся packagename и overlayfilename. Все остальное останется на своих местах.

Вот и все, что касается файла contents.rdf. И снова довольно просто. Теперь, когда мы разобрались со всей этой скукотищей, давайте оттопыриваться по созданию непосредственно тулбара.

No Comments »