Создание своих собственных расширений для браузера: Часть 2. Расширение возможностей Firefox

Как написать простое расширение для браузера Firefox

У каждого браузера свои сторонники и противники ― и свои преимущества и недостатки. Связывает их то, что люди проводят в браузерах все больше и больше времени. Этот цикл статей посвящен тому, как самостоятельно построить простое расширение для браузеров Chrome, Firefox и Safari. Читатель узнает, как создать расширение для каждого браузера, насколько трудно или легко решаются некоторые типичные задачи и как распространять свое расширение. В этой статье мы построим расширение для браузера Firefox.

Дуэйн О'Брайен, разработчик PHP, EPAM Systems

Дуэйн О'Брайен (Duane O'Brien) был разносторонним специалистом еще в те времена, когда у игры Oregon Trail был только текстовый интерфейс. Его любимый цвет - sushi (суши). Он никогда не бывал на луне.



07.06.2013

Об этом цикле статей

В этом цикле из четырех статей рассматривается процесс создания расширения Gawkblocker для трех браузеров: Chrome, Firefox и Safari.

  • Первая часть посвящена созданию расширения для Google Chrome ― от начала и до App Store.
  • В этой части мы построим дополнение (или расширение) для Mozilla Firefox.
  • В части 3 то же расширение адаптируется для браузера Safari.
  • А в части 4 мы отредактируем код так, чтобы получить расширение, не зависящее от браузера.

Эта вторая статья нашего цикла о создании расширений для браузера учит строить дополнения (или расширения) для Mozilla Firefox. В статье "Создание своих собственных расширений для браузера: Часть 1. Расширение возможностей Chrome" мы построили расширение Gawkblocker для Chrome. Теперь перенесем Gawkblocker Chrome на Firefox. (Полный исходный код приведен в разделе Загрузки).

Gawkblocker: оживление в памяти

Напомним, что Gawkblocker позволяет блокировать определенные домены, которые пользователь предпочитает не посещать, такие как блоги, отнимающие много времени. Gawkblocker содержит несколько компонентов:

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

В Chrome расширение Gawkblocker приставляет к каждой вкладке или окну прослушивающий процесс и сопоставляет URL-адреса с черным списком, перенаправляя заблокированные URL на локальную страницу. Теперь посмотрим, как изменится расширение Gawkblocker в среде Firefox.

Gawkblocker определенным образом проникает в браузер и делает некоторые вещи, типичные для всех расширений, которые создаются в этом цикле статей. Как и в Части 1, нам нужно получить ответы на следующие вопросы:

  • Насколько трудно внедриться в пользовательский интерфейс браузера?
  • Как сохранить данные между сеансами браузера?
  • Как обеспечить взаимодействие разных частей расширения друг с другом?
  • Насколько глубоко можно проникнуть в данные пользователя?

Пройдя процесс создания Gawkblocker для Firefox, мы ответим на эти вопросы.


Перед началом работы

Дополнения и расширения ― одно и то же

В Firefox расширения называются дополнениями (add-ons). Для Chrome, Safari и Internet Explorer используется термин расширения (extensions). В этом цикле статей к дополнениям Firefox применяются оба термина, как синонимы.

Для этой статьи нужно загрузить и установить Firefox 12 или более позднюю версию браузера (см. раздел Ресурсы). (Приведенные здесь примеры основаны на версии 12.) Также понадобится инструмент для редактирования HTML, CSS и JavaScript. Будет полезен и некоторый опыт работы с Firefox и какими-нибудь дополнениями Firefox. Если такого опыта нет, просмотрите расширения на странице Mozilla Add-ons (см. раздел Ресурсы). Попробуйте какие-нибудь расширения в качестве контекста для этой статьи.

Вашим справочным документом будет руководство разработчика Mozilla Add-on SDK (см. раздел Ресурсы). Большую часть работы мы будем выполнять в Add-on Builder — специальном Web-инструменте для создания расширений Firefox. Add-on Builder входит в состав проекта Firefox Jetpack. Цель Jetpack ― облегчить написание расширений с использованием только HTML, CSS и JavaScript (как мы делали в случае расширения Chrome). Имеются и другие способы создания расширений для Firefox.

Полный исходный код приведен в разделе Загрузка.


Анатомия расширения для Firefox

Альтернативные подходы

Помимо процесса, описанного в этой статье, существует ряд других способов создания расширений для Firefox. Можно загрузить файлы SDK, которые Add-on Builder использует прямо из Developer Hub (см. раздел ресурсы). Загрузите файлы SDK, чтобы при создании дополнения можно было использовать свою предпочтительную IDE.

