Как я могу приручить несколько слушателей событий в расширении 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 для разработки.