Итак, после обновления Firefox до 19 версии, полностью отвалилось горячо любимое расширение Яндекс.Бар. Не забуду напомнить, что Яндекс.Бар был заменен Яндекс.Элементами, которые понравились чуть больше, чем никому, поэтому и получили свои заслуженные 2 бала из 5ти.
Почему не понравились? Заменили адресную строку, стало неудобно просматривать почту, заменили закладки и убрали корректор адресной строки (под предлогом установки Punto Switcher, который может и хорош для обычного работника, но никак не для программиста. Поэтому и был удален почти сразу же, как установлен. Да и если можно было бы настроить, то всё равно желание пропало).
Немного погодя было решено создать свое подобное расширение, которое будет включать в себя такие плюшки, как просмотр почты и корректор адресной строки. Чтож, раз не ты, так кто другой?
Первым делом решено было не создавать свой велосипед и воскресить Яндекс.Бар, который не хотел работать в 19 версии браузера. В интернете подсказали, что расширение — это обычный zip архив. Открыли, посмотрели, ужаснулись и закрыли. Воскресить не удалось, даже при всем желании.
Тогда заходим в центр разработчика: builder.addons.mozilla.org/. Я предпочел орудовать в веб-редакторе, хоть местами он иногда не очень гладко работал. Посмотрев на другие расширения, позаимствовав код и немного поняв весь смысл сея устройства, началось сначала всё со стенобитной машины и закончилось надфилем.
Билдер включает в себя 3 раздела: это раздел со скриптами (Lib), раздел с загружаемым контентом (картинки, стили и скрипты) и раздел с готовыми библиотеками (Libraries)
Кстати, вот документация: addons.mozilla.org/en-US/developers/docs/sdk/latest/, добротно написанная.
Старт расширения начинается с загрузки файла main.js.
Вызывается функция: exports.main.
Пример файла main.js:
const tabs = require("tabs");
exports.main = function (options) {
tabs.on("ready", function(tab){
tab.attach({
contentScript: "document.addEventListener('click', function(e) {
var target = e.target;
if(target.tagName == 'A') {
var mail_to = target.href.match(/^mailto:(.*)/i);
if(mail_to != null) {
e.preventDefault();
var form = document.createElement('form');
form.setAttribute('action','http://mail.yandex.ru/neo2/#compose/mailto=' + mail_to[1]);
form.setAttribute('target','_blank');
document.getElementsByTagName('body')[0].appendChild(form);
form.submit();
form.parentNode.removeChild(form);
}
}
}, false);"
});
});
}
Что же за магия происходит в этом коде?
Первым делом подключается модуль tabs.
В данном случае он служит для того, чтобы можно было добавлять свой JavaScript код в страницу браузера.
Т.е. что у нас: при событии документа onready происходит добавление любого JavaScript кода в тело документа. В данном примере добавляется обработчик ссылок, у которых адрес начинается с mailto.
Ладно, давайте что-нибудь посложнее сделаем. Добавим-ка свою кнопку в верхний бар!
Опять же, не будем строить велосипеды, а с чистой совестью возьмем уже готовую библиотеку Toolbar Button Complete.
В ней же есть пример добавления кнопки в бар браузера. Я думаю, не стоит его сюда вываливать, т.к. там многоватенько кода.
Итак, кнопка есть, иконку поставили, всё вроде хорошо, но не очень. Как же у нас в Яндекс.Баре было? Ах да, напротив иконки еще и счетчик непрочитанных сообщений был.
Тут я разузнал несколько путей добавления счетчика:
- универсальный, но более легкий (с помощью стилей)
- не слишком универсальный, но не такой простой, как первый (с помощью canvas)
Второй способ, правда, нашелся методом тыка в интернет. Но я взял первый.
Нам известно, что верхний бар — это такой же набор элементов со своими классами, идентификаторами, свойствами и способами работы с ними.
Методом тыка типа:
for(var val in document.getElementById('yandex-menu')) {
console.log(val);
}
было обнаружено, что методы в точности совпадают с теми, что мы обычно используем при работе с элементами сайта. Но замечу, что по стандарту браузер не знает, что такое ни document, ни window в расширениях (да и еще есть отличия).
Пример решения:
var wuntils = require('sdk/window/utils');
var window = wuntils.getMostRecentBrowserWindow();
var document = window.document;
Замечу, что разработка билдера не стоит на месте и если раньше способ получения активного окна был таким:
var winUtils = require("window-utils");
for (window in winUtils.windowIterator()) {
if ("chrome://browser/content/browser.xul" != window.location) return;
console.log("An open window! " + window.location);
}
то сейчас всё намного легче (пример я выше привел).
Чтож, немного рассказав о особенностях, вернусь к добавлению счетчика для кнопки.
Умные люди подсказали, что по стандарту стиль поля label у кнопки равен display: none;, поэтому как-то нужно было внедрить свой css код в бар. Решение, как оказалось, не сложное (советую завернуть в файл, который будет инклюдится по мере надобности):
const { Cc, Ci } = require('chrome');
const { when: unload } = require('sdk/system/unload');
var ios = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
/* Helper that registers style sheets and remembers to unregister on unload */
exports.addXULStylesheet = function addXULStylesheet(url) {
var uri = newURI(url);
var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
unload(function () {
if (sss.sheetRegistered(uri, sss.USER_SHEET)) {
sss.unregisterSheet(uri, sss.USER_SHEET);
}
});
return sss;
};
function newURI(uriStr, base) {
try {
var baseURI = base ? ios.newURI(base, null, null) : null;
return ios.newURI(uriStr, null, baseURI);
}
catch (e) {
if (e.result === chrome.Cr.NS_ERROR_MALFORMED_URI) {
throw new Error("malformed URI: " + uriStr);
} else if (e.result === chrome.Cr.NS_ERROR_FAILURE ||
e.result === chrome.Cr.NS_ERROR_ILLEGAL_VALUE) {
throw new Error("invalid URI: " + uriStr);
}
}
return null;
}
И в функцию exprorts.main добавляем что-то вроде (хотя добавлять можете куда угодно):
stylesheet.addXULStylesheet(data.url("stylesheet.css"));
не забыв создать в контенте файл stylesheet.css.
У меня файл содержит примерно следующее:
#yandex-mail {
min-width: 16px;
}
#yandex-mail .toolbarbutton-text {
float: right !important;
display: inline-block !important;
font-size: 13px;
padding-left:20px;
background: url(data:image/png;base64,iVB.............OCYII=) no-repeat left center;
}
#yandex-mail .toolbarbutton-icon {
display: none;
}
Почему мы скрываем иконку и добавляем фон? Всё потому, что если этого не сделать, то блоки всегда отображаются как display: block, какие бы значения я не выставлял (кстати, может кто знает по этой теме?) Поэтому и приходится так хитрить.
Также столкнулся с вопросом загрузки контента с других сайтов и парсинг xml.
С первым быстро разобрался, далеко ходить не надо: Request
А вот со вторым пришлось повозиться.
Как мы знаем, получить dom xml документа можно с помощью нескольких функций:
- XMLHttpRequest — отпал, т.к. выдало ошибку кроссдоменного запроса (может я не так что-то делал?)
- DOMParser — но тут тоже пришлось повозиться
В чем собственно возня: как и с получением window, так и тут:
var {Cc, Ci} = require("chrome");
var parser = Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
var dom = parser.parseFromString(xmlPrepare (text), "application/xml");
Вот так создание расширений для Firefox ничем не отличается от создания плагинов для jQuery :)
Кстати, конечное творение на сей день: CustomYandexBar, пока находится на проверке. Исходники, в них много чего полезного.
Если кому-нибудь не понравится, что использую «их» картинки, бренд или т.п. — пишите.
Автор: lampa