Можно также создавать традиционные (или классические, или XUL) расширения. У этого способа есть определенные недостатки: для установки расширения требуется перезагрузка, и процесс написания такого расширения сложнее. Преимущество же в том, что можно изменять сам браузер, чего не позволяют ни Add-on Builder, ни SDK. Например, с помощью XUL значок своего расширения можно разместить вне панели Add-on. Подробнее об XUL-расширениях можно прочесть на страницах Mozilla Development Network (см. раздел Ресурсы).

Для привлечения необходимых библиотек расширения для Firefox, построенные с помощью Add-on Builder, используют соглашения CommonJS. Расширение может содержать любое сочетание файлов HTML, CSS и JavaScript, но в основе всего лежит файл main.js.

Файл main.js ― фундамент расширения для браузера Firefox. Он указывает Firefox, какие модули привлекать и где решать любые задачи по инициализации расширения. Возвращаясь к Части 1, отметим, что аналогом файла main.js в расширениях для Chrome является страница background.html. Он работает за кулисами ― никто не взаимодействует с ней напрямую ― и выполняется один раз во время запуска.

Может быть также ряд страниц, отображаемых на панелях внутри браузера Firefox. Одну из таких страниц мы будем использовать в качестве комбинированной страницы всплывающего окна и свойств, как показано на рисунке 1.

Рисунок 1. Страница всплывающего окна/свойств
Страница всплывающего окна/свойств Gawkblocker

В Firefox можно использовать и сценарии, почти так же, как в Chrome. Это файлы JavaScript, которые внедряются в Web-страницы для взаимодействия с ними. В Firefox сценарии эффективно работают в контексте страницы, но прямой доступ к ним из DOM и обратно заблокирован во избежание проблем безопасности. Сценарии могут общаться с остальной частью расширения через port.

Для Gawkblocker мы будем использовать:

  • файл main.js;
  • Файл JavaScript, содержащий некоторые основные функции (главным образом перенесенные из расширения Chrome);
  • комбинированную страницу всплывающего окна/свойств;
  • один или пару значков.

Реализация слегка отличается от того, что было в Chrome, но с точки зрения пользователя фактически никакой разницы нет. Рабочее расширение Gawkblocker можно загрузить из моего профиля Add-on Builder (см. раздел Ресурсы), чтобы увидеть его в действии в соответствии с приведенным здесь описанием.


Работа с Add-on Builder

Чтобы использовать Add-on Builder, показанный на рисунке 2 и доступный по адресу https://builder.addons.mozilla.org/, необходимо пройти процесс бесплатной регистрации. Затем можно войти в Add-on Builder и приступить к созданию своих собственных дополнений.

Рисунок 2. Add-on Builder
Mozilla Add-on Builder

Полное описание интерфейса Add-on Builder выходит за рамки темы этой статьи, но нужно отметить два момента, касающихся структуры файлов. Библиотеки, встраиваемые с помощью require, Firefox ищет в каталоге Lib. В этот каталог помещается основной класс JavaScript Gawkblocker. В каталог Data помещаются изображения, HTML, CSS и другие ресурсы, которые может обслуживать ваше расширение.

Когда расширение будет построено и проверено, вам предложат установить помощник Add-on Builder. Этот помощник управляет удалением и установкой дополнений во время разработки.


Редактирование основного класса Gawkblocker

В Части 1 мы написали то, что казалось в разумной мере переносимым файлом основного класса Gawkblocker. Теперь, когда его нужно использовать в расширении для Firefox, можно проверить, в какой степени этот файл класса переносим на самом деле.

Как выясняется, в него необходимо внести несколько важных изменений:

  • использовать API-интерфейс расширений для Firefox simple-storage, вместо localStorage;
  • добавить в exports объект GB.

В файле класса из Части 1 мы определили объект Storage Manager (с именем SM) — оболочку для localStorage— чтобы управлять хранением данных между сеансами. В расширении для Firefox этот код не работает. Вместо этого Firefox предоставляет API-интерфейс simple-storage, сохраняющий данные. Объект Storage Manager из Части 1 легко отредактировать, как показано в листинге 1.

Листинг 1. Редакция объекта SM
var SM = (function () {
    var SS = require("simple-storage");
    var my = {};
 
    my.get = function (key) {
        return SS.storage[key];
    }
    ...

    return my;

}());

Объект GB не требует изменения, но его нужно добавить в exports, соблюдая соглашения CommonJS. Эту задачу решает последняя строка листинга 2.

Листинг 2. Добавление объекта GB в exports
var GB = (function (SM) {
   var my = {};

   my.blockTheseSites = {
       "gawker.com"        : "Gawker Media",
       "io9.com"           : "SciFi Blog",
       "gizmodo.com"       : "Gadget Blog",
       ...
   }

   ...

}(SM));

exports.GB = GB;

