forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			140 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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",
 | 
						|
    "makeUuid.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;
 |