Как стать автором
Обновить

Как сделать FF удобней — пишем свои кнопки

Firefox

Преамбула


Я перешел на FF с IE очень давно — мне нужен был браузер с удобными средствами разработки и отладки, позволяющий полностью настраиваться «под себя» так как это был мой основной рабочий инструмент — инструмент должен быть удобным.

И FF полностью справился со своими обязанностями — возможно, я кому-то покажусь странным — но я потратил около 2-х месяцев на чтение сайта с дополнениями и нахождения для меня лучшего их набора, настройки и т.д.
В результате я получил мощную хорошо настроенную и удобную программу для своих нужд.

image

Не смотря на то, что я знаю JS, мне ни разу не пришло в голову писать какие-либо расширения под ff по одной простой причине — чтобы я не захотел — это уже было в депозитории расширений. Так продолжалось до вчера :)


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

Можно использовать избранное… но как-то много у меня там всякого не относящегося к работе… папки там — тоже вариант — но вот не нравится мне оно как-то.

Поиски...


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

Было абсолютно не охота разбираться с тем как его упаковывать как устанавливать и писать локализации к нему — однако выход нашелся быстро — есть такое замечательное расширение, которое наверняка стоит у многих программеров Custom Buttons, есть еще более навороченный вариант Custom Buttons 2 — кому что нравится, я же выбрал первый, так как руководствуюсь принципом если несколько сущностей одинаково удовлетворяют ваши потребности — используйте простейшую — ну да это я — а Вы можете выбрать исходя из своих принципов :)

Далее все просто — данные расширения — это некоторая обвязка, позволяющая создавать свои собственные кнопки на тулбаре и реализовывать в них собственный функционал. Он пишется на JS, расширенном внутренними объектами FF.

Т.е. особо пытливым хабралюдям все-таки придется лезть и читать документацию :)

Алгоритм добавления кнопки прост: правый клик по тулбару -> добавить кнопку, позднее после заполнения всех нужных полей и сохранения кнопки надо будет еще вытащить ее в нужное место на нужный тулбар, используя правый клик по тулбару -> настроить, а дальше найдя свою кнопку перетащить ее в нужное место.

image

Что касается полей:
Имя — имя вашей кнопки
Картинка — путь до картинки, которая и будет кнопкой ( вы можете указав путь нажать base64 — тогда за место пути до картинки у вас образуется dataURL, и картинка будет хранится в самой кнопке )

Далее вкладки
Код — тот код, что выполняется по нажатию
Инициализация — код, выполняемый один раз при загрузке браузера

Соотвественно вся мощь FF у вас в руках, делать можно все что хочешь :)
Например для того, чтобы сделать отдельную кнопку для вызова избранного достаточно добавить вот такое:
Код:
if ( !this.lastChild ) {
var mc = document.getElementById("bookmarksMenuPopup");
var mcc = mc.cloneNode( true );
this.appendChild( mcc );
}

var bo = document.getBoxObjectFor( this );
this.lastChild.showPopup ( this, -1, -1, "popup", "bottomleft", "topleft" );


* This source code was highlighted with Source Code Highlighter.


Инициализация:
пусто
Здесь я обошелся без отдельного кода инициализации, засунув его и проверку в основной код.
Естественно можно разделить это как должно быть правильно — переписав все содержимое первого if в код инициализации и убрав if из кода, но зато так кароче :)

Собственно щелкнув по правой клавишей по нашей кнопке мы получим меню Custom Buttons с помощью которого можно редактировать код кнопки, копировать код кнопки — вобщем работать и изменять наше маленькое расширение, левый же клик откроет нам избранное, выполнив наш код.

image

Копирование кода кнопки позволит создать эту кнопку в любом другом FF, причем там сохранятся все поля вашей кнопки ( и естественно картинки, если они были dataURL ).

Вот оно!


Возвращаясь к своей персональной задачке и пока я писал для нее код, у меня родился еще небольшой функционал:
  1. возможность открыть определенный URL
  2. хотелось иметь возможность быстро запускать нужные приложения ( например хранитель паролей )
  3. удобно было бы иметь возможность запускать некий стандартный код JS на любой странице ( конечно можно поглядеть в FireBug-е, но всеже иногда удобней кликнуть два раза чем бегать по его закладкам )
  4. ну и некое подобие roboform, только с более простым функционалом — а именно — открыть нужный URL и заполнить определнные поля определнными значениями

п.3 — использую например чтобы поглядеть список iframe-ов или timer-ов на странице и много еще для чего. Очень часто мне такое бывает нужно.

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

Почитав доки и подглядев в установленных расширения куски кода родилась вот такая штука ( над оптимизацией кода не работал — ибо не до того было — с удовольствием приму замечания :) ):
Код:
var bo = document.getBoxObjectFor( this );
this.lastChild.showPopup ( this, -1, -1, "popup", "bottomleft", "topleft" );


Инициализация:
var mitems = [
{
"label" : "localhost",
"tip" : "localhost",
"image" : "",
"type" : "url",
"val" : "localhost"
},

"separator",
{
"label" : "Google",
"tip" : "Google",
"image" : "",
"type" : "url",
"val" : "http://www.google.ru"
},
"separator",

{
"label" : "Notepad",
"tip" : "Notepad",
"image" : "",
"type" : "exec",
"val" : "c:/windows/notepad.exe"
},

"separator",

{
"label" : "other",
"tip" : "other",
"image" : "",
"type" : "submenu",
"val" :
[
{
"label" : "JS test",
"tip" : "JS test",
"image" : "",
"type" : "js",
"val" : "alert( 'js testing...' );"
},

{
"label" : "Выход из FF",
"tip" : "Выход из FF",
"image" : "",
"type" : "js",
"val" : "goQuitApplication();"
}
]
}
];

