diff options
Diffstat (limited to 'browser/extensions/screenshots/background/selectorLoader.js')
-rw-r--r-- | browser/extensions/screenshots/background/selectorLoader.js | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/browser/extensions/screenshots/background/selectorLoader.js b/browser/extensions/screenshots/background/selectorLoader.js new file mode 100644 index 0000000000..347b29deb8 --- /dev/null +++ b/browser/extensions/screenshots/background/selectorLoader.js @@ -0,0 +1,139 @@ +/* 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; |