author | Matthew Wein <mwein@mozilla.com> |
Tue, 30 May 2017 22:40:57 -0400 | |
changeset 361497 | 8e9c427717c8c5f294a48d63abb33e196695e631 |
parent 361496 | c336400a21d7bbaf072553a4dfe39d4d297abea8 |
child 361498 | f066295fa2d3d0be3063de361d509564fa77c42d |
push id | 90875 |
push user | cbook@mozilla.com |
push date | Wed, 31 May 2017 12:23:54 +0000 |
treeherder | mozilla-inbound@7061759a0b57 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mixedpuppy |
bugs | 1351111 |
milestone | 55.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/components/extensions/ext-browserAction.js +++ b/mobile/android/components/extensions/ext-browserAction.js @@ -10,33 +10,130 @@ XPCOMUtils.defineLazyModuleGetter(this, // Import the android BrowserActions module. XPCOMUtils.defineLazyModuleGetter(this, "BrowserActions", "resource://gre/modules/BrowserActions.jsm"); // WeakMap[Extension -> BrowserAction] var browserActionMap = new WeakMap(); +const { + DefaultMap, +} = ExtensionUtils; + class BrowserAction { constructor(options, extension) { + // Map[TabID -> Object] + this.tabIdToPropertyMap = new DefaultMap(() => ({})); + this.tabManager = extension.tabManager; this.uuid = `{${extension.uuid}}`; this.name = options.default_title || extension.name; + + GlobalEventDispatcher.registerListener(this, ["Tab:Selected"]); + GlobalEventDispatcher.registerListener(this, ["Tab:Closed"]); + BrowserActions.register(this); EventEmitter.decorate(this); } /** + * Retrieves the name for the active tab. Used for testing only. + * @returns {string} the name used for the active tab. + */ + get activeName() { + let tab = tabTracker.activeTab; + return this.tabIdToPropertyMap.get(tab.id).name || this.name; + } + + /** * Required by the BrowserActions module. This event will get * called whenever the browser action is clicked on. */ onClicked() { this.emit("click", tabTracker.activeTab); } /** + * Required by the GlobalEventDispatcher module. This event will get + * called whenever one of the registered listeners fires. + * @param {string} event The event which fired. + * @param {object} data Information about the event which fired. + */ + onEvent(event, data) { + switch (event) { + case "Tab:Selected": + this.onTabSelected(this.tabManager.get(data.id)); + break; + case "Tab:Closed": + this.onTabClosed(this.tabManager.get(data.tabId)); + break; + } + } + + /** + * Updates the browser action whenever a tab is selected. + * @param {Object} tab The tab to update. + */ + onTabSelected(tab) { + let name = this.tabIdToPropertyMap.get(tab.id).name || this.name; + BrowserActions.update(this.uuid, {name}); + } + + /** + * Removes the tab from the property map now that it is closed. + * @param {Object} tab The tab which closed. + */ + onTabClosed(tab) { + this.tabIdToPropertyMap.delete(tab.id); + } + + /** + * Sets a property for the browser action for the specified tab. If the property is set + * for the active tab, the browser action is also updated. + * + * @param {Object} tab The tab to set. If null, the browser action's default value is set. + * @param {string} prop The property to update. Currently only "name" is supported. + * @param {string} value The value to set the property to. + */ + setProperty(tab, prop, value) { + if (tab == null) { + if (value) { + this[prop] = value; + } + } else { + let properties = this.tabIdToPropertyMap.get(tab.id); + if (value) { + properties[prop] = value; + } else { + delete properties[prop]; + } + } + + if (tab && tab.selected) { + BrowserActions.update(this.uuid, {[prop]: value}); + } + } + + /** + * Retreives a property of the browser action for the specified tab. + * + * @param {Object} tab The tab to retrieve the property from. If null, the default value is returned. + * @param {string} prop The property to retreive. Currently only "name" is supported. + * @returns {string} the value stored for the specified property. If the value is undefined, then the + * default value is returned. + */ + getProperty(tab, prop) { + if (tab == null) { + return this[prop]; + } + + return this.tabIdToPropertyMap.get(tab.id)[prop] || this[prop]; + } + + /** * Unregister the browser action from the BrowserActions module. */ shutdown() { BrowserActions.unregister(this.uuid); } } this.browserAction = class extends ExtensionAPI { @@ -67,12 +164,25 @@ this.browserAction = class extends Exten let listener = (event, tab) => { fire.async(tabManager.convert(tab)); }; browserActionMap.get(extension).on("click", listener); return () => { browserActionMap.get(extension).off("click", listener); }; }).api(), + + setTitle: function(details) { + let {tabId, title} = details; + let tab = tabId ? tabTracker.getTab(tabId) : null; + browserActionMap.get(extension).setProperty(tab, "name", title); + }, + + getTitle: function(details) { + let {tabId} = details; + let tab = tabId ? tabTracker.getTab(tabId) : null; + let title = browserActionMap.get(extension).getProperty(tab, "name"); + return Promise.resolve(title); + }, }, }; } };
--- a/mobile/android/components/extensions/schemas/browser_action.json +++ b/mobile/android/components/extensions/schemas/browser_action.json @@ -72,17 +72,16 @@ "additionalProperties": { "type": "any" }, "postprocess": "convertImageDataToURL", "description": "Pixel data for an image. Must be an ImageData object (for example, from a <code>canvas</code> element)." } ], "functions": [ { "name": "setTitle", - "unsupported": true, "type": "function", "description": "Sets the title of the browser action. This shows up in the tooltip.", "async": "callback", "parameters": [ { "name": "details", "type": "object", "properties": { @@ -102,17 +101,16 @@ "name": "callback", "optional": true, "parameters": [] } ] }, { "name": "getTitle", - "unsupported": true, "type": "function", "description": "Gets the title of the browser action.", "async": "callback", "parameters": [ { "name": "details", "type": "object", "properties": {
--- a/mobile/android/modules/BrowserActions.jsm +++ b/mobile/android/modules/BrowserActions.jsm @@ -28,17 +28,17 @@ var BrowserActions = { EventDispatcher.instance.registerListener(this, "Menu:BrowserActionClicked"); } }, /** * Unregisters the listeners if they are already initizliaed and * all of the browser actions have been removed. */ - _maybeUnregisterListeners: function() { + _maybeUnregisterListeners() { if (this._initialized && !Object.keys(this._browserActions).length) { this._initialized = false; EventDispatcher.instance.unregisterListener(this, "Menu:BrowserActionClicked"); } }, /** * Called when a browser action is clicked on. @@ -68,33 +68,59 @@ var BrowserActions = { EventDispatcher.instance.sendRequest({ type: "Menu:AddBrowserAction", id: this._nextMenuId++, uuid: browserAction.uuid, name: browserAction.name, }); this._browserActions[browserAction.uuid] = browserAction; + this._maybeRegisterListeners(); }, /** + * Updates the browser action with the specified UUID. + * @param {string} uuid The UUID of the browser action. + * @param {Object} options The properties to update. + */ + update(uuid, options) { + if (options.name) { + EventDispatcher.instance.sendRequest({ + type: "Menu:UpdateBrowserAction", + uuid, + options, + }); + } + }, + + /** + * Retrieves the name currently used for the browser action with the + * specified UUID. Used for testing only. + * @param {string} uuid The UUID of the browser action. + * @returns {string} the name currently used for the browser action. + */ + getNameForActiveTab(uuid) { + return this._browserActions[uuid].activeName; + }, + + /** * Checks to see if the browser action is shown. Used for testing only. * @param {string} uuid The UUID of the browser action. - * @returns True if the browser action is shown; false otherwise. + * @returns {boolean} true if the browser action is shown; false otherwise. */ - isShown: function(uuid) { + isShown(uuid) { return !!this._browserActions[uuid]; }, /** * Synthesizes a click on the browser action. Used for testing only. * @param {string} uuid The UUID of the browser action. */ - synthesizeClick: function(uuid) { + synthesizeClick(uuid) { let browserAction = this._browserActions[uuid]; if (!browserAction) { throw new Error(`No BrowserAction with UUID ${uuid} was found`); } browserAction.onClicked(); }, /** @@ -108,9 +134,9 @@ var BrowserActions = { } EventDispatcher.instance.sendRequest({ type: "Menu:RemoveBrowserAction", uuid, }); delete this._browserActions[uuid]; this._maybeUnregisterListeners(); } -} \ No newline at end of file +}