Пишем своё расширение для браузера Mozilla Firefox

  • Tutorial
Итак, после обновления 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, пока находится на проверке. Исходники, в них много чего полезного.

Если кому-нибудь не понравится, что использую «их» картинки, бренд или т.п. — пишите.
Метки:
Поделиться публикацией
Похожие публикации
Комментарии 48
  • +32
    — Итак, после обновления Firefox до 19 версии, полностью отвалился горячо любимый плагин Яндекс.Бар.
    Разве это не хорошая новость?
    • –5
      Мне было удобно, когда стоял данный плагин. Причины описаны в статье.
      • +13
        Однозначно хорошая. Никогда не любил всякие бары, особенно за их навязчивость.
        • 0
          Я использовал бар для перевода слов на странице в лингво наведением на них курсора мыши.

          Да, держать целый бар ради одной этой функции как-то жирно, но другого аддона с этой функциональностью найти не удалось.
          • 0
            Ну, «элементы» это таки умеют, хотя часть их функций отключить стоит сразу после установки
            • 0
              Элементы оказались для меня бесполезны в этом плане. Упорно переводят с русского на англияский, хотя мне нужно наоборот :-D
              Подозреваю, что из-за того что у меня LC_MESSAGES=en_US.utf8 (всё остальное, включая LANG — ru_RU.utf8).

              Снём элементы нафиг.
              • 0
                Ну да, в плане допиленности они никакие — лично я постеснялся бы настолько сырой продукт выводить на рынок, да ещё ломая устоявшиеся привычки пользователей и сжигая мосты. В этом плане руководители проекта не вызывают ни малейших тёплых чувств…
            • 0
              Обновил расширение — теперь функция перевода слов при наведении присутствует.
              • 0
                Вы об «элементах»? Когда я писал свой комментарий, эта функция там уже была. Но в бесполезном для меня варианте (см. мой каммент выше)
                • 0
                  Нет, я о своём расширении, смотрите скриншот:

                  image

          • +10
            Как странен мир. Кто-то убивается, чтоб избавиться от штатного «Бара», а кто-то пишет себе свой…
            • +1
              Всё логично. Бары от интернет-гигантов не любят из-за того, что они сливают персональную информацию (как минимум — все посещённые URL-ы). Если делать свой бар, то этого недостатка не будет — одни профиты.
            • +6
              Вроде как это называется не плагин, а расширение (addon, extension). Плагины для firefox — это библиотеки на базе NPAPI.
              • +1
                Спасибо, исправил.
              • +1
                убрали корректор адресной строки (под предлогом установки Punto Switcher, который может и хорош для обычного работника, но никак не для программиста)
                Согласен, сам какое-то время ставил только из-за этой функции его.
                • +2
                  Возможность открывать mailto: ссылки в Яндекс почте есть в настройках Firefox.
                  • +1
                    До чего же запутанное sdk у firefox'a для расширений. простые вещи делаются через какие-то дебри. Ещё и sdk надо ставить, а с ним питона. Отладка через ChromeBug это вообще что-то с чем-то. Пытался перенести своё расширение для рехостинга картинок, вот с XMLHttpRequest как раз одна из проблем. Чтобы выполнять кросдоменные запросы надо использовать его по другому — импортировать эту функцию из XPCOM (на stackoverflow нашёл подобные же проблемы). А там вообще без поллитры никак. Но всё убил баг с BLOBом который никто не хотел фиксить, а у меня не хватает квалификации. Насколько же проще делать расширения для Хрома, просто день и ночь.
                    • 0
                      Отчасти вы правы, я только из-за заморок с установкой sdk делал проект через веб-интерфейс. Отладкой занимался через консоль ошибок, встроенную в браузер.
                      • +2
                        Про SDK это вы наверно пошутили.
                        А вообще, да, писать расширения для Firefox намного сложнее чем для Chrome (ну, в простых случаях), зато глубина кастомизации у Firefox-расширений просто бесконечная, чего не скажешь о Chrome.
                        • +1
                          Попробуйте переслать blob через XMLHttpRequest. Я никакого пути не нашёл. imgur видимо тоже и написали свой плагин целиком на java для firefox'a. Вот тут в Upload.js простейший код.. Правда, буду очень признателен.
                        • 0
                          На сколько проще писать расширение для Хрома, на столько проще они и по функциональности. 99% расширений, расширяют не сам Хром а странички сайтов. Ограничения в Хроме — выше крыши. Реально, не видел под хром расширений уровня FireBug (понятно что в самом хроме есть неплохая встроенная замена).
                          • 0
                            API хрома постоянно совершенствуется. И вообще хотелось бы больше примеров кроме firebug'a. Тот же chrome bug, повторюсь, вообще трудно использовать. А больше никак расширения под firefox не отладить.
                            • 0
                              Мне сейчас сложно сразу выкатить список расширений, так как сижу уже на Chromium (что ни говори, но он быстрее FF и меньше проблем с Flash) причем Chromium пиленый, с возможностью Открыть/Сохранить файл (долго не мог из-за этой фичи, перейти с FF на Chrome пока не нашел этот кастом). Но как пример, я не видел под хром расширений вида самого браузера, ну например Download Statusbar (помню использовал под FF). На сколько я понимаю, расширения хрома не умеют изменять/встраиваться в интерфейс браузера.
                              • 0
                                Я даже скажу, что запрет изменения интерфейса это благо. Да, есть вещи более функциональные, тот же адблок, но хром-то на месте не стоит, а даже бежит. Вот они уже выкатили в dev ветке высокопроизводительный api для мониторинга URI и подмены, там даже функции готовые есть — вернуть пустой документ.
                                да достаточно взглянуть на магазин хрома — прямо рай для юзера, и игрушки и всякие интерфейсы к сайтам превращающие их в приложения — всего валом. А из-за очень сложного api в FF вообще сложно даже начать. И это при том, что это JetPack — вообще призван помогать в быстрой разработке. К тому же я сомневаюсь, что все эти возможности вообще нужны основной массе. Лучше бы разработку упростили.

                                • +1
                                  Во-во… Взгляд на магазин Хрома — это как придти на радио рынок, увидеть циган с медведем, клоунов, цирк шапито и не найти нужной детали (а если и найдете то окажется, что деталь — всего обертка). Конечно хром сам развивается быстро и многие онлайн сервисы чаще выкатывают расширение под хром чем под FF.
                                  Зачем нужны эти игрушки, если в них можно играть зайдя на сайт? Как это расширяет функциональность браузера?
                                  Про благо расширения интерфейса браузера, могу сказать следующее:
                                  Одни из 2 частых вопросов про Хром это:
                                  1. Как сделать так что бы он предлагал не только сохранить файл но и открыть (сохранив в Temp который потом очищается).
                                  2. Как изменить DownloadBar что бы…
                                  И тут ответ один — никак пока это не сделают в браузере, и да, это противоречит модели безопасности Google.

                                  • 0
                                    Более того — в хром даже пытались впилить закладки как в файрфоксе — боковой панелью и пару версий они продержались, пока в очередном релизе это не обломали…
                            • 0
                              Ну вот в моём примере наоборот. И пока этот баг не уберут, будет невозможно.
                              • 0
                                Да ну, вы явно драматизируете. Под Chrome тоже существуют и можно писать много функциональных расширений. Благо, API даёт почти безграничные возможности. Как насчёт замены страниц истории, новой вкладки? Да и вообще доступ почти ко всем пользовательским данным, хранящимся в браузере
                                Суть расширений – в предоставлении пользователю каких-то полезных функций, которые нет смысла делать в самом браузере. И при этом не обязательна глубокая интеграция и вообще кастомизация браузера.
                                Почему только на firebug равняться?
                                • 0
                                  Замена страниц истории и новой вкладки (привет Speed Dial 2) это конечно хорошо, но это не глубокая кастомизация.
                                  Дайте мне другой Download Bar. В FF это реально.
                                  Я про такой уровень кастомизации.
                            • 0
                              Как только напишете свое первое расширение, обязательно приходите к нам на собеседование: company.yandex.ru/job/vacancies/javascript_developer.xml
                              • 0
                                А мотоцикл дадут?
                                • +1
                                  Самокат подарим!
                              • –8
                                Firefox медленно умирает. У них каша с документацией, она или незаконченная или помеченая как устаревшая, и с каждой страницы еще 10 страниц нужно открывать. Еще они не брезгуют убирать фичи которые им показались уже не нужными. Ну а самая большая проблема — это ревью плагина при паблишинге. Такое впечатление что там роботы работают. Уже второй раз завернули плагин ибо им показалось что jQuery включеная в плагин неофициальная (видимо хеш не сходится), уже третюю либу вставляем с официального сайта. И каждый раз нужно ждать несколько недель пока они соизвоолят бегло проверить расширение галимым скриптом. Тоже самое касается упакованых либ — они им не подходят так как облажались они с независимостью плагинов, разделением процессов и областью исполнения кода.

                                И да, он до сих пор самый медленный в джаваскрипте, благо вебворкеры помогли вынести функционал в отдельный поток. На других браузерах тот-же самый функционал так заметно не тормозил

                                То что они сейчас выкатывают СДК для разработки расширений конечно и хорошо, но с другой стороны почему Хром сразу сделал раз и нормально?! Уже не говоря о том что серьезные вещи пока не поддерживаются и приходится кодить все вручную без СДК.

                                А плагины для мобильного файрфокса — отдельная песня. Они уже трижды меняли архитектуру без обратной совместимости. А я чуть голову себе не сломал при подгоне расширения к последнему файрфоксу с Native UI. Оказывается у них аддоны с SD-карточки не читаются в запакованом виде. И люди жаловались, тикеты открывали — а мозиловцы лишь вонтфикс и ворксформи ставили. И уж потом я где-то случайно нарыл решение этой проблемы
                                • 0
                                  Зачем jQuery в плагине???? o_O
                                  Чем не устроили родные функции, что вы решились прикрутить дополнительные 40кб?

                                  И почему я, написав тонну расширений, не замечал никакого дискомфорта с документацией?
                                  Документация у них отличная и почти всегда на все вопросы можно найти ответы.

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

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

                                  Кроме того, если уж говорить про хром — расширения под FF имеют в ущерб простоты гораздо более глубокую кастомизацию,
                                  но если честно, то и сложность их не настолько критична.
                                  • 0
                                    jQuery используется в построении интерфейса над логикой которого работает дизайнер, а не я, потому и используется им эта либа. Хотя я лично сторонник использовать личную реализицию нужных фич в плагинах

                                    Кастомизация действительно на высоте, но Мозилла думаю со временем ее зарубает (сдк тому явный признак), так как безопасность страдает при этом. Ведь у них даже свои требования к стилю написания кода, названия переменных и свойств, а так-же классов css и айдешек елементов во избежание конфликтов с другими плагинами и самим файрфоксом, и все это зарубывается на этапе паблишинга плагина. И думаю правила эти придумали довольно недавно, так как в других плагинах этого нету ибо раньше проверка была не столь критична.

                                    А вы работали с расширениями не требующими рестарта браузера? Да, СДК сейчас старается сглаживает боль, но раньше когда его не было нужно было всегда за собой «подтирать» при выключении/удалении плагина, а это порой нетривиально, так как забыть о чем-то довольно дегко. Не понимаю почему в других браузерах сей процесс автоматизирован?

                                    А насчет документации, возможно мое мнение подпортила документация по Firefox OS, вот там жуть полная, я так и не нашел нормальной информации как сделать приложение-сервис. А общение с поддержкой ни к чему не привело, молчание в ответ. И главное нужное апи вроде и есть, да вот информации по нему нету.

                                    Да, я тоже написал много расширений для всех популярных браузеров, и вот такое у меня мнение сложилось про файрфокс неспроста, а на опыте
                                  • 0
                                    > почему Хром сразу сделал раз и нормально?!

                                    Честно говоря, если заглянуть в «Adblock Plus — Bug reports» так не кажется.
                                  • +2
                                    горячо любимое расширение Яндекс.Бар
                                    горячо любимое
                                    HAHAHA OH WOW
                                    (куда более горячо любимый Habrastorage не пускает к загрузке файлов, говоря о нужности авторизации на Хабрахабре)
                                    • +1
                                      Если что-то не так в орфографии — напишите мне, я исправлю. Про «горячо любимое» — так я выразил свои эмоции данному продукту :)
                                      • +1
                                        Вы на самом деле не представляете, скольким людям это приложение нравилось. Хотя политика «впарить всем» — реально отвратительна.
                                      • 0
                                        > создать свое подобное расширение, которое будет включать в себя такие плюшки, как просмотр почты и корректор адресной строки

                                        Про настройку mailto: уже написали, а для адресной строки есть скажем UrlCorrector. Хотя в адресах сейчас встречается всё больше кириллицы, что уменьшает полезность подобных расширений. В ближайшей перспективе, видимо действительно будет удобнее пользоваться пунто (с ручной коррекцией по scroll lock).
                                        ______

                                        Да, тут выше критиковали сложность фоксовых расширений. Упомяну что небольшие вещи (не только кнопки) довольно удобно делать в виде Сustom Buttons, правда необходимо и само расширение. См. например, forum.mozilla-russia.org/viewforum.php?id=34
                                        • +1
                                          Вместе с «Баром» почили в бозе и визуальные закладки Яндекса. А то, что предложили взамен — тоже не совсем оно. В общем, история та же — написал для себя замену. Но наверно было бы глупо и эгоистично не поделиться со всеми, следуя примеру топикстартера. Если что, сильно не пинайте — писалось для себя :-)
                                          • 0
                                            под предлогом установки Punto Switcher, который может и хорош для обычного работника, но никак не для программиста

                                            при клике правой кнопкой по иконке Пунто в трее есть опция «Автопереключение», снимаете птичку и конвертация только по Break

                                            P.S. а еще в пунто мне понравилось переключать раскладки по КапсЛоку — намного быстрее как Ctrl+Shift, так и Command+Space как на Маке. Все равно никто уже почти не пользуется капсом.
                                            • +1
                                              Не менее удобно переключать между двумя часто используемыми языками одиночным левым и правым Ctrl — всегда знаешь, на какой язык переключился.
                                            • 0
                                              Аддоны для FF несколько запутаннее аддонов для Chrome, но если разобраться, всё не так плохо.

                                              Как мы знаем, получить dom xml документа можно с помощью нескольких функций:
                                              XMLHttpRequest — отпал, т.к. выдало ошибку кроссдоменного запроса (может я не так что-то делал?)


                                              Кроссдоменные запросы делать можно, только немного не так. Из контент-скриптов запросы делать нельзя, их надо делать по особому:

                                              function get_alexa_rank(url) {
                                              		var Request = require("request").Request;
                                              		Request({
                                              			url: "some url',
                                              			onComplete: function (response) {
                                              				worker.port.emit('message1', response.text);
                                              			}
                                              		}).get();
                                              
                                              	}
                                              
                                              	function get_google_pr(url) {
                                              		var Request = require("request").Request;
                                              		Request({
                                              			url: 'some url',
                                              			onComplete: function (response) {
                                              				var google_pr = response.text;
                                              				google_pr = google_pr.charAt(google_pr.length - 2);
                                              				worker.port.emit('message2', google_pr);
                                              			}
                                              		}).get();
                                              }
                                              


                                              На стороне контент-скрипта листенеры выглядят так:

                                              self.port.on("message1", function(addonMessage) {
                                              		var alexaRaw = $.parseXML(addonMessage),
                                              			alexa = $(alexaRaw).find('POPULARITY').attr('TEXT');
                                              		if (alexa === undefined) {
                                              			$('#alexa_rank').text('No data');
                                              		} else {
                                              			$('#alexa_rank').text(alexa);
                                              		}
                                              
                                              	});
                                              	self.port.on("message2", function(addonMessage) {
                                              		if (addonMessage === '') {
                                              			$('#google_pr').text('0');
                                              		} else {
                                              			$('#google_pr').text(addonMessage);
                                              		}
                                              	});
                                              
                                              


                                              Гуглите модуль Request и передачу сообщений к контент-скриптам и обратно.
                                              • 0
                                                Спасибо за ответ! Про модуль Request у меня написано в статье. Модуль легкий, по этому всего одно предложение) Наверно вы и не заметили.
                                              • +1
                                                Мне по части перевода всего и всея в адресной строке понравилась реализация отсюда: addons.mozilla.org/en-us/firefox/addon/input-language-assistant/
                                                Во-первых не запрещает писать русские буквы, если они нужны, во-вторых не добавляет кнопок, в-третьих ему похоже плевать на раскладки). А что отвалилось то в отжившем своё баре? Он вроде давно «не совместим», но работает, не?
                                                • 0
                                                  Спасибо за статью.
                                                  Придется мне в этом деле тоже поразобраться. Мой давно юзаемый LastPass продался в Logmein. Понимаю, что может быть это и паранойя. Но я не люблю вот такие вот закиды.

                                                  Никогда не писал плагины для FireFox, но похоже будет проще разобраться с этим, чем вспоминать (почти наугад по остатком 5-ей летней давности) как через WinAPI добраться до полей ввода на странице и загонять туба из базы парольчики.

                                                  Буду делать маленькую персональную замену для LastPass
                                                  • 0
                                                    Ничего сложного, я смотрел в том году сдк, его допилили, убрали онлайн версию и вообще всё стало хорошо) Не написали еще?

                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.