Pull to refresh

Chrome extension — с шахматами и библиотекаршами

Reading time3 min
Views18K
Добрый день, любители ездить на чужих велосипедах, у которых нет сиденья, педали надо крутить руками, а тормоза появятся через пару релизов.

Задача:
Создать расширение для браузера Chrome, которое сможет в любой из открытых табов внедрить необходимый контент и небольшой управляющий модуль для него, и если этот контент внедрен в несколько разных табов, то управляющие модули должны иметь возможность между собой общаться.

Доступные инструменты:
Content Scripts, Background Pages, Message Passing

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



Абстрактный пример:
Общий управляющий модуль (ОУМ), создал 3 потомка (П1, П2, П3), каждый из которых работает в отдельной вкладке. Пользователь произвел действие с П1, П1 используя механизм обратной связи отправил сообщение об этом ОУМу, ОУМ совершил необходимые действия и оповестил П2, П3 о произошедших изменениях.

Конкретный пример:
Пользователь решил в 3 табах использовать расширение, которое меняет бекграунд, в одной из них он решил что его не устраивает новый зеленый фон и он хочет что бы новый фон был светло серым. Он нажимает кнопку которая внедрилась в страницу при открытии, фон страницы меняется на серый, то же самое происходит в остальных 2 табах.

Реализация:
Создаем Background Page которая создается раз и навсегда на время жизни расширения, в нем будем держать общий управляющий модуль (ОУМ).

Когда пользователь входит на страницу и хочет использовать на ней возможности расширения, он нажимает на кнопку расширения, запуская тем самым основной функционал, который внедряет в контент выбранного таба небольшой командный модуль (КМ) (фронтенд html и бекенд javascript), также расширение производит необходимые действия c этим контентом.
main.js
chrome.tabs.executeScript(null, {file: "content_script.js"}); // внедряем командный модуль
// совершаем какие то действия с контентом


Как только модуль внедрился он посылает сообщение ОУМу.
content_script.js
chrome.extension.sendMessage({cmd: "tab_add"}, function(response) {}); // отправляем сообщение ОУМу
chrome.extension.onMessage.addListener(ext_msg_listener); // создаем слушатель команд от ОУМ

function ext_msg_listener () {
  var cmd = arguments[0].cmd;
  ...
}


ОУМ берет из сообщения идентификатор таба и кладет его в список табов для оповещения.
background.js
chrome.extension.onMessage.addListener(
  function(request, sender, send_response) {
    if (request.cmd == "tab_add") {
      // добавляем в список для оповещения идентификатор таба = sender.tab.id
    }
    ...
  }
)


При совершении пользователем действий с КМ, КМ отсылает сообщение ОУМу.
content_script.js
chrome.extension.sendMessage({cmd: "some_msg_from_km"}, function(response) {})


ОУМ, если это необходимо оповещает КМы из списка.
background.js
chrome.extension.onMessage.addListener(
  function(request, sender, send_response) {
    ...
    if (request.cmd == "some_msg_from_km") {
      // каждому tab_id из списка отсылаем сообщение
      chrome.tabs.sendMessage(tab_id, {cmd: 'some_command_from_oum', bar: 'buz'}, null)
    }
    ...
  }
)


КМ слушает сообщения и услышав необходимую команду от ОУМа выполняет действия.
content_script.js
function ext_msg_listener () {
  ...
  if (cmd=="some_command_from_oum") {
    // делаем что необходимо
  }
}


Когда КМ закрывается пользователем, перед закрытием он оповещает ОУМ.
content_script.js
chrome.extension.onMessage.removeListener(ext_msg_listener);
chrome.extension.sendMessage({cmd: "tab_remove"}, function(response) {}); // сообщаем ОУМу о закрытии КМ


Соответственно из списка идентификатор таба убирается.
background.js
chrome.extension.onMessage.addListener(
  function(request, sender, send_response) {
    ...
    if (request.cmd == "tab_remove") {
      // убираем из списка оповещения идентификатор таба = sender.tab.id
    }
  }
)


Немного обо мне:
Пишу фронтенды на html+js или objective-c, бекэнды на php или руби (sinatra). Люблю делать интерактивные приложения для IOS, особенно игры. В одно время надо было написать приложение с использованием OpenGL ES 2.0, но все фреймворки тогда сидели на 1.1, пришлось писать свой, увлекательное было занятие, если есть конкретные вопросы по OpenGL ES 2.0 — задавайте, отвечу.

PS:
Небольшое замечание для тех, кому режет глаз смешение русского текста и иностранных названий. Я придерживаюсь позиции, что если писать название в оригинале, то будет проще искать информацию в первоисточниках.

Можно также было не отправлять сообщения каждый раз, а открыть одно постоянное соединение между КМ и ОУМ.

Если что то требует более обширного объяснения — задавайте вопросы, дополню.
Tags:
Hubs:
+7
Comments5

Articles