Эти мелкие изменения легко внести в объект GB таким образом, чтобы он работал в Firefox или в Chrome. (Я предоставляю это читателю для его собственного проекта).

Переименуйте файл на GB.js и загрузите его в каталог Lib, чтобы научиться использовать объект в файле main.js.


Файл main.js в Gawkblocker

В Chrome мы сверяли URL с черным списком с помощью фоновой страницы. В Firefox эта проверка осуществляется внутри файла main.js. Прежде чем main.js сможет что-нибудь сделать, нужно собрать модули и API, которые планируется использовать, с помощью серии операторов require, как показано в листинге 3.

Листинг 3. Операторы require
var data = require("self").data,
    tabs = require("tabs"),
    GB = require("GB").GB,
    popupPanel = require("panel").Panel({
        height: 500,
        contentURL: data.url("popup.html")
    });

Операторы из листинга 3 последовательно указывают main.js, что надо предоставить:

  • объект, используемый для доступа к каталогу данных;
  • объект для обработки вкладок;
  • объект GB, экспортированный из класса main;
  • Объект popupPanel для хранения всплывающего окна. Этот же код создает всплывающее окно.

Кроме того, так как созданное всплывающее окно также служит в качестве страницы свойств, необходимо настроить некоторые прослушивающие процессы. В Chrome мы обращались к фоновой странице и указывали, что нужно делать. В Firefox для достижения той же цели нужно отправлять сообщения в main.js. Например, в листинге 4 показан прослушивающий процесс, определяющий целевую страницу по умолчанию для сайтов, которые пользователи решили заблокировать.

