Расширения для браузеров очень популярны в наше время. Повод написать какое-либо расширение всегда найдется, и их напашется еще много. В данной статье я хочу рассказать о том как я написал небольшое расширение для google chrome в личных целях. А цель статьи — помощь молодому программисту, с трудом понимающему английский язык. Не каждый на 3ом курсе сможет читать гугловскую документацию, которая есть только на английском. А сделать расширение хочется.
Если поискать, то на русском языке нет ничего толкового по разраб��тке расширений для chrome, только лишь эта статья доступно описывает самые основы.
Данный пост будет более продвинутой версией.
Приступим.
Не хочется вдаваться в самые основы и поэтому рекомендую для начала прочесть эту статью.
Скачайте мое расширение и смотрите код параллельно чтению.
Мы уже примерно знаем, что такое manifest.json и для чего он нужен.
Если кратко, то это основной файл расширения, который сообщает браузеру какими вещами расширение будет пользоваться, и основные параметры (название, описание и тд).
Перейдем непосредственно к моему расширению.
Это простой скрипт, который удаляет со страницы фриланса те объявления, которые мешают искать интересные мне объявления (если точнее, то я ищу лишь долгосрочные проекты). Дополнение к существующему встроенному фильтру.
manifest.json
{
"name":"Ffilter",
"version": "1.0",
"background_page": "bg.html", // имя background страницы.
"icons": {
"48":"icon_48.png",
"128":"icon_128.png"
},
"page_action":{ // действие для текущей страницы
"default_title": "Ffilter",
"default_icon": "icon_19.png",
"default_popup":"popup.html" // имя страницы фильтра
},
"permissions": [ // разрешения
"tabs","http://www.free-lance.ru/*"
],
"content_scripts":[{ // работа с DOM страницы фриланса.
"matches": ["http://www.free-lance.ru/*"],
"js": ["jq.js","script.js"]
}]
}
* This source code was highlighted with Source Code Highlighter.Рассмотрим.
Имя, версия — это всем понятно.
background_page — тут должно лежать имя фоновой страницы. Фоновая страницы — очень важный элемент, хотя для некоторых приложений он и не обязателен. Но в нашем случаи без него не обойтись.Фоновая страницы работает всегда, когда работает расширение (то есть когда оно включено). Она всегда одна и может связываться и управлять всеми остальными элементами.
Иконки нужны разных размеров для отображения в адресной строке, в списке расширений, возле адресной строки.
page_action — важный объект. Он сообщает браузеру, что наше расширение будет индивидуально для каждой вкладки, то есть значок будет выводиться в адресной строке, а не на панели (например gmail checker). Такие расширения как gmail checker не считаются индивидуальными, они открываются один раз для всего браузера (для них в манифесте используется вместо объекта page_action объект browser_action, на картинках соответственно).

default_title, default_icon — название, иконка соответственно.
default_popup — имя html-страницы расширения, которая будет всплывать при нажатии на иконку. Посмотрите предыдущий топик, если не все ясно.
permissions — массив с разрешениями. Нам пригодиться общаться с системным объектом tabs и обращаться к адресу фриланса (имеется в виду не ajax запросы, а js работа со страницей).
content_scripts — важный для нас объект, именно он разрешает пользоваться js на странице фриланса. Мы указываем адрес страницы и указываем js-файлы, которые будут исполнены сразу после загрузки body. Я использую jQuery и определяю свои функции. Порядок имеет значение.
Важно знать, что скрипты расширения не могу видеть объекты/переменные скриптов самой страницы. Это значит, что если у страницы уже есть свой jQuery мы не сможем его использовать, обязательно надо подгрузить свой. Это называется изолированными мирами и это иногда удобно. Скрипты из расширения, конечно же, могут манипулировать DOM.
Идем далее.
Если Вы все верно представили себе то видите, что наше расширение состоит из 3х основных объектов: фоновая страница (одна для всех), окошко с фильтром (для каждой страницы), и скрипты на каждой странице.
Общий алгоритм таков:
Фильтр должен общаться только со скриптом на текущей странице. Скрипт должен только принимать указания от фильтра на текущей странице и исполнять их. И тот и другой не должен общаться с фоновой страницей, но фоновая страница должна контролировать фильтр. Ведь фильтр должен появляться только на странице фриланса. И, кстати говоря, расширение page_action по умолчанию всегда скрыто, и его нужно включать через фоновую страницу, она это и делает когда загружается страница фриланса.

