forked from mirrors/gecko-dev
		
	 768f7a15c5
			
		
	
	
		768f7a15c5
		
	
	
	
	
		
			
			Screenshots moved from a Photon page action to a pure WebExtension page action, but this move introduced some UI bugs where the two page actions behave differently. Since this change isn't needed for 63, seems better to just temporarily revert. Differential Revision: https://phabricator.services.mozilla.com/D4162 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			283 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			283 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* globals ADDON_DISABLE Services CustomizableUI LegacyExtensionsUtils AppConstants PageActions */
 | |
| const ADDON_ID = "screenshots@mozilla.org";
 | |
| const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
 | |
| const PREF_BRANCH = "extensions.screenshots.";
 | |
| const USER_DISABLE_PREF = "extensions.screenshots.disabled";
 | |
| const UPLOAD_DISABLED_PREF = "extensions.screenshots.upload-disabled";
 | |
| const HISTORY_ENABLED_PREF = "places.history.enabled";
 | |
| 
 | |
| ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 | |
| ChromeUtils.defineModuleGetter(this, "AddonManager",
 | |
|                                "resource://gre/modules/AddonManager.jsm");
 | |
| ChromeUtils.defineModuleGetter(this, "AppConstants",
 | |
|                                "resource://gre/modules/AppConstants.jsm");
 | |
| ChromeUtils.defineModuleGetter(this, "CustomizableUI",
 | |
|                                "resource:///modules/CustomizableUI.jsm");
 | |
| ChromeUtils.defineModuleGetter(this, "LegacyExtensionsUtils",
 | |
|                                "resource://gre/modules/LegacyExtensionsUtils.jsm");
 | |
| ChromeUtils.defineModuleGetter(this, "PageActions",
 | |
|                                "resource:///modules/PageActions.jsm");
 | |
| ChromeUtils.defineModuleGetter(this, "Services",
 | |
|                                "resource://gre/modules/Services.jsm");
 | |
| 
 | |
| let addonResourceURI;
 | |
| let appStartupDone;
 | |
| let appStartupPromise = new Promise((resolve, reject) => {
 | |
|   appStartupDone = resolve;
 | |
| });
 | |
| 
 | |
| const prefs = Services.prefs;
 | |
