Создание тулбара для Mozilla FireFox - часть 3
Создание скриптов. 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);
}
}
