Страницы

пятница, 19 ноября 2010 г.

Пишем plugin для FireFox

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

https://addons.mozilla.org/en-US/developers/tools/builder

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

chrome chrome.manifest defaults install.rdf

./chrome:
content locale skin

./chrome/content:
about.xul adding.xul ff-overlay.js ff-overlay.xul options.xul overlay.js

./chrome/locale:
en-US

./chrome/locale/en-US:
about.dtd adding.dtd options.dtd overlay.dtd overlay.properties

./chrome/skin:
overlay.css

Содержимое папки зависит от выбранных вами опций, мне нужна была кнопка в контекстном меню и настройки. В моем примере мне нужно была отдельная кнопка в
контексном меню браузера. Для того чтоб зарегистрировать что либо объекте браузера, нужно "проверлеить" его основной объект "chrome://browser/content/browser.xul". За это отвечает файл chrome.manifest, приведу пример моего
content ext_add chrome/content/
skin ext_add classic/1.0 chrome/skin/
locale ext_add en-US chrome/locale/en-US/

overlay chrome://browser/content/browser.xul chrome://ext_add/content/ff-overlay.xul

Где ext_add/content/ff-overlay.xul содержит следующее :

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="chrome://ext_add/skin/overlay.css" type="text/css"?>
<!DOCTYPE overlay SYSTEM "chrome://ext_add/locale/overlay.dtd">
<overlay id="ext_add-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="overlay.js"/>
<script src="ff-overlay.js"/>

<stringbundleset id="stringbundleset">
<stringbundle id="ext_add-strings" src="chrome://ext_add/locale/overlay.properties"/>
</stringbundleset>

<popup id="contentAreaContextMenu">
<menuitem id="context-ext_add" label="&ext_addContext.label;"
accesskey="&ext_addContext.accesskey;"
insertafter="context-stop"
oncommand="ext_add.onMenuItemCommand(event)"/>
</popup>


</overlay>


Добавить что-то другое можно, воспользовавшись стандартной документацие XUL.
С первых минут написания плагина возникнет вопрос, как получить доступ к текущему документу - через псевдоним текущего окна 'content' , например

var e =content.document.createElement('div');


Расскажем про диалоговые окна, не юзать же нам один promt и alert. В firefox-e в качестве шаблона используют XML-подобный язык XUL . Например пишем файлик типа adding.xul




<!DOCTYPE dialog SYSTEM "chrome://ext_add/locale/adding.dtd">
<dialog width='300' title="&about;" orient="vertical" autostretch="always" onload="sizeToContent()"
buttons="accept,cancel"
ondialogaccept="return ext_add.post2();"
ondialogcancel="return ext_add.cancel_post();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="overlay.js">

<groupbox align="center" orient="horizontal">
<vbox>
<label control="texttitle">&title.label;</label>
<textbox id="texttitle">
<separator class="thin">
<label control="cattitle">&cattitle.label;</label>
<menulist id="'cattitle'">
<menupopup>
<menuitem label="IT-сфера" value="'9'/">
<menuitem value="19" label="'Авторы'">
</menupopup>
</menulist>
<separator class="thin">
</vbox>
<groupbox align="center" orient="horizontal">
<caption label="'&desc.label;'/">
<textbox multiline="true" rows="'5'" id="'desc'">
</groupbox>

</groupbox>
</dialog>



Код вызова диалога :
var win = window.openDialog( "chrome://ext_add/content/adding.xul",
"addingWindow", "chrome,centerscreen",
{text_data: this.commit_text,
main: this,
hst:content.window.location.host,
url:content.window.location.href });







Первый параметр указывает относительный путь к файлу дескриптору adding.xul ,
второй параметр - наименование окна,
третий - позиционирование,
далее идут параметры, которые мы передаем в диалоговое окно.
К параметрам можно обратиться следующим образом :

var plugin=window.arguments[0].main;
var h=window.arguments[0].hst;
var l=window.arguments[0].url;


