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

Я пытаюсь написать перезапускаемое дополнение для 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, чтобы увидеть, было ли событие уже обработано.У него никогда не было.
  • Проверка, если (this === content.document), чтобы увидеть, был ли EventListener запущен собственным содержимым страницы.Не работает, так как я получаю несколько «истинных» ответов.
  • Создание захвата события EventListener.Без эффекта.
  • Использование события загрузки вместо DOMContentLoaded.

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

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

...