| const prefObserver = {
 | |
|   register() {
 | |
|     prefs.addObserver(PREF_BRANCH, this, false); // eslint-disable-line mozilla/no-useless-parameters
 | |
|   },
 | |
| 
 | |
|   unregister() {
 | |
|     prefs.removeObserver(PREF_BRANCH, this, false); // eslint-disable-line mozilla/no-useless-parameters
 | |
|   },
 | |
| 
 | |
|   observe(aSubject, aTopic, aData) {
 | |
|     // aSubject is the nsIPrefBranch we're observing (after appropriate QI)
 | |
|     // aData is the name of the pref that's been changed (relative to aSubject)
 | |
|     if (aData === USER_DISABLE_PREF) {
 | |
|       // eslint-disable-next-line promise/catch-or-return
 | |
|       appStartupPromise = appStartupPromise.then(handleStartup);
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| const appStartupObserver = {
 | |
|   register() {
 | |
|     Services.obs.addObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
 | |
|   },
 | |
| 
 | |
|   unregister() {
 | |
|     Services.obs.removeObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
 | |
|   },
 | |
| 
 | |
|   observe() {
 | |
|     appStartupDone();
 | |
|     this.unregister();
 | |
|   }
 | |
| };
 | |
| 
 | |
| const LibraryButton = {
 | |
|   ITEM_ID: "appMenu-library-screenshots",
 | |
| 
 | |
|   init(webExtension) {
 | |
|     this._initialized = true;
 | |
|     const permissionPages = [...webExtension.extension.permissions].filter(p => (/^https?:\/\//i).test(p));
 | |
|     if (permissionPages.length > 1) {
 | |
|       Cu.reportError(new Error("Should not have more than 1 permission page, but got: " + JSON.stringify(permissionPages)));
 | |
|     }
 | |
|     this.PAGE_TO_OPEN = permissionPages.length === 1 ? permissionPages[0].replace(/\*$/, "") : "https://screenshots.firefox.com/";
 | |
|     this.PAGE_TO_OPEN += "shots";
 | |
|     this.ICON_URL = webExtension.extension.getURL("icons/icon-v2.svg");
 | |
|     this.LABEL = webExtension.extension.localizeMessage("libraryLabel");
 | |
|     CustomizableUI.addListener(this);
 | |
|     for (const win of CustomizableUI.windows) {
 | |
|       this.onWindowOpened(win);
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   uninit() {
 | |
|     if (!this._initialized) {
 | |
|       return;
 | |
|     }
 | |
|     for (const win of CustomizableUI.windows) {
 | |
|       const item = win.document.getElementById(this.ITEM_ID);
 | |
|       if (item) {
 | |
|         item.remove();
 | |
|       }
 | |
|     }
 | |
|     CustomizableUI.removeListener(this);
 | |
|     this._initialized = false;
 | |
|   },
 | |
| 
 | |
|   onWindowOpened(win) {
 | |
|     const libraryViewInsertionPoint = win.document.getElementById("appMenu-library-remotetabs-button");
 | |
|     // If the library view doesn't exist (on non-photon builds, for instance),
 | |
|     // this will be null, and we bail out early.
 | |
|     if (!libraryViewInsertionPoint) {
 | |
|       return;
 | |
|     }
 | |
|     const parent = libraryViewInsertionPoint.parentNode;
 | |
|     const {nextSibling} = libraryViewInsertionPoint;
 | |
|     const item = win.document.createXULElement("toolbarbutton");
 | |
|     item.className = "subviewbutton subviewbutton-iconic";
 | |
|     item.addEventListener("command", () => win.openWebLinkIn(this.PAGE_TO_OPEN, "tab"));
 | |
|     item.id = this.ITEM_ID;
 | |
|     const iconURL = this.ICON_URL;
 | |
|     item.setAttribute("image", iconURL);
 | |
|     item.setAttribute("label", this.LABEL);
 | |
| 
 | |
|     parent.insertBefore(item, nextSibling);
 | |
|   },
 | |
| };
 | |
| 
 | |
| const APP_STARTUP = 1;
 | |
| const APP_SHUTDOWN = 2;
 | |
| let addonData, startupReason;
 | |
| 
 | |
| function startup(data, reason) { // eslint-disable-line no-unused-vars
 | |
|   addonData = data;
 | |
|   startupReason = reason;
 | |
|   if (reason === APP_STARTUP) {
 | |
|     appStartupObserver.register();
 | |
|   } else {
 | |
|     appStartupDone();
 | |
|   }
 | |
|   prefObserver.register();
 | |
|   addonResourceURI = data.resourceURI;
 | |
|   // eslint-disable-next-line promise/catch-or-return
 | |
|   appStartupPromise = appStartupPromise.then(handleStartup);
 | |
| }
 | |
| 
 | |
| function shutdown(data, reason) { // eslint-disable-line no-unused-vars
 | |
|   prefObserver.unregister();
 | |
|   const webExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
 | |
|     id: ADDON_ID,
 | |
|     resourceURI: addonResourceURI
 | |
|   });
 | |
|   // Immediately exit if Firefox is exiting, #3323
 | |
|   if (reason === APP_SHUTDOWN) {
 | |
|     stop(webExtension, reason);
 | |
|     return;
 | |
|   }
 | |
|   // Because the prefObserver is unregistered above, this _should_ terminate the promise chain.
 | |
|   appStartupPromise = appStartupPromise.then(() => { stop(webExtension, reason); });
 | |
| }
 | |
| 
 | |
| function install(data, reason) {} // eslint-disable-line no-unused-vars
 | |
| 
 | |
| function uninstall(data, reason) {} // eslint-disable-line no-unused-vars
 | |
| 
 | |
| function getBoolPref(pref) {
 | |
|   return prefs.getPrefType(pref) && prefs.getBoolPref(pref);
 | |
| }
 | |
| 
 | |
| function shouldDisable() {
 | |
|   return getBoolPref(USER_DISABLE_PREF);
 | |
| }
 | |
| 
 | |
| function handleStartup() {
 | |
|   const webExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
 | |
|     id: ADDON_ID,
 | |
|     resourceURI: addonResourceURI
 | |
|   });
 | |
| 
 | |
|   if (!shouldDisable() && !webExtension.started) {
 | |
|     start(webExtension);
 | |
|   } else if (shouldDisable()) {
 | |
|     stop(webExtension, ADDON_DISABLE);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function start(webExtension) {
 | |
|   return webExtension.startup(startupReason, addonData).then((api) => {
 | |
|     api.browser.runtime.onMessage.addListener(handleMessage);
 | |
|     LibraryButton.init(webExtension);
 | |
|     initPhotonPageAction(api, webExtension);
 | |
|   }).catch((err) => {
 | |
|     // The startup() promise will be rejected if the webExtension was
 | |
|     // already started (a harmless error), or if initializing the
 | |
|     // WebExtension failed and threw (an important error).
 | |
|     console.error(err);
 | |
|     if (err.message !== "This embedded extension has already been started") {
 | |
|       // TODO: Should we send these errors to Sentry? #2420
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| function stop(webExtension, reason) {
 | |
|   if (reason !== APP_SHUTDOWN) {
 | |
|     LibraryButton.uninit();
 | |
|     if (photonPageAction) {
 | |
|       photonPageAction.remove();
 | |
|       photonPageAction = null;
 | |
|     }
 | |
|   }
 | |
|   return Promise.resolve(webExtension.shutdown(reason));
 | |
| }
 | |
| 
 | |
| function handleMessage(msg, sender, sendReply) {
 | |
|   if (!msg) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (msg.funcName === "isTelemetryEnabled") {
 | |
|     const telemetryEnabled = getBoolPref(TELEMETRY_ENABLED_PREF);
 | |
|     sendReply({type: "success", value: telemetryEnabled});
 | |
|   } else if (msg.funcName === "isUploadDisabled") {
 | |
|     const isESR = AppConstants.MOZ_UPDATE_CHANNEL === "esr";
 | |
|     const uploadDisabled = getBoolPref(UPLOAD_DISABLED_PREF);
 | |
|     sendReply({type: "success", value: uploadDisabled || isESR});
 | |
|   } else if (msg.funcName === "isHistoryEnabled") {
 | |
|     const historyEnabled = getBoolPref(HISTORY_ENABLED_PREF);
 | |
|     sendReply({type: "success", value: historyEnabled});
 | |
|   } else if (msg.funcName === "incrementCount") {
 | |
|     const allowedScalars = ["download", "upload", "copy"];
 | |
|     const scalar = msg.args && msg.args[0] && msg.args[0].scalar;
 | |
|     if (!allowedScalars.includes(scalar)) {
 | |
|       sendReply({type: "error", name: `incrementCount passed an unrecognized scalar ${scalar}`});
 | |
|     } else {
 | |
|       Services.telemetry.scalarAdd(`screenshots.${scalar}`, 1);
 | |
|       sendReply({type: "success", value: true});
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| let photonPageAction;
 | |
| 
 | |
| // If the current Firefox version supports Photon (57 and later), this sets up
 | |
| // a Photon page action and removes the UI for the WebExtension browser action.
 | |
| // Does nothing otherwise.  Ideally, in the future, WebExtension page actions
 | |
| // and Photon page actions would be one in the same, but they aren't right now.
 | |
| function initPhotonPageAction(api, webExtension) {
 | |
|   const id = "screenshots";
 | |
|   let port = null;
 | |
| 
 | |
|   const {tabManager} = webExtension.extension;
 | |
| 
 | |
|   // Make the page action.
 | |
|   photonPageAction = PageActions.actionForID(id) || PageActions.addAction(new PageActions.Action({
 | |
|     id,
 | |
|     title: "Take a Screenshot",
 | |
|     iconURL: webExtension.extension.getURL("icons/icon-v2.svg"),
 | |
|     _insertBeforeActionID: null,
 | |
|     onCommand(event, buttonNode) {
 | |
|       if (port) {
 | |
|         const browserWin = buttonNode.ownerGlobal;
 | |
|         const tab = tabManager.getWrapper(browserWin.gBrowser.selectedTab);
 | |
|         port.postMessage({
 | |
|           type: "click",
 | |
|           tab: {id: tab.id, url: tab.url}
 | |
|         });
 | |
|       }
 | |
|     },
 | |
|   }));
 | |
| 
 | |
|   // Establish a port to the WebExtension side.
 | |
|   api.browser.runtime.onConnect.addListener((listenerPort) => {
 | |
|     if (listenerPort.name !== "photonPageActionPort") {
 | |
|       return;
 | |
|     }
 | |
|     port = listenerPort;
 | |
|     port.onMessage.addListener((message) => {
 | |
|       switch (message.type) {
 | |
|       case "setProperties":
 | |
|         if (message.title) {
 | |
|           photonPageAction.setTitle(message.title);
 | |
|         }
 | |
|         if (message.iconPath) {
 | |
|           photonPageAction.setIconURL(webExtension.extension.getURL(message.iconPath));
 | |
|         }
 | |
|         break;
 | |
|       default:
 | |
|         console.error("Unrecognized message:", message);
 | |
|         break;
 | |
|       }
 | |
|     });
 | |
|   });
 | |
| }
 |