forked from mirrors/gecko-dev
		
	 e930b89c34
			
		
	
	
		e930b89c34
		
	
	
	
	
		
			
			***
Bug 1514594: Part 3a - Change ChromeUtils.import to return an exports object; not pollute global. r=mccr8
This changes the behavior of ChromeUtils.import() to return an exports object,
rather than a module global, in all cases except when `null` is passed as a
second argument, and changes the default behavior not to pollute the global
scope with the module's exports. Thus, the following code written for the old
model:
  ChromeUtils.import("resource://gre/modules/Services.jsm");
is approximately the same as the following, in the new model:
  var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
Since the two behaviors are mutually incompatible, this patch will land with a
scripted rewrite to update all existing callers to use the new model rather
than the old.
***
Bug 1514594: Part 3b - Mass rewrite all JS code to use the new ChromeUtils.import API. rs=Gijs
This was done using the followng script:
https://bitbucket.org/kmaglione/m-c-rewrites/src/tip/processors/cu-import-exports.jsm
***
Bug 1514594: Part 3c - Update ESLint plugin for ChromeUtils.import API changes. r=Standard8
Differential Revision: https://phabricator.services.mozilla.com/D16747
***
Bug 1514594: Part 3d - Remove/fix hundreds of duplicate imports from sync tests. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16748
***
Bug 1514594: Part 3e - Remove no-op ChromeUtils.import() calls. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16749
***
Bug 1514594: Part 3f.1 - Cleanup various test corner cases after mass rewrite. r=Gijs
***
Bug 1514594: Part 3f.2 - Cleanup various non-test corner cases after mass rewrite. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D16750
--HG--
extra : rebase_source : 359574ee3064c90f33bf36c2ebe3159a24cc8895
extra : histedit_source : b93c8f42808b1599f9122d7842d2c0b3e656a594%2C64a3a4e3359dc889e2ab2b49461bab9e27fc10a7
		
	
			
		
			
				
	
	
		
			411 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			411 lines
		
	
	
	
		
			12 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/. */
 | |
| 
 | |
| const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 | |
| 
 | |