Стандартная документация тут

Обратите внимание в adding.xul -в теге dialog описывается наличие кнопок OK, Cancel
а так же их обработчики через атрибуты ondialogaccept, ondialogcancel,
которые находяться в файле overlay.js.
Обработчик ondialogaccept :
post2 : function(e){
var cat=document.getElementById('cattitle').value;
var t=document.getElementById('texttitle').value;
var desc=document.getElementById('desc').value;
var txt=window.arguments[0].text_data;
txt=txt.replace(" "," ");
txt=txt.replace("","");
txt=txt.replace("&","");
txt=txt.replace("&","");
txt=''+txt+'';
var plugin=window.arguments[0].main;
var h=window.arguments[0].hst;
var l=window.arguments[0].url;
var params='cat_id='+cat;
params+='&text='+txt;
params+='&title='+t;
params+='&desc='+desc;
params+='&host='+h;
params+='&url='+l;

plugin.send_http(plugin.post_url,params,plugin.debug_func);
return true; },

Одним из важных элементов, которые вам понадобяться в начале написание плагина это ваши настройки...
Диалоговое окно настроек описавается тоже при помощи XUL.
Интересней, как получить сохраненные настройки :
//находим компонент настроек
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
// находим ветку относящуюся к нашему плагину в данном случае 'ext_add'
prefs = prefs.getBranch("extensions.ext_add.");
// получение настроек
login=prefs.getCharPref("loginpref");
pwd=prefs.getCharPref('pwdpref');
// проверка наличия настроек
if(!prefs.prefHasUserValue("loginpref")) {
alert("Заполните данные для авторизации");
return; }

Более детально читаем тут
Для любого приложения важна среда программирования, в данном случае удобно сделать отдельный профайл FireFox например Debug. Здесь подробно написано как это сделать под разными OS, в Linux-е я же просто запустил команду
" /usr/bin/firefox -no-remote -P dev". В новом профайле советую установить несколько плагинов для разработки.

Extension Developer's Extension
набор утилит javascript-shell, regexp evaluater, архиватор плагинов и т.п
Firebug - анализатор DOM -модели и не только
Tamper - дампер сетевых соединений, хорош, если вы активно используете Ajax.

Кстати про Ajax, из плагина можно обращаться к сторонним доменам,
если запросы выполняются из контекста вашего плагина.
Ajax работает через обычный XMLHttpRequest.


P.S Вообщем все интутивно понятно и знакомо, что не может не радовать.

3 комментария:

Анонимно комментирует...

Здравствуйте. У меня есть вопрос: где разместить скачаный шаблон плагина, чтобы фаерфокс отобразил сделанные мной изменения(добавленую кнопку. В файле chrome.manifest есть запись, как вы писали выше про оверлей моего файла, но он не как не повлиял на вид фаерфокса.

Анонимно комментирует...

Если не хотите публиковать на своем блоге переписку, ответьте на ранее присланный вопрос на мыло m.kuzmich@yahoo.com. Заранее, спасибо.

Богдан комментирует...

А вы устанавливали описаные внизу мной дополнения для разработки плагинов, а так же делали отдельный профиль под разработку?

В дополнение Extension Developer's Extension - есть опция перегрузить chrome, браузер и еще что-то не помню...
Если не делали то ваш браузер со стандартными настройками кеширует( по крайней мере я сталкивался примерно с тем же, что и у вас), что естественно все дополнения. Для отключения этих опций, "я забыл написать в посте это" надо в профиле для разработки установить значения системных переменных, весь этот процесс описан
- https://developer.mozilla.org/en/Setting_up_extension_development_environment#Development_preferences

копируя оттуда надо устанавить след системные переменные
nglayout.debug.disable_xul_cache = true
javascript.options.showInConsole = true
browser.dom.window.dump.enabled = true
javascript.options.strict = true
extensions.logging.enabled = true
nglayout.debug.disable_xul_fastload = true
dom.report_all_js_exceptions = true

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