Как я могу приручить несколько слушателей событий в расширении Fennec?

Я пытаюсь написать перезапускаемое дополнение для Firefox Mobile, которое будет вставлять контент на определенные веб-страницы. Кажется, все работает нормально, пока я не попытаюсь отключить, а затем снова включить надстройку, после чего я получаю несколько ответов на событие загрузки страницы, и я не могу найти способ разобраться в них.

Поскольку Fennec использует многопроцессорную платформу Electrolysis, я знаю, что мне нужно разделить мой код на скрипты chrome и content. Мой bootstrap.js выглядит примерно так (обрезано для ясности):

function startup(data, reason) {
  mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager);
  mm.loadFrameScript(getResourceURISpec('content.js'), true);
}

function shutdown(data, reason) {
  let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager);
  mm.sendAsyncMessage("GeoMapEnh:Disable", {reason: reason});
}

function install(data, reason) {}
function uninstall(data, reason) {}

По сути, bootstrap.js просто запускает скрипт содержимого и отправляет сообщение, чтобы он очистился при завершении работы. Content.js устанавливает eventListener для отслеживания загрузки страниц, который выглядит примерно так:

addMessageListener("GeoMapEnh:Disable", disableScript);
addEventListener("DOMContentLoaded", loadHandler, false );

function loadHandler(e) {
  LOG("Page loaded");
  // Do something cool with the web page.
}

function disableScript(aMessage) {
  if (aMessage.name != "GeoMapEnh:Disable") {
    return;
  }
  LOG("Disabling content script: " + aMessage.json.reason);
  try {
    removeEventListener("DOMContentLoaded", loadHandler, false );
    removeMessageListener("GeoMapEnh:Disable", disableScript);
  } catch(e) {
    LOG("Remove failed: " + e);
  }
}

function LOG(msg) {
  dump(msg + "\n");
  var consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
  consoleService.logStringMessage(msg);
}

Когда я впервые запускаю расширение, все работает нормально. Экземпляр content.js выполняется для каждой вкладки браузера (и любых новых вкладок, которые я открываю), и мой eventListener обнаруживает загрузку страницы, которую он должен, через событие DOMContentLoaded. Когда я отключаю расширение, все кажется, что все в порядке: загрузка страниц перестает быть обнаруженной.

Когда я снова включаю расширение, все идет не так. Я все еще получаю экземпляр content.js, выполняемый для каждой открытой вкладки, но теперь, если я открываю новые вкладки, DOMContentLoaded запускает несколько событий EventListeners, и я не могу определить, какая из них должна обрабатывать событие. Хуже того, некоторые из EventListener активны, но не предоставляют отладочную информацию через мою функцию LOG, и не все они удаляются, если я отключаю расширение во второй раз.

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

  • Вызов e.stopPropagation(), чтобы остановить передачу события другим слушателям. Нет эффекта.
  • Вызов e.preventDefault() и тестирование e.defaultPrevented, чтобы увидеть, было ли событие уже обработано. Это никогда не имеет.
  • Тестирование if (this === content.document), чтобы увидеть, был ли EventListener запущен собственным содержимым страницы. Не работает, так как я получаю несколько "истинных" ответов.
  • Делаем захват EventListener. Нет эффекта.
  • Использование события загрузки, а не DOMContentLoaded.

Я не могу установить общую переменную, чтобы сказать, что событие было обработано, как в Electrolysis, разные EventListeners будут выполняться в разных контекстах. Кроме того, я не смогу различить несколько вкладок, загружающих одну и ту же страницу, и одна загрузка страницы, обнаруженная несколько раз. Я мог бы сделать это с помощью сообщения IPC, передаваемого обратно в скрипт начальной загрузки Chrome, но тогда я не знал бы, как вернуть ответ на нужную вкладку браузера.

Есть идеи? Это ошибка Firefox, или я делаю что-то глупое в своем коде? Я использую Fennec Desktop v4 для разработки и буду ориентироваться на Fennec Android v6 для разработки.

0 ответов

Другие вопросы по тегам