| XPCOMUtils.defineLazyModuleGetters(this, {
 | |
|   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
 | |
|   PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
 | |
|   Services: "resource://gre/modules/Services.jsm",
 | |
|   AppConstants: "resource://gre/modules/AppConstants.jsm",
 | |
|   Localization: "resource://gre/modules/Localization.jsm",
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * Executes a XUL command on the top window. Called by the callbacks in each
 | |
|  * TouchBarInput.
 | |
|  * @param {string} commandName
 | |
|  *        A XUL command.
 | |
|  * @param {string} telemetryKey
 | |
|  *        A string describing the command, sent for telemetry purposes.
 | |
|  *        Intended to be shorter and more readable than the XUL command.
 | |
|  */
 | |
| function execCommand(commandName, telemetryKey) {
 | |
|   let win = BrowserWindowTracker.getTopWindow();
 | |
|   let command = win.document.getElementById(commandName);
 | |
|   if (command) {
 | |
|     command.doCommand();
 | |
|   }
 | |
|   let telemetry = Services.telemetry.getHistogramById("TOUCHBAR_BUTTON_PRESSES");
 | |
|   telemetry.add(telemetryKey);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Static helper function to convert a hexadecimal string to its integer
 | |
|  * value. Used to convert colours to a format accepted by Apple's NSColor code.
 | |
|  * @param {string} hexString
 | |
|  *        A hexadecimal string, optionally beginning with '#'.
 | |
|  */
 | |
| function hexToInt(hexString) {
 | |
|   if (!hexString) {
 | |
|     return null;
 | |
|   }
 | |
|   if (hexString.charAt(0) == "#") {
 | |
|     hexString = hexString.slice(1);
 | |
|   }
 | |
|   let val = parseInt(hexString, 16);
 | |
|   return isNaN(val) ? null : val;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * An object containing all implemented TouchBarInput objects.
 | |
|  */
 | |
| const kBuiltInInputs = {
 | |
|   Back: {
 | |
|     title: "back",
 | |
|     image: "back.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("Browser:Back", "Back"),
 | |
|   },
 | |
|   Forward: {
 | |
|     title: "forward",
 | |
|     image: "forward.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("Browser:Forward", "Forward"),
 | |
|   },
 | |
|   Reload: {
 | |
|     title: "reload",
 | |
|     image: "refresh.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("Browser:Reload", "Reload"),
 | |
|   },
 | |
|   Home: {
 | |
|     title: "home",
 | |
|     image: "home.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("Browser:Home", "Home"),
 | |
|   },
 | |
|   Fullscreen: {
 | |
|     title: "fullscreen",
 | |
|     image: "fullscreen.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("View:FullScreen", "Fullscreen"),
 | |
|   },
 | |
|   Find: {
 | |
|     title: "find",
 | |
|     image: "search.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("cmd_find", "Find"),
 | |
|   },
 | |
|   NewTab: {
 | |
|     title: "new-tab",
 | |
|     image: "new.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("cmd_newNavigatorTabNoEvent", "NewTab"),
 | |
|   },
 | |
|   Sidebar: {
 | |
|     title: "open-bookmarks-sidebar",
 | |
|     image: "sidebar-left.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("viewBookmarksSidebar", "Sidebar"),
 | |
|   },
 | |
|   AddBookmark: {
 | |
|     title: "add-bookmark",
 | |
|     image: "bookmark.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("Browser:AddBookmarkAs", "AddBookmark"),
 | |
|   },
 | |
|   ReaderView: {
 | |
|     title: "reader-view",
 | |
|     image: "reader-mode.pdf",
 | |
|     type: "button",
 | |
|     callback: () => execCommand("View:ReaderView", "ReaderView"),
 | |
|     disabled: true,  // Updated when the page is found to be Reader View-able.
 | |
|   },
 | |
|   OpenLocation: {
 | |
|     title: "open-location",
 | |
|     image: "search.pdf",
 | |
|     type: "mainButton",
 | |
|     callback: () => execCommand("Browser:OpenLocation", "OpenLocation"),
 | |
|   },
 | |
|   Focus: {
 | |
|     title: "close-window",
 | |
|     image: "private-browsing.pdf",
 | |
|     type: "mainButton",
 | |
|     callback: () => execCommand("cmd_closeWindow", "Focus"),
 | |
|     color: "#8000D7",
 | |
|     context: () => {
 | |
|       let name;
 | |
|       if (PrivateBrowsingUtils.isWindowPrivate(BrowserWindowTracker.getTopWindow())) {
 | |
|         name = "Focus";
 | |
|       }
 | |
|       return name;
 | |
|     },
 | |
|   },
 | |
|   OpenOrFocus: {
 | |
|     // This input is just a forwarder to other inputs.
 | |
|     context: () => {
 | |
|       let name;
 | |
|       if (PrivateBrowsingUtils.isWindowPrivate(BrowserWindowTracker.getTopWindow())) {
 | |
|         name = "Focus";
 | |
|       } else {
 | |
|         name = "OpenLocation";
 | |
|       }
 | |
|       return name;
 | |
|     },
 | |
|   },
 | |
|   // This is a special-case `type: "scrubber"` element.
 | |
|   // Scrubbers are not yet generally implemented.
 | |
|   // See follow-up bug 1502539.
 | |
|   Share: {
 | |
|     title: "share",
 | |
|     type: "scrubber",
 | |
|     image: "share.pdf",
 | |
|     callback: () => execCommand("cmd_share", "Share"),
 | |
|   },
 | |
| };
 | |
| 
 | |
| const kHelperObservers = new Set(["bookmark-icon-updated", "reader-mode-available",
 | |
|   "touchbar-location-change", "quit-application", "intl:app-locales-changed"]);
 | |
| 
 | |
| /**
 | |
|  * JS-implemented TouchBarHelper class.
 | |
|  * Provides services to the Mac Touch Bar.
 | |
|  */
 | |
| class TouchBarHelper {
 | |
|   constructor() {
 | |
|     for (let topic of kHelperObservers) {
 | |
|       Services.obs.addObserver(this, topic);
 | |
|     }
 | |
| 
 | |
|     XPCOMUtils.defineLazyPreferenceGetter(this, "_touchBarLayout",
 | |
|       "ui.touchbar.layout", "Back,Reload,OpenOrFocus,AddBookmark,NewTab,Share");
 | |
|   }
 | |
| 
 | |
|   destructor() {
 | |
|     for (let topic of kHelperObservers) {
 | |
|       Services.obs.removeObserver(this, topic);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   get activeTitle() {
 | |
|     let tabbrowser = this.window.ownerGlobal.gBrowser;
 | |
|     let activeTitle;
 | |
|     if (tabbrowser) {
 | |
|       activeTitle = tabbrowser.selectedBrowser.contentTitle;
 | |
|     }
 | |
|     return activeTitle;
 | |
|   }
 | |
| 
 | |
|   get layout() {
 | |
|     let prefArray = this.storedLayout;
 | |
|     let layoutItems = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
 | |
| 
 | |
|     for (let inputName of prefArray) {
 | |
|       if (typeof kBuiltInInputs[inputName].context == "function") {
 | |
|         inputName = kBuiltInInputs[inputName].context();
 | |
|       }
 | |
|       let input = this.getTouchBarInput(inputName);
 | |
|       if (!input) {
 | |
|         continue;
 | |
|       }
 | |
|       layoutItems.appendElement(input);
 | |
|     }
 | |
| 
 | |
|     return layoutItems;
 | |
|   }
 | |
| 
 | |
|   get window() {
 | |
|     return BrowserWindowTracker.getTopWindow();
 | |
|   }
 | |
| 
 | |
|   get bookmarkingUI() {
 | |
|     return this.window.BookmarkingUI;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a string array of the user's Touch Bar layout preference.
 | |
|    * Set by a pref ui.touchbar.layout and returned in an array.
 | |
|    */
 | |
|   get storedLayout() {
 | |
|     let prefArray = this._touchBarLayout.split(",");
 | |
|     prefArray = prefArray.map(str => str.trim());
 | |
|     // Remove duplicates.
 | |
|     prefArray = Array.from(new Set(prefArray));
 | |
| 
 | |
|     // Remove unimplemented/mispelled inputs.
 | |
|     prefArray = prefArray.filter(input =>
 | |
|       Object.keys(kBuiltInInputs).includes(input));
 | |
|     this._storedLayout = prefArray;
 | |
|     return this._storedLayout;
 | |
|   }
 | |
| 
 | |
|   getTouchBarInput(inputName) {
 | |
|     // inputName might be undefined if an input's context() returns undefined.
 | |
|     if (!inputName || !kBuiltInInputs.hasOwnProperty(inputName)) {
 | |
|       return null;
 | |
|     }
 | |
| 
 | |
|     if (typeof kBuiltInInputs[inputName].context == "function") {
 | |
|       inputName = kBuiltInInputs[inputName].context();
 | |
|     }
 | |
| 
 | |
|     if (!inputName || !kBuiltInInputs.hasOwnProperty(inputName)) {
 | |
|       return null;
 | |
|     }
 | |
| 
 | |
|     let inputData = kBuiltInInputs[inputName];
 | |
| 
 | |
|     let item = new TouchBarInput(inputData);
 | |
| 
 | |
|     // Async l10n fills in the localized input labels after the initial load.
 | |
|     this._l10n.formatValue(item.key).then((result) => {
 | |
|       item.title = result;
 | |
|       kBuiltInInputs[inputName].localTitle = result; // Cache result.
 | |
|       // Checking this.window since this callback can fire after all windows are closed.
 | |
|       if (this.window) {
 | |
|         let baseWindow = this.window.docShell.treeOwner.QueryInterface(Ci.nsIBaseWindow);
 | |
|         let updater = Cc["@mozilla.org/widget/touchbarupdater;1"]
 | |
|                         .getService(Ci.nsITouchBarUpdater);
 | |
|         updater.updateTouchBarInput(baseWindow, item);
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     return item;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Fetches a specific Touch Bar Input by name and updates it on the Touch Bar.
 | |
|    * @param {string} inputName
 | |
|    *        A key to a value in the kBuiltInInputs object in this file.
 | |
|    */
 | |
|   _updateTouchBarInput(inputName) {
 | |
|     let input = this.getTouchBarInput(inputName);
 | |
|     if (!input || !this.window) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let baseWindow = this.window.docShell.treeOwner.QueryInterface(Ci.nsIBaseWindow);
 | |
|     let updater = Cc["@mozilla.org/widget/touchbarupdater;1"]
 | |
|                     .getService(Ci.nsITouchBarUpdater);
 | |
|     updater.updateTouchBarInput(baseWindow, input);
 | |
|   }
 | |
| 
 | |
|   observe(subject, topic, data) {
 | |
|     switch (topic) {
 | |
|       case "touchbar-location-change":
 | |
|         this.activeUrl = data;
 | |
|         if (data.startsWith("about:reader")) {
 | |
|           kBuiltInInputs.ReaderView.disabled = false;
 | |
|           this._updateTouchBarInput("ReaderView");
 | |
|         } else {
 | |
|           // ReaderView button is disabled on every location change since
 | |
|           // Reader View must determine if the new page can be Reader Viewed.
 | |
|           kBuiltInInputs.ReaderView.disabled = true;
 | |
|           this._updateTouchBarInput("ReaderView");
 | |
|         }
 | |
|         break;
 | |
|       case "bookmark-icon-updated":
 | |
|         data == "starred" ?
 | |
|           kBuiltInInputs.AddBookmark.image = "bookmark-filled.pdf"
 | |
|           : kBuiltInInputs.AddBookmark.image = "bookmark.pdf";
 | |
|         this._updateTouchBarInput("AddBookmark");
 | |
|         break;
 | |
|       case "reader-mode-available":
 | |
|         kBuiltInInputs.ReaderView.disabled = false;
 | |
|         this._updateTouchBarInput("ReaderView");
 | |
|         break;
 | |
|       case "intl:app-locales-changed":
 | |
|         // On locale change, refresh all inputs after loading new localTitle.
 | |
|         for (let inputName of this._storedLayout) {
 | |
|           delete kBuiltInInputs[inputName].localTitle;
 | |
|           this._updateTouchBarInput(inputName);
 | |
|         }
 | |
|         break;
 | |
|       case "quit-application":
 | |
|         this.destructor();
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| const helperProto = TouchBarHelper.prototype;
 | |
| helperProto.classDescription = "Services the Mac Touch Bar";
 | |
| helperProto.classID = Components.ID("{ea109912-3acc-48de-b679-c23b6a122da5}");
 | |
| helperProto.contractID = "@mozilla.org/widget/touchbarhelper;1";
 | |
| helperProto.QueryInterface = ChromeUtils.generateQI([Ci.nsITouchBarHelper]);
 | |
| helperProto._l10n = new Localization(["browser/touchbar/touchbar.ftl"]);
 | |
| 
 | |
| /**
 | |
|  * A representation of a Touch Bar input.
 | |
|  * Uses async update() in lieu of a constructor to accomodate async l10n code.
 | |
|  *     @param {object} input
 | |
|  *            An object representing a Touch Bar Input.
 | |
|  *            Contains listed properties.
 | |
|  *     @param {string} input.title
 | |
|  *            The lookup key for the button's localized text title.
 | |
|  *     @param {string} input.image
 | |
|  *            The name of a icon file added to
 | |
|  *            /widget/cocoa/resources/touchbar_icons.
 | |
|  *     @param {string} input.type
 | |
|  *            The type of Touch Bar input represented by the object.
 | |
|  *            One of `button`, `mainButton`.
 | |
|  *     @param {Function} input.callback
 | |
|  *            A callback invoked when a touchbar item is touched.
 | |
|  *     @param {string} input.color (optional)
 | |
|  *            A string in hex format specifying the button's background color.
 | |
|  *            If omitted, the default background color is used.
 | |
|  *     @param {bool} input.disabled (optional)
 | |
|  *            If `true`, the Touch Bar input is greyed out and inoperable.
 | |
|  */
 | |
| class TouchBarInput {
 | |
|   constructor(input) {
 | |
|     this._key = input.title;
 | |
|     this._title = input.hasOwnProperty("localTitle") ? input.localTitle : "";
 | |
|     this._image = input.image;
 | |
|     this._type = input.type;
 | |
|     this._callback = input.callback;
 | |
|     this._color = hexToInt(input.color);
 | |
|     this._disabled = input.hasOwnProperty("disabled") ? input.disabled : false;
 | |
|   }
 | |
| 
 | |
|   get key() {
 | |
|     return this._key;
 | |
|   }
 | |
|   get title() {
 | |
|     return this._title;
 | |
|   }
 | |
|   set title(title) {
 | |
|     this._title = title;
 | |
|   }
 | |
|   get image() {
 | |
|     return this._image;
 | |
|   }
 | |
|   set image(image) {
 | |
|     this._image = image;
 | |
|   }
 | |
|   get type() {
 | |
|     return this._type == "" ? "button" : this._type;
 | |
|   }
 | |
|   set type(type) {
 | |
|     this._type = type;
 | |
|   }
 | |
|   get callback() {
 | |
|     return this._callback;
 | |
|   }
 | |
|   set callback(callback) {
 | |
|     this._callback = callback;
 | |
|   }
 | |
|   get color() {
 | |
|     return this._color;
 | |
|   }
 | |
|   set color(color) {
 | |
|     this._color = this.hexToInt(color);
 | |
|   }
 | |
|   get disabled() {
 | |
|     return this._disabled || false;
 | |
|   }
 | |
|   set disabled(disabled) {
 | |
|     this._disabled = disabled;
 | |
|   }
 | |
| }
 | |
| 
 | |
| const inputProto = TouchBarInput.prototype;
 | |
| inputProto.classDescription = "Represents an input on the Mac Touch Bar";
 | |
| inputProto.classID = Components.ID("{77441d17-f29c-49d7-982f-f20a5ab5a900}");
 | |
| inputProto.contractID = "@mozilla.org/widget/touchbarinput;1";
 | |
| inputProto.QueryInterface = ChromeUtils.generateQI([Ci.nsITouchBarInput]);
 | |
| 
 | |
| this.NSGetFactory =
 | |
|   XPCOMUtils.generateNSGetFactory([TouchBarHelper, TouchBarInput]);
 |