bg.html
chrome.tabs.onUpdated.addListener(function(id,info,tab) {
if(info.url)
if(/free-lance.ru/.test(info.url))
chrome.pageAction.show(id);
});
* This source code was highlighted with Source Code Highlighter.Приведен только js код (только он и нужен).
chrome.tabs — системный объект с которым приходится больше всего работать, как Вы догадались, он отвечает за вкладки.
Мы вешаем свою функцию на событие onUpdated (обновление вкладки, переход по ссылке). В качестве параметров приходят идентификатор вкладки, информация о обновлении, объект самой вкладки. Нам понадобиться информация — она содержит адрес текущей страницы. Мы проверяем фриланс ли это и если да, то у объекта chrome.pageAction вызываем метод show передавая туда идентификатор этой вкладки.
chrome.pageAction — объект отвечающий за расширения внутри адресной строки, и мы просим показать иконку в нужной нам вкладке (где только что открылся фриланс).
Все действия фоновой страницы окончены, сайт открылся, иконка появилась, теперь можно на нее кликнуть и появится popup.html.
popup.html
Нет смысла разбирать весь код, важно только знать как обратиться из этого окошка к скрипту который ждет на странице, как наладить транспорт?
Вообще, в документации сразу предлагают этот способ:
chrome.tabs.executeScript(null, {code:"alert(‘hello!’)"});
* This source code was highlighted with Source Code Highlighter.или можно так:
chrome.tabs.executeScript(null, {file : “script.js”});
* This source code was highlighted with Source Code Highlighter.
Но подумайте, как туда передавать параметры? Только строковые? (к слову говоря, null — это значит, что мы хотим исполнить скрипт на текущей вкладке)Это мне подходило, я искал способ передать объекты. И такой способ нашелся, но он был спрятан в документации.
port — специальный объект в chrome, с помощью которого можно общаться от скрипта к фоновой странице и popup, или от фоновой страницы и popup к скрипту.
Что бы подключиться к скрипту нужно соединяться через табы:
var port = chrome.tabs.connect(id);
* This source code was highlighted with Source Code Highlighter.где id номер нужной вкладки со скриптом. port — возвращенный объект транспорта.
Что бы подключиться к фоновой странице или всплывающему окну нужно обратиться к объекту расширения:
var port = chrome.extension.connect();
* This source code was highlighted with Source Code Highlighter.Расширение одно — идентификатор указывать не надо.
Прослушивать эти подключения можно одинаково и там и там:
chrome.extension.onConnect.addListener(function(port){
port.onMessage.addListener(MyFunc);
});
* This source code was highlighted with Source Code Highlighter.Для чего onMessage станет понятнее позже.
Вернемся к popup.html.
В этом месте я связываюсь со скриптом, который “дежурит” на данной странице.
Для меня стало проблемой то, что нужно указать идентификатор вкладки, а ведь я не знаю этот ИД. Забавно, что нам нужная текущая вкладка, и можно было бы просто послать null вместо номера, но это не пройдет — нужно знать ИД. Как?
Много времени убил на это и сделал вот так:
chrome.windows.getCurrent(function(w){
chrome.tabs.getSelected(w.id,function(t){
port = chrome.tabs.connect(t.id);
})
});
* This source code was highlighted with Source Code Highlighter.Мы просим сказать какое окно сейчас активно, и нам в callback возвращают объект окна. Далее мы просим сказать текущую вкладку в этом окне и нам ее возвращают тоже в callback. И только тогда мы открываем соединение со скриптом.
Это работает, но мне кажется, что это неправильно — должен быть способ проще.
Когда все данные фильтра собраны, по нажатию на кнопку мы отправляем в этот порт объект с помощью метода:
port.postMessage(obj);
* This source code was highlighted with Source Code Highlighter.И в этот момент начинает работать script.js
В script.js важно это:
chrome.extension.onConnect.addListener(function(port){
port.onMessage.addListener(Filtr);
});
* This source code was highlighted with Source Code Highlighter.Прослушиваем порт и дожидаемся входящего подключения с объектом port.
У этого объекта есть событие onMessage — событие когда сюда присылают сообщение. Мы вешаем свою функцию Filtr, которая примет все аргументы, которые пришлют с помощью port.postMessage() на другом конце. Функция Filtr удалит все объявления, которые указаны в объекте.
Все
Вот и все. Это работает и помогает мне в поиске заработка.
Было сложно разбираться без знания английского.
Надеюсь Вам ��ригодится.
Документация, расширение.