function createMenu( label, tip, image ) {
var m = document.createElement( "menu" );
m.setAttribute( "label", label );
if ( image ) {
m.setAttribute( "class", "menu-iconic" );
m.setAttribute( "image", image );
}
if ( tip ) m.tooltipText = tip;

return m;
}

function createMenuItem( label, tip, image ) {
var mi = document.createElement( "menuitem" );
mi.setAttribute( "label", label );
if ( image ) {
mi.setAttribute( "class", "menuitem-iconic" ); // "menuitem-iconic bookmark-item"
mi.setAttribute( "image", image );
}
if ( tip ) mi.tooltipText = tip;

return mi;
}

function executeFile( progPath, arg ) {
progPath = progPath.replace( /\//gi, "\\" );
try {
var argArray = arg ? arg.split(/\s+/) : [];
var nsILocalFile = Components.classes["@mozilla.org/file/local;1"].getService(Components.interfaces.nsILocalFile);
var nsIProcess = Components.classes["@mozilla.org/process/util;1"].getService(Components.interfaces.nsIProcess);
nsILocalFile.initWithPath(progPath);
nsIProcess.init(nsILocalFile);
nsIProcess.run(false, argArray, argArray.length);
// nsIProcess.close();
return nsILocalFile;
}
catch( ex ) {
alert( ex.toString() );
return null;
}
}

function buildMenu( items ) {
var menu, i, t, mi, item;
var self = this;

menu = document.createElement( "menupopup" );
menu.type = "menu";
menu.orient = "horizontal";
// menu.id = "myCustomMenu";

for ( i in items ) {
item = items[i];
if ( typeof( item ) == "string" ) {
switch( item ) {
case "separator":
mi = document.createElement( "menuseparator" );
break;

default:
mi = null;
break;
}
}
else {
switch( item.type ) {
case "url":
mi = createMenuItem( item.label, item.tip, item.image );
mi.onclick = function() {
var b = getBrowser();
b.selectedTab = b.addTab( this.onclick.addr );
b.selectedTab.onload = function() {}
};
mi.onclick.addr = item.val;
break;

case "urlForm":
mi = createMenuItem( item.label, item.tip, item.image );
mi.onclick = function() {
var item = this.onclick.item;
var b = getBrowser();
var tab = gBrowser.addTab( item.val.addr );
var newTabBrowser = b.getBrowserForTab( tab );
b.selectedTab = tab;
var lf = function( event ) {
var fields = item.val.fields;
newTabBrowser.removeEventListener( 'load', lf, true );
setTimeout(
function() {
var doc = newTabBrowser.contentDocument;
var inputs = doc.getElementsByTagName( "input" );
for ( var i in fields ) {
for ( var j = 0; j < inputs.length; j++ ) if ( inputs[j].name == i ) inputs[j].value = fields[i];
}
},
100
);
};
newTabBrowser.addEventListener( "load", lf, true );
};
mi.onclick.item = item;
break;

case "js":
mi = createMenuItem( item.label, item.tip, item.image );
mi.onclick = new Function( item.val );
break;

case "submenu":
mi = createMenu( item.label, item.tip, item.image );
mi.appendChild( buildMenu( item.val ) );
break;

case "exec":
mi = createMenuItem( item.label, item.tip, item.image );
mi.onclick = new Function( "this.onclick.executeFile('" + item.val + "')" );
mi.onclick.executeFile = executeFile;
break;

default:
mi = null;
break;
}
}

if ( mi ) menu.appendChild( mi );
}

return menu;
}

this.appendChild( buildMenu( mitems, false ) );


* This source code was highlighted with Source Code Highlighter.



mitems собственно массив наших пунктов меню и самих меню
задатеся JS объектами, поля:
  • label — название пункта меню
  • tip — всплывающая подсказка на пункте ( может быть пустое )
  • image — либо адрес либо dataURL для картинки ( может быть пустое )
  • type — тип пункта:
    • url — открыть страничку, в поле val — адрес странички
    • urlForm — открыть страничку и заполнить нужные поля нужными значениями, поле val:
      {
      "addr": "адрес страницы",
      "fields": {
      "поле1": "значение поля1",
      "поле2": "значение поля2",
      и т.д.
      }
      }


      * This source code was highlighted with Source Code Highlighter.
    • js — запустить JS код, в поле val — JS код
    • exec — запустить приложение, в поле val — полный путь до приложение и его имя — типа «c:/a/b/c.exe», слэши используются обратные
    • submenu — создать подменю, в поле val — массив из наших пунктов-объектов

  • val — зависит от type


image

Ну вот собственно наше расширение и готово, не буду говорить за всех — а мне стало удобней.
И, я надеюсь, пусть на чуток я увеличу количество пользователей такого замечательного браузера ( а может быть чего доброго — и количество разработчиков расширений под него :) )

Очень надеюсь, что моя статья кому-нибудь окажется полезной…

P.S. Полный код кнопки: тут
Теги:firefoxудобстводополнениеextensionwebпрограммированиеjavascript
Хабы: Firefox
Всего голосов 133: ↑125 и ↓8 +117
Просмотры6.3K

Похожие публикации

Лучшие публикации за сутки