Листинг 4. Прослушивающий процесс, определяющий целевую страницу по умолчанию для сайтов, которые пользователи решили заблокировать.
popupPanel.port.on("watchthis", function () {
    GB.setWatchThisInstead(http://www.youtube.com/watch?v=N-uyWAe0NhQ);
    console.log("watchthis");
});

Мы станем передавать сообщения на этот порт чуть позже, когда будем говорить о всплывающей странице.

Через тот же файл main.js Gawkblocker обращается к вкладкам, чтобы узнать, какие URL пользователь хочет заблокировать. В листинге 5 приведен код, который "прослушивает" вкладки на наличие изменений.

Листинг 5. Прослушивание вкладок на обновление
tabs.on("ready", function checkForBlock(tab) {
    for (site in GB.getBlockedSites()) {

        if (tab.url.match(site)) {
            tab.url = GB.getWatchThisInstead();
        }
    }
});

Функции и характеристики те же, что для Chrome. API тоже используется аналогичным образом (вызов метода, передача обратного вызова).

Наконец, чтобы добавить значок в нижнем правом углу окна браузера, создадим Widget, как показано в листинге 6.

Листинг 6. Создание виджета
require("widget").Widget({
    id: "GBBrowserAction",
    label: "Gawkblocker",
    contentURL: data.url("images/GB-19.png"),
    panel: popupPanel
});

Когда для файла main.js все готово, можно заняться изменениями для страницы всплывающего окна.


Страница всплывающего окна

В расширении для Chrome страница всплывающего окна была просто списком заблокированных доменов. Теперь самое время пересмотреть эту конструкцию. В расширении для Firefox эта функциональность переходит со страницы свойств на страницу всплывающего окна. А к заголовку, отображаемому на странице всплывающего окна, добавляется обработчик кликов, который меняет параметры div и список доменов. Параметры позволяют сайтам пользователя обращаться к черному списку и указывать адрес перенаправления для заблокированных сайтов. На рисунке 3 показаны параметры, настраиваемые на странице всплывающего окна Gawkblocker.

Рисунок 3. Параметры на странице всплывающего окна Gawkblocker
Параметры на странице всплывающего окна Gawkblocker

Настраивая порт в листинге 4, не забудьте прослушивать watchthis в файле main.js. В листинге 7 это сообщение со страницы всплывающего окна передается с использованием addon.port.emit.

Листинг 7. Отправка сообщения со страницы всплывающего окна с использованием addon.port.emit
$("#watchthis").click(function () {
    addon.port.emit("watchthis");
    $("#status").text("YOU'RE GOOD MATE.  ");
});

Прослушивая также список с использованием port, получаем от файла main.js перечень заблокированных сайтов. В main.js список передается, когда страница всплывающего окна сообщает, что она готова, как показано в листинге 8.

Листинг 8. Отправка списка, когда объект всплывающего окна сообщает, что он готов
popupPanel.port.on("pop", function () {
    popupPanel.port.emit("blocklist", GB.getBlockedSites());
    ...
});

А в объекте всплывающего окна он прослушивается, и в страницу вносятся изменения, как показано в листинге 9.

Листинг 9. Прослушивание и изменение страницы
addon.port.on("blocklist", function (blocklist) {
    $("#blockedlist").children().remove();
    $.each(blocklist, function (index, value) {
        $("#blockedlist").append("<div class='siterow' title='"+value+"'>
<div class='sitename'>"+index+"</div><span class='sitedesc'> : 
"+value+"</span></div>");
        showBlockList(blocklist);
    });
});

Всплывающее окно обращается к main.js за списком заблокированных сайтов. Затем этот список просматривается, и информация о заблокированных сайтах добавляется для отображения в тег div всплывающего окна.


Целевая страница переадресации

В Chrome мы делали переадресацию на целевую страницу, которая была частью расширения. В Firefox это не работает, поэтому переадресуем запросы прямо к источнику (URL YouTube, встроенный в целевую страницу: "Эй! Туда не ходи! Сюда ходи!").

Первоначальное условие переадресации задается в файле main. JS, как показано в листинге 10.

Листинг 10. Задание первоначального условия
if (!GB.getWatchThisInstead()) {
   GB.setWatchThisInstead("http://www.youtube.com/watch?v=N-uyWAe0NhQ");
}

Целевая страница переадресации показана на рисунке 4.

Рисунок 4. Целевая страница переадресации
Целевая страница переадресации

Тестирование из Add-on Builder

При использовании Add-on Builder Firefox облегчает тестирование расширения по ходу разработки. Вы получаете консоль ошибок, кнопку test и помощника Add-on Builder, который автоматически перезагружает расширение после каждого сохранения. Рисунок 5 демонстрирует Add-on Builder в действии.

Рисунок 5. Утилиты Add-on Builder
Утилиты Add-on Builder

Распространение расширения

Когда расширение готово к прайм-тайм, вам предоставляется несколько возможностей для его распространения. Если вы отметите его в своем профиле Add-on как public, то сможете отправлять ссылки потенциальным пользователям, чтобы те установили его. Иначе, можно распространять расширение, упакованное для загрузки, или отправить его на addons.mozilla.org.

Распространение упакованного расширения

Чтобы распространять упакованное расширение, загрузите его из Add-on Builder. Щелкните на значке Download, чтобы получить файл XPI, который может установить каждый. Этот файл можно распространять любым способом (по электронной почте, через хостинг, посредством установщиков и т.п.). Но обработка обновлений и хостинг остаются вашей заботой.

Загрузка на addons.mozilla.org

Процесс помещения расширения на addons.mozilla.org требует меньшего технического участия, чем самостоятельное распространение расширения, но вам придется пройти процесс проверки и преодолеть некоторые другие препоны. Нажмите на ссылку upload to АМО рядом с расширением в своем профиле, как показано на рисунке 6.

Рисунок 6. Загрузка в АМО
Загрузка в АМО

Далее следуйте инструкциям по загрузке.


Ответы на вопросы

Теперь, когда расширение для Firefox готово, самое время посмотреть, как выглядят ответы на наши вопросы по сравнению с Chrome.

Насколько трудно внедриться в пользовательский интерфейс браузера?
Не намного труднее, чем в Chrome, если требуется присутствие на панели Add-on Bar в нижней части окна браузера. Это достигается созданием Widget в файле main.js.
Как сохранять данные между сеансами браузера?
Используя специальный API simple-storage Firefox. Если нужно, чтобы класс Storage Manager работал в Chrome и в Firefox, реализуйте функцию определения браузера.
Как разные части расширения взаимодействуют друг с другом?
Такого рода связь создается с помощью порта и настройки прослушивающих процессов и источников.
Насколько глубоко можно проникнуть в данные пользователя?
Можно получить доступ как минимум к каждому URL, который посетил пользователь, без явного на то разрешения от пользователя. То есть довольно глубоко.

Заключение

Расширение - это только начало того, что можно делать внутри дополнения к Firefox. До пределов возможностей, предоставляемых Add-on Builder, еще очень и очень далеко. А если вы решите углубиться дальше, то их будет еще больше. Существует множество способов углубиться в Firefox, от Add-on Builder до Add-on SDK и более сложных XUL-расширений.

Ждите третью статью этого цикла, в которой мы перенесем Gawkblocker в браузере Safari.


Загрузка

ОписаниеИмяРазмер
Исходный код для статьиfirefox-sourcecode.zip38 KБ

Ресурсы

Научиться

Получить продукты и технологии

  • Mozilla Firefox: загрузите Firefox для своей платформы.
  • Add-on SDK: загрузите SDK.
  • Add-on Builder: здесь находится Add-on Builder.
  • Gawkblocker: загрузите Gawkblocker из профиля Add-on Builder автора.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source, Web-архитектура
ArticleID=932970
ArticleTitle=Создание своих собственных расширений для браузера: Часть 2. Расширение возможностей Firefox
publish-date=06072013