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

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

Задача:
Создать расширение для браузера 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:
Небольшое замечание для тех, кому режет глаз смешение русского текста и иностранных названий. Я придерживаюсь позиции, что если писать название в оригинале, то будет проще искать информацию в первоисточниках.

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

Если что то требует более обширного объяснения — задавайте вопросы, дополню.
  • +7
  • 17,1k
  • 5
Поделиться публикацией

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 5

    0
    Что с разрешениями? Доступ к данным на всех вебсайтах людей обычно настораживает.
      0
      Возможно вы подумали что в моем примере модуль внедряется в каждую посещаемую страницу? Если так, то спешу вас уведомить, что в данном примере модуль внедряется только после нажатия пользователем на кнопку расширения. Но действительно есть возможность, и некоторые приложения ей активно пользуются, внедрять код на каждую страницу.
        0
        Если нужно внедрять по кнопке на произвольный сайт — тут уже ничего не сделаешь. А если только на заданные URL, то возможно есть способ ограничить (в манифесте) расширение только ими. Это нужно, чтобы пользователь был уверен, что расширение не начнет воровать пароли от других сайтов.
          0
          Да, именно так, в манифесте есть возможность указать на какие именно сайты необходимо внедрять код приложения автоматически, не ожидая действия пользователя.
      0
      С какими? Content script имеет доступ только до DOM, javascript окружение создается новое.

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

      Самое читаемое