/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ /* globals browser, catcher, communication, log, main */ "use strict"; // eslint-disable-next-line no-var var global = this; this.selectorLoader = (function() { const exports = {}; // These modules are loaded in order, first standardScripts and then selectorScripts // The order is important due to dependencies const standardScripts = [ "log.js", "catcher.js", "assertIsTrusted.js", "assertIsBlankDocument.js", "blobConverters.js", "background/selectorLoader.js", "selector/callBackground.js", "selector/util.js", ]; const selectorScripts = [ "clipboard.js", "build/selection.js", "build/shot.js", "randomString.js", "domainFromUrl.js", "build/inlineSelectionCss.js", "selector/documentMetadata.js", "selector/ui.js", "selector/shooter.js", "selector/uicontrol.js", ]; exports.unloadIfLoaded = function(tabId) { return browser.tabs .executeScript(tabId, { code: "this.selectorLoader && this.selectorLoader.unloadModules()", runAt: "document_start", }) .then(result => { return result && result[0]; }); }; exports.testIfLoaded = function(tabId) { if (loadingTabs.has(tabId)) { return true; } return browser.tabs .executeScript(tabId, { code: "!!this.selectorLoader", runAt: "document_start", }) .then(result => { return result && result[0]; }); }; const loadingTabs = new Set(); exports.loadModules = function(tabId) { loadingTabs.add(tabId); catcher.watchPromise( executeModules(tabId, standardScripts.concat(selectorScripts)).then( () => { loadingTabs.delete(tabId); } ) ); }; function executeModules(tabId, scripts) { let lastPromise = Promise.resolve(null); scripts.forEach(file => { lastPromise = lastPromise.then(() => { return browser.tabs .executeScript(tabId, { file, runAt: "document_start", }) .catch(error => { log.error("error in script:", file, error); error.scriptName = file; throw error; }); }); }); return lastPromise.then( () => { log.debug("finished loading scripts:", scripts.join(" ")); }, error => { exports.unloadIfLoaded(tabId); catcher.unhandled(error); throw error; } ); } exports.unloadModules = function() { const watchFunction = catcher.watchFunction; const allScripts = standardScripts.concat(selectorScripts); const moduleNames = allScripts.map(filename => filename.replace(/^.*\//, "").replace(/\.js$/, "") ); moduleNames.reverse(); for (const moduleName of moduleNames) { const moduleObj = global[moduleName]; if (moduleObj && moduleObj.unload) { try { watchFunction(moduleObj.unload)(); } catch (e) { // ignore (watchFunction handles it) } } delete global[moduleName]; } return true; }; exports.toggle = function(tabId) { return exports.unloadIfLoaded(tabId).then(wasLoaded => { if (!wasLoaded) { exports.loadModules(tabId); } return !wasLoaded; }); }; return exports; })(); null;