summaryrefslogtreecommitdiffstats
path: root/browser/extensions/screenshots/background/selectorLoader.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/extensions/screenshots/background/selectorLoader.js')
-rw-r--r--browser/extensions/screenshots/background/selectorLoader.js139
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;