--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -332,63 +332,79 @@ this.bookmarks = class extends Extension
try {
return PlacesUtils.bookmarks.remove(info)
.catch(error => Promise.reject({message: error.message}));
} catch (e) {
return Promise.reject({message: `Invalid bookmark: ${JSON.stringify(info)}`});
}
},
- onCreated: new EventManager(context, "bookmarks.onCreated", fire => {
- let listener = (event, bookmark) => {
- fire.sync(bookmark.id, bookmark);
- };
+ onCreated: new EventManager({
+ context,
+ name: "bookmarks.onCreated",
+ register: fire => {
+ let listener = (event, bookmark) => {
+ fire.sync(bookmark.id, bookmark);
+ };
- observer.on("created", listener);
- incrementListeners();
- return () => {
- observer.off("created", listener);
- decrementListeners();
- };
+ observer.on("created", listener);
+ incrementListeners();
+ return () => {
+ observer.off("created", listener);
+ decrementListeners();
+ };
+ },
}).api(),
- onRemoved: new EventManager(context, "bookmarks.onRemoved", fire => {
- let listener = (event, data) => {
- fire.sync(data.guid, data.info);
- };
+ onRemoved: new EventManager({
+ context,
+ name: "bookmarks.onRemoved",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.sync(data.guid, data.info);
+ };
- observer.on("removed", listener);
- incrementListeners();
- return () => {
- observer.off("removed", listener);
- decrementListeners();
- };
+ observer.on("removed", listener);
+ incrementListeners();
+ return () => {
+ observer.off("removed", listener);
+ decrementListeners();
+ };
+ },
}).api(),
- onChanged: new EventManager(context, "bookmarks.onChanged", fire => {
- let listener = (event, data) => {
- fire.sync(data.guid, data.info);
- };
+ onChanged: new EventManager({
+ context,
+ name: "bookmarks.onChanged",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.sync(data.guid, data.info);
+ };
- observer.on("changed", listener);
- incrementListeners();
- return () => {
- observer.off("changed", listener);
- decrementListeners();
- };
+ observer.on("changed", listener);
+ incrementListeners();
+ return () => {
+ observer.off("changed", listener);
+ decrementListeners();
+ };
+ },
}).api(),
- onMoved: new EventManager(context, "bookmarks.onMoved", fire => {
- let listener = (event, data) => {
- fire.sync(data.guid, data.info);
- };
+ onMoved: new EventManager({
+ context,
+ name: "bookmarks.onMoved",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.sync(data.guid, data.info);
+ };
- observer.on("moved", listener);
- incrementListeners();
- return () => {
- observer.off("moved", listener);
- decrementListeners();
- };
+ observer.on("moved", listener);
+ incrementListeners();
+ return () => {
+ observer.off("moved", listener);
+ decrementListeners();
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-browser.js
+++ b/browser/components/extensions/ext-browser.js
@@ -170,44 +170,16 @@ class WindowTracker extends WindowTracke
* Will return the topmost "normal" (i.e., not popup) window.
* @readonly
*/
get topNormalWindow() {
return RecentWindow.getMostRecentBrowserWindow({allowPopups: false});
}
}
-/**
- * An event manager API provider which listens for a DOM event in any browser
- * window, and calls the given listener function whenever an event is received.
- * That listener function receives a `fire` object, which it can use to dispatch
- * events to the extension, and a DOM event object.
- *
- * @param {BaseContext} context
- * The extension context which the event manager belongs to.
- * @param {string} name
- * The API name of the event manager, e.g.,"runtime.onMessage".
- * @param {string} event
- * The name of the DOM event to listen for.
- * @param {function} listener
- * The listener function to call when a DOM event is received.
- */
-global.WindowEventManager = class extends EventManager {
- constructor(context, name, event, listener) {
- super(context, name, fire => {
- let listener2 = listener.bind(null, fire);
-
- windowTracker.addListener(event, listener2);
- return () => {
- windowTracker.removeListener(event, listener2);
- };
- });
- }
-};
-
class TabTracker extends TabTrackerBase {
constructor() {
super();
this._tabs = new WeakMap();
this._browsers = new WeakMap();
this._tabIds = new Map();
this._nextId = 1;
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -585,25 +585,30 @@ this.browserAction = class extends Exten
if (tabId !== null) {
return tabTracker.getTab(tabId);
}
return null;
}
return {
browserAction: {
- onClicked: new InputEventManager(context, "browserAction.onClicked", fire => {
- let listener = (event, browser) => {
- context.withPendingBrowser(browser, () =>
- fire.sync(tabManager.convert(tabTracker.activeTab)));
- };
- browserAction.on("click", listener);
- return () => {
- browserAction.off("click", listener);
- };
+ onClicked: new EventManager({
+ context,
+ name: "browserAction.onClicked",
+ inputHandling: true,
+ register: fire => {
+ let listener = (event, browser) => {
+ context.withPendingBrowser(browser, () =>
+ fire.sync(tabManager.convert(tabTracker.activeTab)));
+ };
+ browserAction.on("click", listener);
+ return () => {
+ browserAction.off("click", listener);
+ };
+ },
}).api(),
enable: function(tabId) {
let tab = getTab(tabId);
browserAction.setProperty(tab, "enabled", true);
},
disable: function(tabId) {
--- a/browser/components/extensions/ext-c-devtools-network.js
+++ b/browser/components/extensions/ext-c-devtools-network.js
@@ -31,29 +31,33 @@ class ChildNetworkResponseLoader {
}
}
this.devtools_network = class extends ExtensionAPI {
getAPI(context) {
return {
devtools: {
network: {
- onRequestFinished: new EventManager(context, "devtools.network.onRequestFinished", fire => {
- let onFinished = (data) => {
- const loader = new ChildNetworkResponseLoader(context, data.requestId);
- const harEntry = {...data.harEntry, ...loader.api()};
- const result = Cu.cloneInto(harEntry, context.cloneScope, {
- cloneFunctions: true,
- });
- fire.asyncWithoutClone(result);
- };
+ onRequestFinished: new EventManager({
+ context,
+ name: "devtools.network.onRequestFinished",
+ register: fire => {
+ let onFinished = (data) => {
+ const loader = new ChildNetworkResponseLoader(context, data.requestId);
+ const harEntry = {...data.harEntry, ...loader.api()};
+ const result = Cu.cloneInto(harEntry, context.cloneScope, {
+ cloneFunctions: true,
+ });
+ fire.asyncWithoutClone(result);
+ };
- let parent = context.childManager.getParentEvent("devtools.network.onRequestFinished");
- parent.addListener(onFinished);
- return () => {
- parent.removeListener(onFinished);
- };
+ let parent = context.childManager.getParentEvent("devtools.network.onRequestFinished");
+ parent.addListener(onFinished);
+ return () => {
+ parent.removeListener(onFinished);
+ };
+ },
}).api(),
},
},
};
}
};
--- a/browser/components/extensions/ext-c-devtools-panels.js
+++ b/browser/components/extensions/ext-c-devtools-panels.js
@@ -92,37 +92,43 @@ class ChildDevToolsPanel extends Extensi
}
onParentPanelHidden() {
this.emit("hidden");
}
api() {
return {
- onShown: new EventManager(
- this.context, "devtoolsPanel.onShown", fire => {
+ onShown: new EventManager({
+ context: this.context,
+ name: "devtoolsPanel.onShown",
+ register: fire => {
const listener = (eventName, panelContentWindow) => {
fire.asyncWithoutClone(panelContentWindow);
};
this.on("shown", listener);
return () => {
this.off("shown", listener);
};
- }).api(),
+ },
+ }).api(),
- onHidden: new EventManager(
- this.context, "devtoolsPanel.onHidden", fire => {
+ onHidden: new EventManager({
+ context: this.context,
+ name: "devtoolsPanel.onHidden",
+ register: fire => {
const listener = () => {
fire.async();
};
this.on("hidden", listener);
return () => {
this.off("hidden", listener);
};
- }).api(),
+ },
+ }).api(),
// TODO(rpl): onSearch event and createStatusBarButton method
};
}
close() {
this.mm.removeMessageListener("Extension:DevToolsPanelShown", this);
this.mm.removeMessageListener("Extension:DevToolsPanelHidden", this);
@@ -187,37 +193,43 @@ class ChildDevToolsInspectorSidebar exte
onParentSidebarHidden() {
this.emit("hidden");
}
api() {
const {context, id} = this;
return {
- onShown: new EventManager(
- context, "devtoolsInspectorSidebar.onShown", fire => {
+ onShown: new EventManager({
+ context,
+ name: "devtoolsInspectorSidebar.onShown",
+ register: fire => {
const listener = (eventName, panelContentWindow) => {
fire.asyncWithoutClone(panelContentWindow);
};
this.on("shown", listener);
return () => {
this.off("shown", listener);
};
- }).api(),
+ },
+ }).api(),
- onHidden: new EventManager(
- context, "devtoolsInspectorSidebar.onHidden", fire => {
+ onHidden: new EventManager({
+ context,
+ name: "devtoolsInspectorSidebar.onHidden",
+ register: fire => {
const listener = () => {
fire.async();
};
this.on("hidden", listener);
return () => {
this.off("hidden", listener);
};
- }).api(),
+ },
+ }).api(),
setObject(jsonObject, rootTitle) {
return context.cloneScope.Promise.resolve().then(() => {
return context.childManager.callParentAsyncFunction(
"devtools.panels.elements.Sidebar.setObject",
[id, jsonObject, rootTitle]
);
});
@@ -277,23 +289,26 @@ this.devtools_panels = class extends Ext
context.cloneScope,
{cloneFunctions: true});
return devtoolsPanelAPI;
});
},
get themeName() {
return themeChangeObserver.themeName;
},
- onThemeChanged: new EventManager(
- context, "devtools.panels.onThemeChanged", fire => {
+ onThemeChanged: new EventManager({
+ context,
+ name: "devtools.panels.onThemeChanged",
+ register: fire => {
const listener = (eventName, themeName) => {
fire.async(themeName);
};
themeChangeObserver.on("themeChanged", listener);
return () => {
themeChangeObserver.off("themeChanged", listener);
};
- }).api(),
+ },
+ }).api(),
},
},
};
}
};
--- a/browser/components/extensions/ext-c-menus.js
+++ b/browser/components/extensions/ext-c-menus.js
@@ -157,27 +157,31 @@ this.menusInternal = class extends Exten
},
removeAll() {
onClickedProp.deleteAllListenersFromExtension();
return context.childManager.callParentAsyncFunction("menusInternal.removeAll", []);
},
- onClicked: new EventManager(context, "menus.onClicked", fire => {
- let listener = (info, tab) => {
- withHandlingUserInput(context.contentWindow,
- () => fire.sync(info, tab));
- };
+ onClicked: new EventManager({
+ context,
+ name: "menus.onClicked",
+ register: fire => {
+ let listener = (info, tab) => {
+ withHandlingUserInput(context.contentWindow,
+ () => fire.sync(info, tab));
+ };
- let event = context.childManager.getParentEvent("menusInternal.onClicked");
- event.addListener(listener);
- return () => {
- event.removeListener(listener);
- };
+ let event = context.childManager.getParentEvent("menusInternal.onClicked");
+ event.addListener(listener);
+ return () => {
+ event.removeListener(listener);
+ };
+ },
}).api(),
},
};
const result = {};
if (context.extension.hasPermission("menus")) {
result.menus = api.menus;
}
--- a/browser/components/extensions/ext-c-omnibox.js
+++ b/browser/components/extensions/ext-c-omnibox.js
@@ -4,26 +4,30 @@
// The ext-* files are imported into the same scopes.
/* import-globals-from ../../../toolkit/components/extensions/ext-c-toolkit.js */
this.omnibox = class extends ExtensionAPI {
getAPI(context) {
return {
omnibox: {
- onInputChanged: new EventManager(context, "omnibox.onInputChanged", fire => {
- let listener = (text, id) => {
- fire.asyncWithoutClone(text, suggestions => {
- context.childManager.callParentFunctionNoReturn("omnibox.addSuggestions", [
- id,
- suggestions,
- ]);
- });
- };
- context.childManager.getParentEvent("omnibox.onInputChanged").addListener(listener);
- return () => {
- context.childManager.getParentEvent("omnibox.onInputChanged").removeListener(listener);
- };
+ onInputChanged: new EventManager({
+ context,
+ name: "omnibox.onInputChanged",
+ register: fire => {
+ let listener = (text, id) => {
+ fire.asyncWithoutClone(text, suggestions => {
+ context.childManager.callParentFunctionNoReturn("omnibox.addSuggestions", [
+ id,
+ suggestions,
+ ]);
+ });
+ };
+ context.childManager.getParentEvent("omnibox.onInputChanged").addListener(listener);
+ return () => {
+ context.childManager.getParentEvent("omnibox.onInputChanged").removeListener(listener);
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-commands.js
+++ b/browser/components/extensions/ext-commands.js
@@ -359,21 +359,25 @@ this.commands = class extends ExtensionA
"commands", name, extension.id);
if (storedCommand && storedCommand.value) {
commands.set(name, {...manifestCommands.get(name)});
ExtensionSettingsStore.removeSetting(extension.id, "commands", name);
this.registerKeys(commands);
}
},
- onCommand: new EventManager(context, "commands.onCommand", fire => {
- let listener = (eventName, commandName) => {
- fire.async(commandName);
- };
- this.on("command", listener);
- return () => {
- this.off("command", listener);
- };
+ onCommand: new EventManager({
+ context,
+ name: "commands.onCommand",
+ register: fire => {
+ let listener = (eventName, commandName) => {
+ fire.async(commandName);
+ };
+ this.on("command", listener);
+ return () => {
+ this.off("command", listener);
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-devtools-network.js
+++ b/browser/components/extensions/ext-devtools-network.js
@@ -14,42 +14,47 @@ this.devtools_network = class extends Ex
return {
devtools: {
network: {
onNavigated: new EventManager(context, "devtools.onNavigated", fire => {
let listener = data => {
fire.async(data.url);
};
- let targetPromise = getDevToolsTargetForContext(context);
- targetPromise.then(target => {
- target.on("navigate", listener);
- });
- return () => {
+ let targetPromise = getDevToolsTargetForContext(context);
targetPromise.then(target => {
- target.off("navigate", listener);
+ target.on("navigate", listener);
});
- };
+ return () => {
+ targetPromise.then(target => {
+ target.off("navigate", listener);
+ });
+ };
+ },
}).api(),
getHAR: function() {
return context.devToolsToolbox.getHARFromNetMonitor();
},
- onRequestFinished: new EventManager(context, "devtools.network.onRequestFinished", fire => {
- const listener = (data) => {
- fire.async(data);
- };
+ onRequestFinished: new EventManager({
+ context,
+ name: "devtools.network.onRequestFinished",
+ register: fire => {
+ const listener = (data) => {
+ fire.async(data);
+ };
- const toolbox = context.devToolsToolbox;
- toolbox.addRequestFinishedListener(listener);
+ const toolbox = context.devToolsToolbox;
+ toolbox.addRequestFinishedListener(listener);
- return () => {
- toolbox.removeRequestFinishedListener(listener);
- };
+ return () => {
+ toolbox.removeRequestFinishedListener(listener);
+ };
+ },
}).api(),
// The following method is used internally to allow the request API
// piece that is running in the child process to ask the parent process
// to fetch response content from the back-end.
Request: {
async getContent(requestId) {
return context.devToolsToolbox.fetchResponseContent(requestId)
--- a/browser/components/extensions/ext-devtools-panels.js
+++ b/browser/components/extensions/ext-devtools-panels.js
@@ -524,26 +524,29 @@ this.devtools_panels = class extends Ext
function newBasePanelId() {
return `${context.extension.id}-${context.contextId}-${nextPanelId++}`;
}
return {
devtools: {
panels: {
elements: {
- onSelectionChanged: new EventManager(
- context, "devtools.panels.elements.onSelectionChanged", fire => {
+ onSelectionChanged: new EventManager({
+ context,
+ name: "devtools.panels.elements.onSelectionChanged",
+ register: fire => {
const listener = (eventName) => {
fire.async();
};
toolboxSelectionObserver.on("selectionChanged", listener);
return () => {
toolboxSelectionObserver.off("selectionChanged", listener);
};
- }).api(),
+ },
+ }).api(),
createSidebarPane(title) {
const id = `devtools-inspector-sidebar-${makeWidgetId(newBasePanelId())}`;
const parentSidebar = new ParentDevToolsInspectorSidebar(context, {title, id});
sidebarsById.set(id, parentSidebar);
context.callOnClose({
close() {
--- a/browser/components/extensions/ext-geckoProfiler.js
+++ b/browser/components/extensions/ext-geckoProfiler.js
@@ -334,18 +334,22 @@ this.geckoProfiler = class extends Exten
// known system library.
// "nm" will fail if `nm` is not available.
}
}
throw new Error(`Ran out of options to get symbols from library ${debugName} ${breakpadId}.`);
},
- onRunning: new EventManager(context, "geckoProfiler.onRunning", fire => {
- isRunningObserver.addObserver(fire.async);
- return () => {
- isRunningObserver.removeObserver(fire.async);
- };
+ onRunning: new EventManager({
+ context,
+ name: "geckoProfiler.onRunning",
+ register: fire => {
+ isRunningObserver.addObserver(fire.async);
+ return () => {
+ isRunningObserver.removeObserver(fire.async);
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-history.js
+++ b/browser/components/extensions/ext-history.js
@@ -218,44 +218,56 @@ this.history = class extends ExtensionAP
let historyQuery = PlacesUtils.history.getNewQuery();
historyQuery.uri = Services.io.newURI(url);
let queryResult = PlacesUtils.history.executeQuery(historyQuery, options).root;
let results = convertNavHistoryContainerResultNode(queryResult, convertNodeToVisitItem);
return Promise.resolve(results);
},
- onVisited: new EventManager(context, "history.onVisited", fire => {
- let listener = (event, data) => {
- fire.sync(data);
- };
+ onVisited: new EventManager({
+ context,
+ name: "history.onVisited",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.sync(data);
+ };
- getHistoryObserver().on("visited", listener);
- return () => {
- getHistoryObserver().off("visited", listener);
- };
+ getHistoryObserver().on("visited", listener);
+ return () => {
+ getHistoryObserver().off("visited", listener);
+ };
+ },
}).api(),
- onVisitRemoved: new EventManager(context, "history.onVisitRemoved", fire => {
- let listener = (event, data) => {
- fire.sync(data);
- };
+ onVisitRemoved: new EventManager({
+ context,
+ name: "history.onVisitRemoved",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.sync(data);
+ };
- getHistoryObserver().on("visitRemoved", listener);
- return () => {
- getHistoryObserver().off("visitRemoved", listener);
- };
+ getHistoryObserver().on("visitRemoved", listener);
+ return () => {
+ getHistoryObserver().off("visitRemoved", listener);
+ };
+ },
}).api(),
- onTitleChanged: new EventManager(context, "history.onTitleChanged", fire => {
- let listener = (event, data) => {
- fire.sync(data);
- };
+ onTitleChanged: new EventManager({
+ context,
+ name: "history.onTitleChanged",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.sync(data);
+ };
- getHistoryObserver().on("titleChanged", listener);
- return () => {
- getHistoryObserver().off("titleChanged", listener);
- };
+ getHistoryObserver().on("titleChanged", listener);
+ return () => {
+ getHistoryObserver().off("titleChanged", listener);
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-menus.js
+++ b/browser/components/extensions/ext-menus.js
@@ -812,50 +812,58 @@ this.menusInternal = class extends Exten
getAPI(context) {
let {extension} = context;
const menus = {
refresh() {
gMenuBuilder.rebuildMenu(extension);
},
- onShown: new EventManager(context, "menus.onShown", fire => {
- let listener = (event, menuIds, contextData) => {
- let info = {
- menuIds,
- contexts: Array.from(getMenuContexts(contextData)),
- };
+ onShown: new EventManager({
+ context,
+ name: "menus.onShown",
+ register: fire => {
+ let listener = (event, menuIds, contextData) => {
+ let info = {
+ menuIds,
+ contexts: Array.from(getMenuContexts(contextData)),
+ };
- // The menus.onShown event is fired before the user has consciously
- // interacted with an extension, so we require permissions before
- // exposing sensitive contextual data.
- let includeSensitiveData =
+ // The menus.onShown event is fired before the user has consciously
+ // interacted with an extension, so we require permissions before
+ // exposing sensitive contextual data.
+ let includeSensitiveData =
extension.tabManager.hasActiveTabPermission(contextData.tab) ||
extension.whiteListedHosts.matches(contextData.inFrame ? contextData.frameUrl : contextData.pageUrl);
- addMenuEventInfo(info, contextData, includeSensitiveData);
+ addMenuEventInfo(info, contextData, includeSensitiveData);
- let tab = extension.tabManager.convert(contextData.tab);
- fire.sync(info, tab);
- };
- gOnShownSubscribers.add(extension);
- extension.on("webext-menu-shown", listener);
- return () => {
- gOnShownSubscribers.delete(extension);
- extension.off("webext-menu-shown", listener);
- };
+ let tab = extension.tabManager.convert(contextData.tab);
+ fire.sync(info, tab);
+ };
+ gOnShownSubscribers.add(extension);
+ extension.on("webext-menu-shown", listener);
+ return () => {
+ gOnShownSubscribers.delete(extension);
+ extension.off("webext-menu-shown", listener);
+ };
+ },
}).api(),
- onHidden: new EventManager(context, "menus.onHidden", fire => {
- let listener = () => {
- fire.sync();
- };
- extension.on("webext-menu-hidden", listener);
- return () => {
- extension.off("webext-menu-hidden", listener);
- };
+ onHidden: new EventManager({
+ context,
+ name: "menus.onHidden",
+ register: fire => {
+ let listener = () => {
+ fire.sync();
+ };
+ extension.on("webext-menu-hidden", listener);
+ return () => {
+ extension.off("webext-menu-hidden", listener);
+ };
+ },
}).api(),
};
return {
contextMenus: menus,
menus,
menusInternal: {
create: function(createProperties) {
@@ -882,24 +890,28 @@ this.menusInternal = class extends Exten
removeAll: function() {
let root = gRootItems.get(extension);
if (root) {
root.remove();
}
},
- onClicked: new EventManager(context, "menusInternal.onClicked", fire => {
- let listener = (event, info, tab) => {
- let {linkedBrowser} = tab || tabTracker.activeTab;
- context.withPendingBrowser(linkedBrowser,
- () => fire.sync(info, tab));
- };
+ onClicked: new EventManager({
+ context,
+ name: "menusInternal.onClicked",
+ register: fire => {
+ let listener = (event, info, tab) => {
+ let {linkedBrowser} = tab || tabTracker.activeTab;
+ context.withPendingBrowser(linkedBrowser,
+ () => fire.sync(info, tab));
+ };
- extension.on("webext-menu-menuitem-click", listener);
- return () => {
- extension.off("webext-menu-menuitem-click", listener);
- };
+ extension.on("webext-menu-menuitem-click", listener);
+ return () => {
+ extension.off("webext-menu-menuitem-click", listener);
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-omnibox.js
+++ b/browser/components/extensions/ext-omnibox.js
@@ -35,61 +35,77 @@ this.omnibox = class extends ExtensionAP
try {
// This will throw if the keyword failed to register.
ExtensionSearchHandler.setDefaultSuggestion(this.keyword, suggestion);
} catch (e) {
return Promise.reject(e.message);
}
},
- onInputStarted: new EventManager(context, "omnibox.onInputStarted", fire => {
- let listener = (eventName) => {
- fire.sync();
- };
- extension.on(ExtensionSearchHandler.MSG_INPUT_STARTED, listener);
- return () => {
- extension.off(ExtensionSearchHandler.MSG_INPUT_STARTED, listener);
- };
+ onInputStarted: new EventManager({
+ context,
+ name: "omnibox.onInputStarted",
+ register: fire => {
+ let listener = (eventName) => {
+ fire.sync();
+ };
+ extension.on(ExtensionSearchHandler.MSG_INPUT_STARTED, listener);
+ return () => {
+ extension.off(ExtensionSearchHandler.MSG_INPUT_STARTED, listener);
+ };
+ },
}).api(),
- onInputCancelled: new EventManager(context, "omnibox.onInputCancelled", fire => {
- let listener = (eventName) => {
- fire.sync();
- };
- extension.on(ExtensionSearchHandler.MSG_INPUT_CANCELLED, listener);
- return () => {
- extension.off(ExtensionSearchHandler.MSG_INPUT_CANCELLED, listener);
- };
+ onInputCancelled: new EventManager({
+ context,
+ name: "omnibox.onInputCancelled",
+ register: fire => {
+ let listener = (eventName) => {
+ fire.sync();
+ };
+ extension.on(ExtensionSearchHandler.MSG_INPUT_CANCELLED, listener);
+ return () => {
+ extension.off(ExtensionSearchHandler.MSG_INPUT_CANCELLED, listener);
+ };
+ },
}).api(),
- onInputEntered: new EventManager(context, "omnibox.onInputEntered", fire => {
- let listener = (eventName, text, disposition) => {
- fire.sync(text, disposition);
- };
- extension.on(ExtensionSearchHandler.MSG_INPUT_ENTERED, listener);
- return () => {
- extension.off(ExtensionSearchHandler.MSG_INPUT_ENTERED, listener);
- };
+ onInputEntered: new EventManager({
+ context,
+ name: "omnibox.onInputEntered",
+ register: fire => {
+ let listener = (eventName, text, disposition) => {
+ fire.sync(text, disposition);
+ };
+ extension.on(ExtensionSearchHandler.MSG_INPUT_ENTERED, listener);
+ return () => {
+ extension.off(ExtensionSearchHandler.MSG_INPUT_ENTERED, listener);
+ };
+ },
}).api(),
// Internal APIs.
addSuggestions: (id, suggestions) => {
try {
ExtensionSearchHandler.addSuggestions(this.keyword, id, suggestions);
} catch (e) {
// Silently fail because the extension developer can not know for sure if the user
// has already invalidated the callback when asynchronously providing suggestions.
}
},
- onInputChanged: new EventManager(context, "omnibox.onInputChanged", fire => {
- let listener = (eventName, text, id) => {
- fire.sync(text, id);
- };
- extension.on(ExtensionSearchHandler.MSG_INPUT_CHANGED, listener);
- return () => {
- extension.off(ExtensionSearchHandler.MSG_INPUT_CHANGED, listener);
- };
+ onInputChanged: new EventManager({
+ context,
+ name: "omnibox.onInputChanged",
+ register: fire => {
+ let listener = (eventName, text, id) => {
+ fire.sync(text, id);
+ };
+ extension.on(ExtensionSearchHandler.MSG_INPUT_CHANGED, listener);
+ return () => {
+ extension.off(ExtensionSearchHandler.MSG_INPUT_CHANGED, listener);
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -320,26 +320,31 @@ this.pageAction = class extends Extensio
getAPI(context) {
let {extension} = context;
const {tabManager} = extension;
const pageAction = this;
return {
pageAction: {
- onClicked: new InputEventManager(context, "pageAction.onClicked", fire => {
- let listener = (evt, tab) => {
- context.withPendingBrowser(tab.linkedBrowser, () =>
- fire.sync(tabManager.convert(tab)));
- };
+ onClicked: new EventManager({
+ context,
+ name: "pageAction.onClicked",
+ inputHandling: true,
+ register: fire => {
+ let listener = (evt, tab) => {
+ context.withPendingBrowser(tab.linkedBrowser, () =>
+ fire.sync(tabManager.convert(tab)));
+ };
- pageAction.on("click", listener);
- return () => {
- pageAction.off("click", listener);
- };
+ pageAction.on("click", listener);
+ return () => {
+ pageAction.off("click", listener);
+ };
+ },
}).api(),
show(tabId) {
let tab = tabTracker.getTab(tabId);
pageAction.setProperty(tab, "show", true);
},
hide(tabId) {
--- a/browser/components/extensions/ext-sessions.js
+++ b/browser/components/extensions/ext-sessions.js
@@ -202,22 +202,26 @@ this.sessions = class extends ExtensionA
removeWindowValue(windowId, key) {
let {win, encodedKey} =
getWindowParams(extension.id, key, windowId, context);
SessionStore.deleteWindowValue(win, encodedKey);
},
- onChanged: new EventManager(context, "sessions.onChanged", fire => {
- let observer = () => {
- fire.async();
- };
+ onChanged: new EventManager({
+ context,
+ name: "sessions.onChanged",
+ register: fire => {
+ let observer = () => {
+ fire.async();
+ };
- Services.obs.addObserver(observer, SS_ON_CLOSED_OBJECTS_CHANGED);
- return () => {
- Services.obs.removeObserver(observer, SS_ON_CLOSED_OBJECTS_CHANGED);
- };
+ Services.obs.addObserver(observer, SS_ON_CLOSED_OBJECTS_CHANGED);
+ return () => {
+ Services.obs.removeObserver(observer, SS_ON_CLOSED_OBJECTS_CHANGED);
+ };
+ },
}).api(),
},
};
}
};
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -333,133 +333,165 @@ this.tabs = class extends ExtensionAPI {
await tabListener.awaitTabReady(tab.nativeTab);
return tab;
}
let self = {
tabs: {
- onActivated: new EventManager(context, "tabs.onActivated", fire => {
- let listener = (eventName, event) => {
- fire.async(event);
- };
+ onActivated: new EventManager({
+ context,
+ name: "tabs.onActivated",
+ register: fire => {
+ let listener = (eventName, event) => {
+ fire.async(event);
+ };
- tabTracker.on("tab-activated", listener);
- return () => {
- tabTracker.off("tab-activated", listener);
- };
+ tabTracker.on("tab-activated", listener);
+ return () => {
+ tabTracker.off("tab-activated", listener);
+ };
+ },
}).api(),
- onCreated: new EventManager(context, "tabs.onCreated", fire => {
- let listener = (eventName, event) => {
- fire.async(tabManager.convert(event.nativeTab, event.currentTab));
- };
+ onCreated: new EventManager({
+ context,
+ name: "tabs.onCreated",
+ register: fire => {
+ let listener = (eventName, event) => {
+ fire.async(tabManager.convert(event.nativeTab, event.currentTab));
+ };
- tabTracker.on("tab-created", listener);
- return () => {
- tabTracker.off("tab-created", listener);
- };
+ tabTracker.on("tab-created", listener);
+ return () => {
+ tabTracker.off("tab-created", listener);
+ };
+ },
}).api(),
/**
* Since multiple tabs currently can't be highlighted, onHighlighted
* essentially acts an alias for self.tabs.onActivated but returns
* the tabId in an array to match the API.
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
*/
- onHighlighted: new EventManager(context, "tabs.onHighlighted", fire => {
- let listener = (eventName, event) => {
- fire.async({tabIds: [event.tabId], windowId: event.windowId});
- };
+ onHighlighted: new EventManager({
+ context,
+ name: "tabs.onHighlighted",
+ register: fire => {
+ let listener = (eventName, event) => {
+ fire.async({tabIds: [event.tabId], windowId: event.windowId});
+ };
- tabTracker.on("tab-activated", listener);
- return () => {
- tabTracker.off("tab-activated", listener);
- };
+ tabTracker.on("tab-activated", listener);
+ return () => {
+ tabTracker.off("tab-activated", listener);
+ };
+ },
}).api(),
- onAttached: new EventManager(context, "tabs.onAttached", fire => {
- let listener = (eventName, event) => {
- fire.async(event.tabId, {newWindowId: event.newWindowId, newPosition: event.newPosition});
- };
+ onAttached: new EventManager({
+ context,
+ name: "tabs.onAttached",
+ register: fire => {
+ let listener = (eventName, event) => {
+ fire.async(event.tabId, {newWindowId: event.newWindowId, newPosition: event.newPosition});
+ };
- tabTracker.on("tab-attached", listener);
- return () => {
- tabTracker.off("tab-attached", listener);
- };
+ tabTracker.on("tab-attached", listener);
+ return () => {
+ tabTracker.off("tab-attached", listener);
+ };
+ },
}).api(),
- onDetached: new EventManager(context, "tabs.onDetached", fire => {
- let listener = (eventName, event) => {
- fire.async(event.tabId, {oldWindowId: event.oldWindowId, oldPosition: event.oldPosition});
- };
+ onDetached: new EventManager({
+ context,
+ name: "tabs.onDetached",
+ register: fire => {
+ let listener = (eventName, event) => {
+ fire.async(event.tabId, {oldWindowId: event.oldWindowId, oldPosition: event.oldPosition});
+ };
- tabTracker.on("tab-detached", listener);
- return () => {
- tabTracker.off("tab-detached", listener);
- };
- }).api(),
-
- onRemoved: new EventManager(context, "tabs.onRemoved", fire => {
- let listener = (eventName, event) => {
- fire.async(event.tabId, {windowId: event.windowId, isWindowClosing: event.isWindowClosing});
- };
-
- tabTracker.on("tab-removed", listener);
- return () => {
- tabTracker.off("tab-removed", listener);
- };
+ tabTracker.on("tab-detached", listener);
+ return () => {
+ tabTracker.off("tab-detached", listener);
+ };
+ },
}).api(),
- onReplaced: new EventManager(context, "tabs.onReplaced", fire => {
- return () => {};
+ onRemoved: new EventManager({
+ context,
+ name: "tabs.onRemoved",
+ register: fire => {
+ let listener = (eventName, event) => {
+ fire.async(event.tabId, {windowId: event.windowId, isWindowClosing: event.isWindowClosing});
+ };
+
+ tabTracker.on("tab-removed", listener);
+ return () => {
+ tabTracker.off("tab-removed", listener);
+ };
+ },
+ }).api(),
+
+ onReplaced: new EventManager({
+ context,
+ name: "tabs.onReplaced",
+ register: fire => {
+ return () => {};
+ },
}).api(),
- onMoved: new EventManager(context, "tabs.onMoved", fire => {
- // There are certain circumstances where we need to ignore a move event.
- //
- // Namely, the first time the tab is moved after it's created, we need
- // to report the final position as the initial position in the tab's
- // onAttached or onCreated event. This is because most tabs are inserted
- // in a temporary location and then moved after the TabOpen event fires,
- // which generates a TabOpen event followed by a TabMove event, which
- // does not match the contract of our API.
- let ignoreNextMove = new WeakSet();
+ onMoved: new EventManager({
+ context,
+ name: "tabs.onMoved",
+ register: fire => {
+ // There are certain circumstances where we need to ignore a move event.
+ //
+ // Namely, the first time the tab is moved after it's created, we need
+ // to report the final position as the initial position in the tab's
+ // onAttached or onCreated event. This is because most tabs are inserted
+ // in a temporary location and then moved after the TabOpen event fires,
+ // which generates a TabOpen event followed by a TabMove event, which
+ // does not match the contract of our API.
+ let ignoreNextMove = new WeakSet();
- let openListener = event => {
- ignoreNextMove.add(event.target);
- // Remove the tab from the set on the next tick, since it will already
- // have been moved by then.
- Promise.resolve().then(() => {
- ignoreNextMove.delete(event.target);
- });
- };
+ let openListener = event => {
+ ignoreNextMove.add(event.target);
+ // Remove the tab from the set on the next tick, since it will already
+ // have been moved by then.
+ Promise.resolve().then(() => {
+ ignoreNextMove.delete(event.target);
+ });
+ };
- let moveListener = event => {
- let nativeTab = event.originalTarget;
+ let moveListener = event => {
+ let nativeTab = event.originalTarget;
- if (ignoreNextMove.has(nativeTab)) {
- ignoreNextMove.delete(nativeTab);
- return;
- }
+ if (ignoreNextMove.has(nativeTab)) {
+ ignoreNextMove.delete(nativeTab);
+ return;
+ }
- fire.async(tabTracker.getId(nativeTab), {
- windowId: windowTracker.getId(nativeTab.ownerGlobal),
- fromIndex: event.detail,
- toIndex: nativeTab._tPos,
- });
- };
+ fire.async(tabTracker.getId(nativeTab), {
+ windowId: windowTracker.getId(nativeTab.ownerGlobal),
+ fromIndex: event.detail,
+ toIndex: nativeTab._tPos,
+ });
+ };
- windowTracker.addListener("TabMove", moveListener);
- windowTracker.addListener("TabOpen", openListener);
- return () => {
- windowTracker.removeListener("TabMove", moveListener);
- windowTracker.removeListener("TabOpen", openListener);
- };
+ windowTracker.addListener("TabMove", moveListener);
+ windowTracker.addListener("TabOpen", openListener);
+ return () => {
+ windowTracker.removeListener("TabMove", moveListener);
+ windowTracker.removeListener("TabOpen", openListener);
+ };
+ },
}).api(),
onUpdated: new TabsUpdateFilterEventManager(context, "tabs.onUpdated").api(),
create(createProperties) {
return new Promise((resolve, reject) => {
let window = createProperties.windowId !== null ?
windowTracker.getWindow(createProperties.windowId, context) :
@@ -891,85 +923,89 @@ this.tabs = class extends ExtensionAPI {
let currentSettings = this._getZoomSettings(tabTracker.getId(nativeTab));
if (!Object.keys(settings).every(key => settings[key] === currentSettings[key])) {
return Promise.reject(`Unsupported zoom settings: ${JSON.stringify(settings)}`);
}
return Promise.resolve();
},
- onZoomChange: new EventManager(context, "tabs.onZoomChange", fire => {
- let getZoomLevel = browser => {
- let {ZoomManager} = browser.ownerGlobal;
+ onZoomChange: new EventManager({
+ context,
+ name: "tabs.onZoomChange",
+ register: fire => {
+ let getZoomLevel = browser => {
+ let {ZoomManager} = browser.ownerGlobal;
- return ZoomManager.getZoomForBrowser(browser);
- };
-
- // Stores the last known zoom level for each tab's browser.
- // WeakMap[<browser> -> number]
- let zoomLevels = new WeakMap();
+ return ZoomManager.getZoomForBrowser(browser);
+ };
- // Store the zoom level for all existing tabs.
- for (let window of windowTracker.browserWindows()) {
- for (let nativeTab of window.gBrowser.tabs) {
- let browser = nativeTab.linkedBrowser;
- zoomLevels.set(browser, getZoomLevel(browser));
- }
- }
+ // Stores the last known zoom level for each tab's browser.
+ // WeakMap[<browser> -> number]
+ let zoomLevels = new WeakMap();
- let tabCreated = (eventName, event) => {
- let browser = event.nativeTab.linkedBrowser;
- zoomLevels.set(browser, getZoomLevel(browser));
- };
-
-
- let zoomListener = event => {
- let browser = event.originalTarget;
-
- // For non-remote browsers, this event is dispatched on the document
- // rather than on the <browser>.
- if (browser instanceof Ci.nsIDOMDocument) {
- browser = browser.docShell.chromeEventHandler;
+ // Store the zoom level for all existing tabs.
+ for (let window of windowTracker.browserWindows()) {
+ for (let nativeTab of window.gBrowser.tabs) {
+ let browser = nativeTab.linkedBrowser;
+ zoomLevels.set(browser, getZoomLevel(browser));
+ }
}
- let {gBrowser} = browser.ownerGlobal;
- let nativeTab = gBrowser.getTabForBrowser(browser);
- if (!nativeTab) {
- // We only care about zoom events in the top-level browser of a tab.
- return;
- }
+ let tabCreated = (eventName, event) => {
+ let browser = event.nativeTab.linkedBrowser;
+ zoomLevels.set(browser, getZoomLevel(browser));
+ };
+
+
+ let zoomListener = event => {
+ let browser = event.originalTarget;
- let oldZoomFactor = zoomLevels.get(browser);
- let newZoomFactor = getZoomLevel(browser);
+ // For non-remote browsers, this event is dispatched on the document
+ // rather than on the <browser>.
+ if (browser instanceof Ci.nsIDOMDocument) {
+ browser = browser.docShell.chromeEventHandler;
+ }
- if (oldZoomFactor != newZoomFactor) {
- zoomLevels.set(browser, newZoomFactor);
+ let {gBrowser} = browser.ownerGlobal;
+ let nativeTab = gBrowser.getTabForBrowser(browser);
+ if (!nativeTab) {
+ // We only care about zoom events in the top-level browser of a tab.
+ return;
+ }
+
+ let oldZoomFactor = zoomLevels.get(browser);
+ let newZoomFactor = getZoomLevel(browser);
- let tabId = tabTracker.getId(nativeTab);
- fire.async({
- tabId,
- oldZoomFactor,
- newZoomFactor,
- zoomSettings: self.tabs._getZoomSettings(tabId),
- });
- }
- };
+ if (oldZoomFactor != newZoomFactor) {
+ zoomLevels.set(browser, newZoomFactor);
+
+ let tabId = tabTracker.getId(nativeTab);
+ fire.async({
+ tabId,
+ oldZoomFactor,
+ newZoomFactor,
+ zoomSettings: self.tabs._getZoomSettings(tabId),
+ });
+ }
+ };
- tabTracker.on("tab-attached", tabCreated);
- tabTracker.on("tab-created", tabCreated);
+ tabTracker.on("tab-attached", tabCreated);
+ tabTracker.on("tab-created", tabCreated);
- windowTracker.addListener("FullZoomChange", zoomListener);
- windowTracker.addListener("TextZoomChange", zoomListener);
- return () => {
- tabTracker.off("tab-attached", tabCreated);
- tabTracker.off("tab-created", tabCreated);
+ windowTracker.addListener("FullZoomChange", zoomListener);
+ windowTracker.addListener("TextZoomChange", zoomListener);
+ return () => {
+ tabTracker.off("tab-attached", tabCreated);
+ tabTracker.off("tab-created", tabCreated);
- windowTracker.removeListener("FullZoomChange", zoomListener);
- windowTracker.removeListener("TextZoomChange", zoomListener);
- };
+ windowTracker.removeListener("FullZoomChange", zoomListener);
+ windowTracker.removeListener("TextZoomChange", zoomListener);
+ };
+ },
}).api(),
print() {
let activeTab = getTabOrActive(null);
let {PrintUtils} = activeTab.ownerGlobal;
PrintUtils.printWindow(activeTab.linkedBrowser.outerWindowID, activeTab.linkedBrowser);
},
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -14,56 +14,88 @@ ChromeUtils.defineModuleGetter(this, "Pr
var {
promiseObserved,
} = ExtensionUtils;
const onXULFrameLoaderCreated = ({target}) => {
target.messageManager.sendAsyncMessage("AllowScriptsToClose", {});
};
+/**
+ * An event manager API provider which listens for a DOM event in any browser
+ * window, and calls the given listener function whenever an event is received.
+ * That listener function receives a `fire` object, which it can use to dispatch
+ * events to the extension, and a DOM event object.
+ *
+ * @param {BaseContext} context
+ * The extension context which the event manager belongs to.
+ * @param {string} name
+ * The API name of the event manager, e.g.,"runtime.onMessage".
+ * @param {string} event
+ * The name of the DOM event to listen for.
+ * @param {function} listener
+ * The listener function to call when a DOM event is received.
+ *
+ * @returns {object} An injectable api for the new event.
+ */
+function WindowEventManager(context, name, event, listener) {
+ let register = fire => {
+ let listener2 = listener.bind(null, fire);
+
+ windowTracker.addListener(event, listener2);
+ return () => {
+ windowTracker.removeListener(event, listener2);
+ };
+ };
+
+ return new EventManager({context, name, register}).api();
+}
+
this.windows = class extends ExtensionAPI {
getAPI(context) {
let {extension} = context;
const {windowManager} = extension;
return {
windows: {
- onCreated:
- new WindowEventManager(context, "windows.onCreated", "domwindowopened", (fire, window) => {
+ onCreated: WindowEventManager(context, "windows.onCreated", "domwindowopened", (fire, window) => {
fire.async(windowManager.convert(window));
- }).api(),
+ }),
- onRemoved:
- new WindowEventManager(context, "windows.onRemoved", "domwindowclosed", (fire, window) => {
+ onRemoved: WindowEventManager(context, "windows.onRemoved", "domwindowclosed", (fire, window) => {
fire.async(windowTracker.getId(window));
- }).api(),
+ }),
- onFocusChanged: new EventManager(context, "windows.onFocusChanged", fire => {
- // Keep track of the last windowId used to fire an onFocusChanged event
- let lastOnFocusChangedWindowId;
+ onFocusChanged: new EventManager({
+ context,
+ name: "windows.onFocusChanged",
+ register: fire => {
+ // Keep track of the last windowId used to fire an onFocusChanged event
+ let lastOnFocusChangedWindowId;
- let listener = event => {
- // Wait a tick to avoid firing a superfluous WINDOW_ID_NONE
- // event when switching focus between two Firefox windows.
- Promise.resolve().then(() => {
- let window = Services.focus.activeWindow;
- let windowId = window ? windowTracker.getId(window) : Window.WINDOW_ID_NONE;
- if (windowId !== lastOnFocusChangedWindowId) {
- fire.async(windowId);
- lastOnFocusChangedWindowId = windowId;
- }
- });
- };
- windowTracker.addListener("focus", listener);
- windowTracker.addListener("blur", listener);
- return () => {
- windowTracker.removeListener("focus", listener);
- windowTracker.removeListener("blur", listener);
- };
+ let listener = event => {
+ // Wait a tick to avoid firing a superfluous WINDOW_ID_NONE
+ // event when switching focus between two Firefox windows.
+ Promise.resolve().then(() => {
+ let window = Services.focus.activeWindow;
+ let windowId = window ? windowTracker.getId(window) : Window.WINDOW_ID_NONE;
+ if (windowId !== lastOnFocusChangedWindowId) {
+ fire.async(windowId);
+ lastOnFocusChangedWindowId = windowId;
+ }
+ });
+ };
+ windowTracker.addListener("focus", listener);
+ windowTracker.addListener("blur", listener);
+ return () => {
+ windowTracker.removeListener("focus", listener);
+ windowTracker.removeListener("blur", listener);
+ };
+ },
}).api(),
get: function(windowId, getInfo) {
let window = windowTracker.getWindow(windowId, context);
if (!window) {
return Promise.reject({message: `Invalid window ID: ${windowId}`});
}
return Promise.resolve(windowManager.convert(window, getInfo));
--- a/mobile/android/components/extensions/ext-browserAction.js
+++ b/mobile/android/components/extensions/ext-browserAction.js
@@ -151,24 +151,28 @@ this.browserAction = class extends Exten
if (tabId !== null) {
return tabTracker.getTab(tabId);
}
return null;
}
return {
browserAction: {
- onClicked: new EventManager(context, "browserAction.onClicked", fire => {
- let listener = (event, tab) => {
- fire.async(tabManager.convert(tab));
- };
- browserActionMap.get(extension).on("click", listener);
- return () => {
- browserActionMap.get(extension).off("click", listener);
- };
+ onClicked: new EventManager({
+ context,
+ name: "browserAction.onClicked",
+ register: fire => {
+ 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 = getTab(tabId);
browserActionMap.get(extension).setProperty(tab, "name", title);
},
--- a/mobile/android/components/extensions/ext-pageAction.js
+++ b/mobile/android/components/extensions/ext-pageAction.js
@@ -227,24 +227,28 @@ this.pageAction = class extends Extensio
getAPI(context) {
const {extension} = context;
const {tabManager} = extension;
pageActionMap.get(extension).setContext(context);
return {
pageAction: {
- onClicked: new EventManager(context, "pageAction.onClicked", fire => {
- let listener = (event, tab) => {
- fire.async(tabManager.convert(tab));
- };
- pageActionMap.get(extension).on("click", listener);
- return () => {
- pageActionMap.get(extension).off("click", listener);
- };
+ onClicked: new EventManager({
+ context,
+ name: "pageAction.onClicked",
+ register: fire => {
+ let listener = (event, tab) => {
+ fire.async(tabManager.convert(tab));
+ };
+ pageActionMap.get(extension).on("click", listener);
+ return () => {
+ pageActionMap.get(extension).off("click", listener);
+ };
+ },
}).api(),
show(tabId) {
let tab = tabTracker.getTab(tabId);
return pageActionMap.get(extension).setProperty(tab, "show", true);
},
hide(tabId) {
--- a/mobile/android/components/extensions/ext-tabs.js
+++ b/mobile/android/components/extensions/ext-tabs.js
@@ -98,147 +98,163 @@ this.tabs = class extends ExtensionAPI {
await tabListener.awaitTabReady(tab.nativeTab);
return tab;
}
let self = {
tabs: {
- onActivated: new GlobalEventManager(context, "tabs.onActivated", "Tab:Selected", (fire, data) => {
+ onActivated: makeGlobalEvent(context, "tabs.onActivated", "Tab:Selected", (fire, data) => {
let tab = tabManager.get(data.id);
fire.async({tabId: tab.id, windowId: tab.windowId});
}).api(),
onCreated: new EventManager(context, "tabs.onCreated", fire => {
let listener = (eventName, event) => {
fire.async(tabManager.convert(event.nativeTab));
};
tabTracker.on("tab-created", listener);
return () => {
tabTracker.off("tab-created", listener);
};
- }).api(),
+ }),
/**
* Since multiple tabs currently can't be highlighted, onHighlighted
* essentially acts an alias for self.tabs.onActivated but returns
* the tabId in an array to match the API.
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
*/
- onHighlighted: new GlobalEventManager(context, "tabs.onHighlighted", "Tab:Selected", (fire, data) => {
+ onHighlighted: makeGlobalEvent(context, "tabs.onHighlighted", "Tab:Selected", (fire, data) => {
let tab = tabManager.get(data.id);
fire.async({tabIds: [tab.id], windowId: tab.windowId});
+ }),
+
+ onAttached: new EventManager({
+ context,
+ name: "tabs.onAttached",
+ register: fire => { return () => {}; },
}).api(),
- onAttached: new EventManager(context, "tabs.onAttached", fire => {
- return () => {};
- }).api(),
-
- onDetached: new EventManager(context, "tabs.onDetached", fire => {
- return () => {};
+ onDetached: new EventManager({
+ context,
+ name: "tabs.onDetached",
+ register: fire => { return () => {}; },
}).api(),
- onRemoved: new EventManager(context, "tabs.onRemoved", fire => {
- let listener = (eventName, event) => {
- fire.async(event.tabId, {windowId: event.windowId, isWindowClosing: event.isWindowClosing});
- };
+ onRemoved: new EventManager({
+ context,
+ name: "tabs.onRemoved",
+ register: fire => {
+ let listener = (eventName, event) => {
+ fire.async(event.tabId, {windowId: event.windowId, isWindowClosing: event.isWindowClosing});
+ };
- tabTracker.on("tab-removed", listener);
- return () => {
- tabTracker.off("tab-removed", listener);
- };
+ tabTracker.on("tab-removed", listener);
+ return () => {
+ tabTracker.off("tab-removed", listener);
+ };
+ },
}).api(),
- onReplaced: new EventManager(context, "tabs.onReplaced", fire => {
- return () => {};
+ onReplaced: new EventManager({
+ context,
+ name: "tabs.onReplaced",
+ register: fire => { return () => {}; },
}).api(),
- onMoved: new EventManager(context, "tabs.onMoved", fire => {
- return () => {};
+ onMoved: new EventManager({
+ context,
+ name: "tabs.onMoved",
+ register: fire => { return () => {}; },
}).api(),
- onUpdated: new EventManager(context, "tabs.onUpdated", fire => {
- const restricted = ["url", "favIconUrl", "title"];
+ onUpdated: new EventManager({
+ context,
+ name: "tabs.onUpdated",
+ register: fire => {
+ const restricted = ["url", "favIconUrl", "title"];
- function sanitize(extension, changeInfo) {
- let result = {};
- let nonempty = false;
- for (let prop in changeInfo) {
- if (extension.hasPermission("tabs") || !restricted.includes(prop)) {
- nonempty = true;
- result[prop] = changeInfo[prop];
+ function sanitize(extension, changeInfo) {
+ let result = {};
+ let nonempty = false;
+ for (let prop in changeInfo) {
+ if (extension.hasPermission("tabs") || !restricted.includes(prop)) {
+ nonempty = true;
+ result[prop] = changeInfo[prop];
+ }
}
+ return [nonempty, result];
}
- return [nonempty, result];
- }
- let fireForTab = (tab, changed) => {
- let [needed, changeInfo] = sanitize(extension, changed);
- if (needed) {
- fire.async(tab.id, changeInfo, tab.convert());
- }
- };
+ let fireForTab = (tab, changed) => {
+ let [needed, changeInfo] = sanitize(extension, changed);
+ if (needed) {
+ fire.async(tab.id, changeInfo, tab.convert());
+ }
+ };
- let listener = event => {
- let needed = [];
- let nativeTab;
- switch (event.type) {
- case "DOMTitleChanged": {
- let {BrowserApp} = getBrowserWindow(event.target.ownerGlobal);
+ let listener = event => {
+ let needed = [];
+ let nativeTab;
+ switch (event.type) {
+ case "DOMTitleChanged": {
+ let {BrowserApp} = getBrowserWindow(event.target.ownerGlobal);
- nativeTab = BrowserApp.getTabForWindow(event.target.ownerGlobal);
- needed.push("title");
- break;
+ nativeTab = BrowserApp.getTabForWindow(event.target.ownerGlobal);
+ needed.push("title");
+ break;
+ }
+
+ case "DOMAudioPlaybackStarted":
+ case "DOMAudioPlaybackStopped": {
+ let {BrowserApp} = event.target.ownerGlobal;
+ nativeTab = BrowserApp.getTabForBrowser(event.originalTarget);
+ needed.push("audible");
+ break;
+ }
}
- case "DOMAudioPlaybackStarted":
- case "DOMAudioPlaybackStopped": {
- let {BrowserApp} = event.target.ownerGlobal;
- nativeTab = BrowserApp.getTabForBrowser(event.originalTarget);
- needed.push("audible");
- break;
+ if (!nativeTab) {
+ return;
}
- }
-
- if (!nativeTab) {
- return;
- }
- let tab = tabManager.getWrapper(nativeTab);
- let changeInfo = {};
- for (let prop of needed) {
- changeInfo[prop] = tab[prop];
- }
-
- fireForTab(tab, changeInfo);
- };
-
- let statusListener = ({browser, status, url}) => {
- let {BrowserApp} = browser.ownerGlobal;
- let nativeTab = BrowserApp.getTabForBrowser(browser);
- if (nativeTab) {
- let changed = {status};
- if (url) {
- changed.url = url;
+ let tab = tabManager.getWrapper(nativeTab);
+ let changeInfo = {};
+ for (let prop of needed) {
+ changeInfo[prop] = tab[prop];
}
- fireForTab(tabManager.wrapTab(nativeTab), changed);
- }
- };
+ fireForTab(tab, changeInfo);
+ };
+
+ let statusListener = ({browser, status, url}) => {
+ let {BrowserApp} = browser.ownerGlobal;
+ let nativeTab = BrowserApp.getTabForBrowser(browser);
+ if (nativeTab) {
+ let changed = {status};
+ if (url) {
+ changed.url = url;
+ }
- windowTracker.addListener("status", statusListener);
- windowTracker.addListener("DOMTitleChanged", listener);
- return () => {
- windowTracker.removeListener("status", statusListener);
- windowTracker.removeListener("DOMTitleChanged", listener);
- };
+ fireForTab(tabManager.wrapTab(nativeTab), changed);
+ }
+ };
+
+ windowTracker.addListener("status", statusListener);
+ windowTracker.addListener("DOMTitleChanged", listener);
+ return () => {
+ windowTracker.removeListener("status", statusListener);
+ windowTracker.removeListener("DOMTitleChanged", listener);
+ };
+ },
}).api(),
async create(createProperties) {
let window = createProperties.windowId !== null ?
windowTracker.getWindow(createProperties.windowId, context) :
windowTracker.topWindow;
let {BrowserApp} = window;
--- a/mobile/android/components/extensions/ext-utils.js
+++ b/mobile/android/components/extensions/ext-utils.js
@@ -182,75 +182,51 @@ class WindowTracker extends WindowTracke
if (wrapper) {
wrapper.destroy();
listeners.delete(listener);
}
}
}
/**
- * An event manager API provider which listens for an event in the Android
- * global EventDispatcher, and calls the given listener function whenever an event
- * is received. That listener function receives a `fire` object, which it can
- * use to dispatch events to the extension, and an object detailing the
- * EventDispatcher event that was received.
+ * Helper to create an event manager which listens for an event in the Android
+ * global EventDispatcher, and calls the given listener function whenever the
+ * event is received. That listener function receives a `fire` object,
+ * which it can use to dispatch events to the extension, and an object
+ * detailing the EventDispatcher event that was received.
*
* @param {BaseContext} context
* The extension context which the event manager belongs to.
* @param {string} name
* The API name of the event manager, e.g.,"runtime.onMessage".
* @param {string} event
* The name of the EventDispatcher event to listen for.
* @param {function} listener
* The listener function to call when an EventDispatcher event is
* recieved.
+ *
+ * @returns {object} An injectable api for the new event.
*/
-global.GlobalEventManager = class extends EventManager {
- constructor(context, name, event, listener) {
- super(context, name, fire => {
+global.makeGlobalEvent = function makeGlobalEvent(context, name, event, listener) {
+ return new EventManager({
+ context,
+ name,
+ register: fire => {
let listener2 = {
onEvent(event, data, callback) {
listener(fire, data);
},
};
GlobalEventDispatcher.registerListener(listener2, [event]);
return () => {
GlobalEventDispatcher.unregisterListener(listener2, [event]);
};
- });
- }
-};
-
-/**
- * An event manager API provider which listens for a DOM event in any browser
- * window, and calls the given listener function whenever an event is received.
- * That listener function receives a `fire` object, which it can use to dispatch
- * events to the extension, and a DOM event object.
- *
- * @param {BaseContext} context
- * The extension context which the event manager belongs to.
- * @param {string} name
- * The API name of the event manager, e.g.,"runtime.onMessage".
- * @param {string} event
- * The name of the DOM event to listen for.
- * @param {function} listener
- * The listener function to call when a DOM event is received.
- */
-global.WindowEventManager = class extends EventManager {
- constructor(context, name, event, listener) {
- super(context, name, fire => {
- let listener2 = listener.bind(null, fire);
-
- windowTracker.addListener(event, listener2);
- return () => {
- windowTracker.removeListener(event, listener2);
- };
- });
- }
+ },
+ }).api();
};
class TabTracker extends TabTrackerBase {
constructor() {
super();
// Keep track of the extension popup tab.
this._extensionPopupTabWeak = null;
--- a/toolkit/components/extensions/ExtensionChild.jsm
+++ b/toolkit/components/extensions/ExtensionChild.jsm
@@ -174,29 +174,37 @@ class Port {
disconnect: () => {
this.disconnect();
},
postMessage: json => {
this.postMessage(json);
},
- onDisconnect: new EventManager(this.context, "Port.onDisconnect", fire => {
- return this.registerOnDisconnect(holder => {
- let error = holder && holder.deserialize(this.context.cloneScope);
- portError = error && this.context.normalizeError(error);
- fire.asyncWithoutClone(portObj);
- });
+ onDisconnect: new EventManager({
+ context: this.context,
+ name: "Port.onDisconnect",
+ register: fire => {
+ return this.registerOnDisconnect(holder => {
+ let error = holder && holder.deserialize(this.context.cloneScope);
+ portError = error && this.context.normalizeError(error);
+ fire.asyncWithoutClone(portObj);
+ });
+ },
}).api(),
- onMessage: new EventManager(this.context, "Port.onMessage", fire => {
- return this.registerOnMessage(holder => {
- let msg = holder.deserialize(this.context.cloneScope);
- fire.asyncWithoutClone(msg, portObj);
- });
+ onMessage: new EventManager({
+ context: this.context,
+ name: "Port.onMessage",
+ register: fire => {
+ return this.registerOnMessage(holder => {
+ let msg = holder.deserialize(this.context.cloneScope);
+ fire.asyncWithoutClone(msg, portObj);
+ });
+ },
}).api(),
get error() {
return portError;
},
};
if (this.sender) {
@@ -398,73 +406,77 @@ class Messenger {
}
sendNativeMessage(messageManager, msg, recipient, responseCallback) {
msg = NativeApp.encodeMessage(this.context, msg);
return this.sendMessage(messageManager, msg, recipient, responseCallback);
}
_onMessage(name, filter) {
- return new EventManager(this.context, name, fire => {
- const caller = this.context.getCaller();
+ return new EventManager({
+ context: this.context,
+ name,
+ register: fire => {
+ const caller = this.context.getCaller();
- let listener = {
- messageFilterPermissive: this.optionalFilter,
- messageFilterStrict: this.filter,
+ let listener = {
+ messageFilterPermissive: this.optionalFilter,
+ messageFilterStrict: this.filter,
- filterMessage: (sender, recipient) => {
- // Exclude messages coming from content scripts for the devtools extension contexts
- // (See Bug 1383310).
- if (this.excludeContentScriptSender && sender.envType === "content_child") {
- return false;
- }
+ filterMessage: (sender, recipient) => {
+ // Exclude messages coming from content scripts for the devtools extension contexts
+ // (See Bug 1383310).
+ if (this.excludeContentScriptSender && sender.envType === "content_child") {
+ return false;
+ }
- // Ignore the message if it was sent by this Messenger.
- return (sender.contextId !== this.context.contextId &&
- filter(sender, recipient));
- },
+ // Ignore the message if it was sent by this Messenger.
+ return (sender.contextId !== this.context.contextId &&
+ filter(sender, recipient));
+ },
- receiveMessage: ({target, data: holder, sender, recipient, channelId}) => {
- if (!this.context.active) {
- return;
- }
+ receiveMessage: ({target, data: holder, sender, recipient, channelId}) => {
+ if (!this.context.active) {
+ return;
+ }
- let sendResponse;
- let response = undefined;
- let promise = new Promise(resolve => {
- sendResponse = value => {
- resolve(value);
- response = promise;
- };
- });
+ let sendResponse;
+ let response = undefined;
+ let promise = new Promise(resolve => {
+ sendResponse = value => {
+ resolve(value);
+ response = promise;
+ };
+ });
- let message = holder.deserialize(this.context.cloneScope);
- holder = null;
+ let message = holder.deserialize(this.context.cloneScope);
+ holder = null;
- sender = Cu.cloneInto(sender, this.context.cloneScope);
- sendResponse = Cu.exportFunction(sendResponse, this.context.cloneScope);
+ sender = Cu.cloneInto(sender, this.context.cloneScope);
+ sendResponse = Cu.exportFunction(sendResponse, this.context.cloneScope);
- // Note: We intentionally do not use runSafe here so that any
- // errors are propagated to the message sender.
- let result = fire.raw(message, sender, sendResponse);
- message = null;
+ // Note: We intentionally do not use runSafe here so that any
+ // errors are propagated to the message sender.
+ let result = fire.raw(message, sender, sendResponse);
+ message = null;
- if (result instanceof this.context.cloneScope.Promise) {
- return StrongPromise.wrap(result, channelId, caller);
- } else if (result === true) {
- return StrongPromise.wrap(promise, channelId, caller);
- }
- return response;
- },
- };
+ if (result instanceof this.context.cloneScope.Promise) {
+ return StrongPromise.wrap(result, channelId, caller);
+ } else if (result === true) {
+ return StrongPromise.wrap(promise, channelId, caller);
+ }
+ return response;
+ },
+ };
- MessageChannel.addListener(this.messageManagers, "Extension:Message", listener);
- return () => {
- MessageChannel.removeListener(this.messageManagers, "Extension:Message", listener);
- };
+ MessageChannel.addListener(this.messageManagers, "Extension:Message", listener);
+ return () => {
+ MessageChannel.removeListener(this.messageManagers, "Extension:Message", listener);
+ };
+ },
}).api();
}
onMessage(name) {
return this._onMessage(name, sender => sender.id === this.sender.id);
}
onMessageExternal(name) {
@@ -501,51 +513,55 @@ class Messenger {
let portId = getUniqueId();
let port = new NativePort(this.context, messageManager, this.messageManagers, name, portId, null, recipient);
return this._connect(messageManager, port, recipient);
}
_onConnect(name, filter) {
- return new EventManager(this.context, name, fire => {
- let listener = {
- messageFilterPermissive: this.optionalFilter,
- messageFilterStrict: this.filter,
+ return new EventManager({
+ context: this.context,
+ name,
+ register: fire => {
+ let listener = {
+ messageFilterPermissive: this.optionalFilter,
+ messageFilterStrict: this.filter,
- filterMessage: (sender, recipient) => {
- // Exclude messages coming from content scripts for the devtools extension contexts
- // (See Bug 1383310).
- if (this.excludeContentScriptSender && sender.envType === "content_child") {
- return false;
- }
+ filterMessage: (sender, recipient) => {
+ // Exclude messages coming from content scripts for the devtools extension contexts
+ // (See Bug 1383310).
+ if (this.excludeContentScriptSender && sender.envType === "content_child") {
+ return false;
+ }
- // Ignore the port if it was created by this Messenger.
- return (sender.contextId !== this.context.contextId &&
- filter(sender, recipient));
- },
+ // Ignore the port if it was created by this Messenger.
+ return (sender.contextId !== this.context.contextId &&
+ filter(sender, recipient));
+ },
- receiveMessage: ({target, data: message, sender}) => {
- let {name, portId} = message;
- let mm = getMessageManager(target);
- let recipient = Object.assign({}, sender);
- if (recipient.tab) {
- recipient.tabId = recipient.tab.id;
- delete recipient.tab;
- }
- let port = new Port(this.context, mm, this.messageManagers, name, portId, sender, recipient);
- fire.asyncWithoutClone(port.api());
- return true;
- },
- };
+ receiveMessage: ({target, data: message, sender}) => {
+ let {name, portId} = message;
+ let mm = getMessageManager(target);
+ let recipient = Object.assign({}, sender);
+ if (recipient.tab) {
+ recipient.tabId = recipient.tab.id;
+ delete recipient.tab;
+ }
+ let port = new Port(this.context, mm, this.messageManagers, name, portId, sender, recipient);
+ fire.asyncWithoutClone(port.api());
+ return true;
+ },
+ };
- MessageChannel.addListener(this.messageManagers, "Extension:Connect", listener);
- return () => {
- MessageChannel.removeListener(this.messageManagers, "Extension:Connect", listener);
- };
+ MessageChannel.addListener(this.messageManagers, "Extension:Connect", listener);
+ return () => {
+ MessageChannel.removeListener(this.messageManagers, "Extension:Connect", listener);
+ };
+ },
}).api();
}
onConnect(name) {
return this._onConnect(name, sender => sender.id === this.sender.id);
}
onConnectExternal(name) {
--- a/toolkit/components/extensions/ExtensionCommon.jsm
+++ b/toolkit/components/extensions/ExtensionCommon.jsm
@@ -1752,34 +1752,39 @@ defineLazyGetter(LocaleData.prototype, "
* }).api()
*
* The result is an object with addListener, removeListener, and
* hasListener methods. `context` is an add-on scope (either an
* ExtensionContext in the chrome process or ExtensionContext in a
* content process). `name` is for debugging. `register` is a function
* to register the listener. `register` should return an
* unregister function that will unregister the listener.
- * @constructor
- *
- * @param {BaseContext} context
- * An object representing the extension instance using this event.
- * @param {string} name
- * A name used only for debugging.
- * @param {functon} register
- * A function called whenever a new listener is added.
*/
-function EventManager(context, name, register) {
- this.context = context;
- this.name = name;
- this.register = register;
- this.unregister = new Map();
- this.inputHandling = false;
-}
+class EventManager {
+ /*
+ * @param {object} params
+ * Parameters that control this EventManager.
+ * @param {BaseContext} params.context
+ * An object representing the extension instance using this event.
+ * @param {string} params.name
+ * A name used only for debugging.
+ * @param {functon} params.register
+ * A function called whenever a new listener is added.
+ * @param {boolean} [params.inputHandling=false]
+ * If true, the "handling user input" flag is set while handlers
+ * for this event are executing.
+ */
+ constructor({context, name, register, inputHandling = false}) {
+ this.context = context;
+ this.name = name;
+ this.register = register;
+ this.unregister = new Map();
+ this.inputHandling = inputHandling;
+ }
-EventManager.prototype = {
addListener(callback, ...args) {
if (this.unregister.has(callback)) {
return;
}
let shouldFire = () => {
if (this.context.unloaded) {
dump(`${this.name} event fired after context unloaded.\n`);
@@ -1814,63 +1819,62 @@ EventManager.prototype = {
return Promise.resolve().then(() => {
if (shouldFire()) {
return this.context.applySafeWithoutClone(callback, args);
}
});
},
};
-
let unregister = this.register(fire, ...args);
this.unregister.set(callback, unregister);
this.context.callOnClose(this);
- },
+ }
removeListener(callback) {
if (!this.unregister.has(callback)) {
return;
}
let unregister = this.unregister.get(callback);
this.unregister.delete(callback);
try {
unregister();
} catch (e) {
Cu.reportError(e);
}
if (this.unregister.size == 0) {
this.context.forgetOnClose(this);
}
- },
+ }
hasListener(callback) {
return this.unregister.has(callback);
- },
+ }
revoke() {
for (let callback of this.unregister.keys()) {
this.removeListener(callback);
}
- },
+ }
close() {
this.revoke();
- },
+ }
api() {
return {
addListener: (...args) => this.addListener(...args),
removeListener: (...args) => this.removeListener(...args),
hasListener: (...args) => this.hasListener(...args),
setUserInput: this.inputHandling,
[Schemas.REVOKE]: () => this.revoke(),
};
- },
-};
+ }
+}
// Simple API for event listeners where events never fire.
function ignoreEvent(context, name) {
return {
addListener: function(callback) {
let id = context.extension.id;
let frame = Components.stack.caller;
let msg = `In add-on ${id}, attempting to use listener "${name}", which is unimplemented.`;
--- a/toolkit/components/extensions/ext-alarms.js
+++ b/toolkit/components/extensions/ext-alarms.js
@@ -120,22 +120,26 @@ this.alarms = class extends ExtensionAPI
let cleared = false;
for (let alarm of self.alarms.values()) {
alarm.clear();
cleared = true;
}
return Promise.resolve(cleared);
},
- onAlarm: new EventManager(context, "alarms.onAlarm", fire => {
- let callback = alarm => {
- fire.sync(alarm.data);
- };
+ onAlarm: new EventManager({
+ context,
+ name: "alarms.onAlarm",
+ register: fire => {
+ let callback = alarm => {
+ fire.sync(alarm.data);
+ };
- self.callbacks.add(callback);
- return () => {
- self.callbacks.delete(callback);
- };
+ self.callbacks.add(callback);
+ return () => {
+ self.callbacks.delete(callback);
+ };
+ },
}).api(),
},
};
}
};
--- a/toolkit/components/extensions/ext-c-storage.js
+++ b/toolkit/components/extensions/ext-c-storage.js
@@ -145,27 +145,31 @@ this.storage = class extends ExtensionAP
remove(keys) {
return Promise.reject({message: "storage.managed is read-only"});
},
clear() {
return Promise.reject({message: "storage.managed is read-only"});
},
},
- onChanged: new EventManager(context, "storage.onChanged", fire => {
- let onChanged = (data, area) => {
- let changes = new context.cloneScope.Object();
- for (let [key, value] of Object.entries(data)) {
- changes[key] = deserialize(value);
- }
- fire.raw(changes, area);
- };
+ onChanged: new EventManager({
+ context,
+ name: "storage.onChanged",
+ register: fire => {
+ let onChanged = (data, area) => {
+ let changes = new context.cloneScope.Object();
+ for (let [key, value] of Object.entries(data)) {
+ changes[key] = deserialize(value);
+ }
+ fire.raw(changes, area);
+ };
- let parent = context.childManager.getParentEvent("storage.onChanged");
- parent.addListener(onChanged);
- return () => {
- parent.removeListener(onChanged);
- };
+ let parent = context.childManager.getParentEvent("storage.onChanged");
+ parent.addListener(onChanged);
+ return () => {
+ parent.removeListener(onChanged);
+ };
+ },
}).api(),
},
};
}
};
--- a/toolkit/components/extensions/ext-c-test.js
+++ b/toolkit/components/extensions/ext-c-test.js
@@ -175,22 +175,28 @@ this.test = class extends ExtensionAPI {
let errorMessage = toSource(error && error.message);
assertTrue(errorMatches(error, expectedError, context),
`Function threw, expecting error to match ${toSource(expectedError)}` +
`got ${errorMessage}${msg}`);
}
},
- onMessage: new TestEventManager(context, "test.onMessage", fire => {
- let handler = (event, ...args) => {
- fire.async(...args);
- };
+ onMessage: new TestEventManager({
+ context,
+ name: "test.onMessage",
+ register: fire => {
+ let handler = (event, ...args) => {
+ dump(`in handler\n`);
+ fire.async(...args);
+ };
- extension.on("test-harness-message", handler);
- return () => {
- extension.off("test-harness-message", handler);
- };
+ dump(`in register, listening in ${extension.id}\n`);
+ extension.on("test-harness-message", handler);
+ return () => {
+ extension.off("test-harness-message", handler);
+ };
+ },
}).api(),
},
};
}
};
--- a/toolkit/components/extensions/ext-contextualIdentities.js
+++ b/toolkit/components/extensions/ext-contextualIdentities.js
@@ -222,56 +222,68 @@ this.contextualIdentities = class extend
if (!ContextualIdentityService.remove(identity.userContextId)) {
throw new ExtensionError(`Contextual identity failed to remove: ${cookieStoreId}`);
}
return convertedIdentity;
},
- onCreated: new EventManager(context, "contextualIdentities.onCreated", fire => {
- let observer = (subject, topic) => {
- let convertedIdentity = convertIdentityFromObserver(subject);
- if (convertedIdentity) {
- fire.async({contextualIdentity: convertedIdentity});
- }
- };
+ onCreated: new EventManager({
+ context,
+ name: "contextualIdentities.onCreated",
+ register: fire => {
+ let observer = (subject, topic) => {
+ let convertedIdentity = convertIdentityFromObserver(subject);
+ if (convertedIdentity) {
+ fire.async({contextualIdentity: convertedIdentity});
+ }
+ };
- Services.obs.addObserver(observer, "contextual-identity-created");
- return () => {
- Services.obs.removeObserver(observer, "contextual-identity-created");
- };
+ Services.obs.addObserver(observer, "contextual-identity-created");
+ return () => {
+ Services.obs.removeObserver(observer, "contextual-identity-created");
+ };
+ },
}).api(),
- onUpdated: new EventManager(context, "contextualIdentities.onUpdated", fire => {
- let observer = (subject, topic) => {
- let convertedIdentity = convertIdentityFromObserver(subject);
- if (convertedIdentity) {
- fire.async({contextualIdentity: convertedIdentity});
- }
- };
+ onUpdated: new EventManager({
+ context,
+ name: "contextualIdentities.onUpdated",
+ register: fire => {
+ let observer = (subject, topic) => {
+ let convertedIdentity = convertIdentityFromObserver(subject);
+ if (convertedIdentity) {
+ fire.async({contextualIdentity: convertedIdentity});
+ }
+ };
- Services.obs.addObserver(observer, "contextual-identity-updated");
- return () => {
- Services.obs.removeObserver(observer, "contextual-identity-updated");
- };
+ Services.obs.addObserver(observer, "contextual-identity-updated");
+ return () => {
+ Services.obs.removeObserver(observer, "contextual-identity-updated");
+ };
+ },
}).api(),
- onRemoved: new EventManager(context, "contextualIdentities.onRemoved", fire => {
- let observer = (subject, topic) => {
- let convertedIdentity = convertIdentityFromObserver(subject);
- if (convertedIdentity) {
- fire.async({contextualIdentity: convertedIdentity});
- }
- };
+ onRemoved: new EventManager({
+ context,
+ name: "contextualIdentities.onRemoved",
+ register: fire => {
+ let observer = (subject, topic) => {
+ let convertedIdentity = convertIdentityFromObserver(subject);
+ if (convertedIdentity) {
+ fire.async({contextualIdentity: convertedIdentity});
+ }
+ };
- Services.obs.addObserver(observer, "contextual-identity-deleted");
- return () => {
- Services.obs.removeObserver(observer, "contextual-identity-deleted");
- };
+ Services.obs.addObserver(observer, "contextual-identity-deleted");
+ return () => {
+ Services.obs.removeObserver(observer, "contextual-identity-deleted");
+ };
+ },
}).api(),
},
};
return self;
}
};
--- a/toolkit/components/extensions/ext-cookies.js
+++ b/toolkit/components/extensions/ext-cookies.js
@@ -410,57 +410,61 @@ this.cookies = class extends ExtensionAP
let result = [];
for (let key in data) {
result.push({id: key, tabIds: data[key], incognito: key == PRIVATE_STORE});
}
return Promise.resolve(result);
},
- onChanged: new EventManager(context, "cookies.onChanged", fire => {
- let observer = (subject, topic, data) => {
- let notify = (removed, cookie, cause) => {
- cookie.QueryInterface(Ci.nsICookie2);
+ onChanged: new EventManager({
+ context,
+ name: "cookies.onChanged",
+ register: fire => {
+ let observer = (subject, topic, data) => {
+ let notify = (removed, cookie, cause) => {
+ cookie.QueryInterface(Ci.nsICookie2);
+
+ if (extension.whiteListedHosts.matchesCookie(cookie)) {
+ fire.async({removed, cookie: convertCookie({cookie, isPrivate: topic == "private-cookie-changed"}), cause});
+ }
+ };
- if (extension.whiteListedHosts.matchesCookie(cookie)) {
- fire.async({removed, cookie: convertCookie({cookie, isPrivate: topic == "private-cookie-changed"}), cause});
+ // We do our best effort here to map the incompatible states.
+ switch (data) {
+ case "deleted":
+ notify(true, subject, "explicit");
+ break;
+ case "added":
+ notify(false, subject, "explicit");
+ break;
+ case "changed":
+ notify(true, subject, "overwrite");
+ notify(false, subject, "explicit");
+ break;
+ case "batch-deleted":
+ subject.QueryInterface(Ci.nsIArray);
+ for (let i = 0; i < subject.length; i++) {
+ let cookie = subject.queryElementAt(i, Ci.nsICookie2);
+ if (!cookie.isSession && cookie.expiry * 1000 <= Date.now()) {
+ notify(true, cookie, "expired");
+ } else {
+ notify(true, cookie, "evicted");
+ }
+ }
+ break;
}
};
- // We do our best effort here to map the incompatible states.
- switch (data) {
- case "deleted":
- notify(true, subject, "explicit");
- break;
- case "added":
- notify(false, subject, "explicit");
- break;
- case "changed":
- notify(true, subject, "overwrite");
- notify(false, subject, "explicit");
- break;
- case "batch-deleted":
- subject.QueryInterface(Ci.nsIArray);
- for (let i = 0; i < subject.length; i++) {
- let cookie = subject.queryElementAt(i, Ci.nsICookie2);
- if (!cookie.isSession && cookie.expiry * 1000 <= Date.now()) {
- notify(true, cookie, "expired");
- } else {
- notify(true, cookie, "evicted");
- }
- }
- break;
- }
- };
-
- Services.obs.addObserver(observer, "cookie-changed");
- Services.obs.addObserver(observer, "private-cookie-changed");
- return () => {
- Services.obs.removeObserver(observer, "cookie-changed");
- Services.obs.removeObserver(observer, "private-cookie-changed");
- };
+ Services.obs.addObserver(observer, "cookie-changed");
+ Services.obs.addObserver(observer, "private-cookie-changed");
+ return () => {
+ Services.obs.removeObserver(observer, "cookie-changed");
+ Services.obs.removeObserver(observer, "private-cookie-changed");
+ };
+ },
}).api(),
},
};
return self;
}
};
--- a/toolkit/components/extensions/ext-downloads.js
+++ b/toolkit/components/extensions/ext-downloads.js
@@ -757,69 +757,81 @@ this.downloads = class extends Extension
// i.e.:
// setShelfEnabled(enabled) {
// if (!extension.hasPermission("downloads.shelf")) {
// throw new context.cloneScope.Error("Permission denied because 'downloads.shelf' permission is missing.");
// }
// ...
// }
- onChanged: new EventManager(context, "downloads.onChanged", fire => {
- const handler = (what, item) => {
- let changes = {};
- const noundef = val => (val === undefined) ? null : val;
- DOWNLOAD_ITEM_CHANGE_FIELDS.forEach(fld => {
- if (item[fld] != item.prechange[fld]) {
- changes[fld] = {
- previous: noundef(item.prechange[fld]),
- current: noundef(item[fld]),
- };
+ onChanged: new EventManager({
+ context,
+ name: "downloads.onChanged",
+ register: fire => {
+ const handler = (what, item) => {
+ let changes = {};
+ const noundef = val => (val === undefined) ? null : val;
+ DOWNLOAD_ITEM_CHANGE_FIELDS.forEach(fld => {
+ if (item[fld] != item.prechange[fld]) {
+ changes[fld] = {
+ previous: noundef(item.prechange[fld]),
+ current: noundef(item[fld]),
+ };
+ }
+ });
+ if (Object.keys(changes).length > 0) {
+ changes.id = item.id;
+ fire.async(changes);
}
+ };
+
+ let registerPromise = DownloadMap.getDownloadList().then(() => {
+ DownloadMap.on("change", handler);
});
- if (Object.keys(changes).length > 0) {
- changes.id = item.id;
- fire.async(changes);
- }
- };
-
- let registerPromise = DownloadMap.getDownloadList().then(() => {
- DownloadMap.on("change", handler);
- });
- return () => {
- registerPromise.then(() => {
- DownloadMap.off("change", handler);
- });
- };
+ return () => {
+ registerPromise.then(() => {
+ DownloadMap.off("change", handler);
+ });
+ };
+ },
}).api(),
- onCreated: new EventManager(context, "downloads.onCreated", fire => {
- const handler = (what, item) => {
- fire.async(item.serialize());
- };
- let registerPromise = DownloadMap.getDownloadList().then(() => {
- DownloadMap.on("create", handler);
- });
- return () => {
- registerPromise.then(() => {
- DownloadMap.off("create", handler);
+ onCreated: new EventManager({
+ context,
+ name: "downloads.onCreated",
+ register: fire => {
+ const handler = (what, item) => {
+ fire.async(item.serialize());
+ };
+ let registerPromise = DownloadMap.getDownloadList().then(() => {
+ DownloadMap.on("create", handler);
});
- };
+ return () => {
+ registerPromise.then(() => {
+ DownloadMap.off("create", handler);
+ });
+ };
+ },
}).api(),
- onErased: new EventManager(context, "downloads.onErased", fire => {
- const handler = (what, item) => {
- fire.async(item.id);
- };
- let registerPromise = DownloadMap.getDownloadList().then(() => {
- DownloadMap.on("erase", handler);
- });
- return () => {
- registerPromise.then(() => {
- DownloadMap.off("erase", handler);
+ onErased: new EventManager({
+ context,
+ name: "downloads.onErased",
+ register: fire => {
+ const handler = (what, item) => {
+ fire.async(item.id);
+ };
+ let registerPromise = DownloadMap.getDownloadList().then(() => {
+ DownloadMap.on("erase", handler);
});
- };
+ return () => {
+ registerPromise.then(() => {
+ DownloadMap.off("erase", handler);
+ });
+ };
+ },
}).api(),
onDeterminingFilename: ignoreEvent(context, "downloads.onDeterminingFilename"),
},
};
}
};
--- a/toolkit/components/extensions/ext-idle.js
+++ b/toolkit/components/extensions/ext-idle.js
@@ -68,22 +68,26 @@ this.idle = class extends ExtensionAPI {
if (idleService.idleTime < detectionIntervalInSeconds * 1000) {
return Promise.resolve("active");
}
return Promise.resolve("idle");
},
setDetectionInterval: function(detectionIntervalInSeconds) {
setDetectionInterval(extension, context, detectionIntervalInSeconds);
},
- onStateChanged: new EventManager(context, "idle.onStateChanged", fire => {
- let listener = (event, data) => {
- fire.sync(data);
- };
+ onStateChanged: new EventManager({
+ context,
+ name: "idle.onStateChanged",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.sync(data);
+ };
- getIdleObserver(extension, context).on("stateChanged", listener);
- return () => {
- getIdleObserver(extension, context).off("stateChanged", listener);
- };
+ getIdleObserver(extension, context).on("stateChanged", listener);
+ return () => {
+ getIdleObserver(extension, context).off("stateChanged", listener);
+ };
+ },
}).api(),
},
};
}
};
--- a/toolkit/components/extensions/ext-management.js
+++ b/toolkit/components/extensions/ext-management.js
@@ -228,56 +228,72 @@ this.management = class extends Extensio
throw new ExtensionError("setEnabled applies only to theme addons");
}
if (addon.isSystem) {
throw new ExtensionError("setEnabled cannot be used with a system addon");
}
addon.userDisabled = !enabled;
},
- onDisabled: new EventManager(context, "management.onDisabled", fire => {
- let listener = (event, data) => {
- fire.async(data);
- };
+ onDisabled: new EventManager({
+ context,
+ name: "management.onDisabled",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.async(data);
+ };
- getManagementListener(extension, context).on("onDisabled", listener);
- return () => {
- getManagementListener(extension, context).off("onDisabled", listener);
- };
+ getManagementListener(extension, context).on("onDisabled", listener);
+ return () => {
+ getManagementListener(extension, context).off("onDisabled", listener);
+ };
+ },
}).api(),
- onEnabled: new EventManager(context, "management.onEnabled", fire => {
- let listener = (event, data) => {
- fire.async(data);
- };
+ onEnabled: new EventManager({
+ context,
+ name: "management.onEnabled",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.async(data);
+ };
- getManagementListener(extension, context).on("onEnabled", listener);
- return () => {
- getManagementListener(extension, context).off("onEnabled", listener);
- };
+ getManagementListener(extension, context).on("onEnabled", listener);
+ return () => {
+ getManagementListener(extension, context).off("onEnabled", listener);
+ };
+ },
}).api(),
- onInstalled: new EventManager(context, "management.onInstalled", fire => {
- let listener = (event, data) => {
- fire.async(data);
- };
+ onInstalled: new EventManager({
+ context,
+ name: "management.onInstalled",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.async(data);
+ };
- getManagementListener(extension, context).on("onInstalled", listener);
- return () => {
- getManagementListener(extension, context).off("onInstalled", listener);
- };
+ getManagementListener(extension, context).on("onInstalled", listener);
+ return () => {
+ getManagementListener(extension, context).off("onInstalled", listener);
+ };
+ },
}).api(),
- onUninstalled: new EventManager(context, "management.onUninstalled", fire => {
- let listener = (event, data) => {
- fire.async(data);
- };
+ onUninstalled: new EventManager({
+ context,
+ name: "management.onUninstalled",
+ register: fire => {
+ let listener = (event, data) => {
+ fire.async(data);
+ };
- getManagementListener(extension, context).on("onUninstalled", listener);
- return () => {
- getManagementListener(extension, context).off("onUninstalled", listener);
- };
+ getManagementListener(extension, context).on("onUninstalled", listener);
+ return () => {
+ getManagementListener(extension, context).off("onUninstalled", listener);
+ };
+ },
}).api(),
},
};
}
};
--- a/toolkit/components/extensions/ext-notifications.js
+++ b/toolkit/components/extensions/ext-notifications.js
@@ -115,48 +115,60 @@ this.notifications = class extends Exten
getAll: function() {
let result = {};
notificationsMap.forEach((value, key) => {
result[key] = value.options;
});
return Promise.resolve(result);
},
- onClosed: new EventManager(context, "notifications.onClosed", fire => {
- let listener = (event, notificationId) => {
- // TODO Bug 1413188, Support the byUser argument.
- fire.async(notificationId, true);
- };
+ onClosed: new EventManager({
+ context,
+ name: "notifications.onClosed",
+ register: fire => {
+ let listener = (event, notificationId) => {
+ // TODO Bug 1413188, Support the byUser argument.
+ fire.async(notificationId, true);
+ };
- notificationsMap.on("closed", listener);
- return () => {
- notificationsMap.off("closed", listener);
- };
+ notificationsMap.on("closed", listener);
+ return () => {
+ notificationsMap.off("closed", listener);
+ };
+ },
}).api(),
- onClicked: new EventManager(context, "notifications.onClicked", fire => {
- let listener = (event, notificationId) => {
- fire.async(notificationId, true);
- };
+ onClicked: new EventManager({
+ context,
+ name: "notifications.onClicked",
+ register: fire => {
+ let listener = (event, notificationId) => {
+ fire.async(notificationId, true);
+ };
- notificationsMap.on("clicked", listener);
- return () => {
- notificationsMap.off("clicked", listener);
- };
+ notificationsMap.on("clicked", listener);
+ return () => {
+ notificationsMap.off("clicked", listener);
+ };
+ },
}).api(),
- onShown: new EventManager(context, "notifications.onShown", fire => {
- let listener = (event, notificationId) => {
- fire.async(notificationId, true);
- };
+ onShown: new EventManager({
+ context,
+ name: "notifications.onShown",
+ register: fire => {
+ let listener = (event, notificationId) => {
+ fire.async(notificationId, true);
+ };
- notificationsMap.on("shown", listener);
- return () => {
- notificationsMap.off("shown", listener);
- };
+ notificationsMap.on("shown", listener);
+ return () => {
+ notificationsMap.off("shown", listener);
+ };
+ },
}).api(),
// TODO Bug 1190681, implement button support.
onButtonClicked: ignoreEvent(context, "notifications.onButtonClicked"),
},
};
}
};
--- a/toolkit/components/extensions/ext-proxy.js
+++ b/toolkit/components/extensions/ext-proxy.js
@@ -42,17 +42,17 @@ class ProxyFilterEventManager extends Ev
}
let proxyFilter = new ProxyChannelFilter(context, listener, filter, extraInfoSpec);
return () => {
proxyFilter.destroy();
};
};
- super(context, name, register);
+ super({context, name, register});
}
}
this.proxy = class extends ExtensionAPI {
onShutdown() {
let {extension} = this;
let proxyScriptContext = proxyScriptContextMap.get(extension);
@@ -60,24 +60,28 @@ this.proxy = class extends ExtensionAPI
proxyScriptContext.unload();
proxyScriptContextMap.delete(extension);
}
}
getAPI(context) {
let {extension} = context;
- let onError = new EventManager(context, "proxy.onError", fire => {
- let listener = (name, error) => {
- fire.async(error);
- };
- extension.on("proxy-error", listener);
- return () => {
- extension.off("proxy-error", listener);
- };
+ let onError = new EventManager({
+ context,
+ name: "proxy.onError",
+ register: fire => {
+ let listener = (name, error) => {
+ fire.async(error);
+ };
+ extension.on("proxy-error", listener);
+ return () => {
+ extension.off("proxy-error", listener);
+ };
+ },
}).api();
return {
proxy: {
register(url) {
this.unregister();
let proxyScriptContext = new ProxyScriptContext(extension, url);
--- a/toolkit/components/extensions/ext-runtime.js
+++ b/toolkit/components/extensions/ext-runtime.js
@@ -14,74 +14,86 @@ ChromeUtils.defineModuleGetter(this, "Se
ChromeUtils.defineModuleGetter(this, "DevToolsShim",
"chrome://devtools-shim/content/DevToolsShim.jsm");
this.runtime = class extends ExtensionAPI {
getAPI(context) {
let {extension} = context;
return {
runtime: {
- onStartup: new EventManager(context, "runtime.onStartup", fire => {
- if (context.incognito) {
- // This event should not fire if we are operating in a private profile.
- return () => {};
- }
- let listener = () => {
- if (extension.startupReason === "APP_STARTUP") {
- fire.sync();
+ onStartup: new EventManager({
+ context,
+ name: "runtime.onStartup",
+ register: fire => {
+ if (context.incognito) {
+ // This event should not fire if we are operating in a private profile.
+ return () => {};
}
- };
- extension.on("startup", listener);
- return () => {
- extension.off("startup", listener);
- };
+ let listener = () => {
+ if (extension.startupReason === "APP_STARTUP") {
+ fire.sync();
+ }
+ };
+ extension.on("startup", listener);
+ return () => {
+ extension.off("startup", listener);
+ };
+ },
}).api(),
- onInstalled: new EventManager(context, "runtime.onInstalled", fire => {
- let temporary = !!extension.addonData.temporarilyInstalled;
+ onInstalled: new EventManager({
+ context,
+ name: "runtime.onInstalled",
+ register: fire => {
+ let temporary = !!extension.addonData.temporarilyInstalled;
- let listener = () => {
- switch (extension.startupReason) {
- case "APP_STARTUP":
- if (AddonManagerPrivate.browserUpdated) {
- fire.sync({reason: "browser_update", temporary});
- }
- break;
- case "ADDON_INSTALL":
- fire.sync({reason: "install", temporary});
- break;
- case "ADDON_UPGRADE":
- fire.sync({
- reason: "update",
- previousVersion: extension.addonData.oldVersion,
- temporary,
- });
- break;
- }
- };
- extension.on("startup", listener);
- return () => {
- extension.off("startup", listener);
- };
+ let listener = () => {
+ switch (extension.startupReason) {
+ case "APP_STARTUP":
+ if (AddonManagerPrivate.browserUpdated) {
+ fire.sync({reason: "browser_update", temporary});
+ }
+ break;
+ case "ADDON_INSTALL":
+ fire.sync({reason: "install", temporary});
+ break;
+ case "ADDON_UPGRADE":
+ fire.sync({
+ reason: "update",
+ previousVersion: extension.addonData.oldVersion,
+ temporary,
+ });
+ break;
+ }
+ };
+ extension.on("startup", listener);
+ return () => {
+ extension.off("startup", listener);
+ };
+ },
}).api(),
- onUpdateAvailable: new EventManager(context, "runtime.onUpdateAvailable", fire => {
- let instanceID = extension.addonData.instanceID;
- AddonManager.addUpgradeListener(instanceID, upgrade => {
- extension.upgrade = upgrade;
- let details = {
- version: upgrade.version,
+ onUpdateAvailable: new EventManager({
+ context,
+ name: "runtime.onUpdateAvailable",
+ register: fire => {
+ let instanceID = extension.addonData.instanceID;
+ AddonManager.addUpgradeListener(instanceID, upgrade => {
+ extension.upgrade = upgrade;
+ let details = {
+ version: upgrade.version,
+ };
+ fire.sync(details);
+ });
+ return () => {
+ AddonManager.removeUpgradeListener(instanceID).catch(e => {
+ // This can happen if we try this after shutdown is complete.
+ });
};
- fire.sync(details);
- });
- return () => {
- AddonManager.removeUpgradeListener(instanceID).catch(e => {
- // This can happen if we try this after shutdown is complete.
- });
- };
+ },
}).api(),
reload: () => {
if (extension.upgrade) {
// If there is a pending update, install it now.
extension.upgrade.install();
} else {
// Otherwise, reload the current extension.
--- a/toolkit/components/extensions/ext-storage.js
+++ b/toolkit/components/extensions/ext-storage.js
@@ -87,27 +87,31 @@ this.storage = class extends ExtensionAP
let data = await lookup;
if (!data) {
return Promise.reject({message: "Managed storage manifest not found"});
}
return ExtensionStorage._filterProperties(data, keys);
},
},
- onChanged: new EventManager(context, "storage.onChanged", fire => {
- let listenerLocal = changes => {
- fire.raw(changes, "local");
- };
- let listenerSync = changes => {
- fire.async(changes, "sync");
- };
+ onChanged: new EventManager({
+ context,
+ name: "storage.onChanged",
+ register: fire => {
+ let listenerLocal = changes => {
+ fire.raw(changes, "local");
+ };
+ let listenerSync = changes => {
+ fire.async(changes, "sync");
+ };
- ExtensionStorage.addOnChangedListener(extension.id, listenerLocal);
- extensionStorageSync.addOnChangedListener(extension, listenerSync, context);
- return () => {
- ExtensionStorage.removeOnChangedListener(extension.id, listenerLocal);
- extensionStorageSync.removeOnChangedListener(extension, listenerSync);
- };
+ ExtensionStorage.addOnChangedListener(extension.id, listenerLocal);
+ extensionStorageSync.addOnChangedListener(extension, listenerSync, context);
+ return () => {
+ ExtensionStorage.removeOnChangedListener(extension.id, listenerLocal);
+ extensionStorageSync.removeOnChangedListener(extension, listenerSync);
+ };
+ },
}).api(),
},
};
}
};
--- a/toolkit/components/extensions/ext-theme.js
+++ b/toolkit/components/extensions/ext-theme.js
@@ -401,26 +401,30 @@ this.theme = class extends ExtensionAPI
if (!defaultTheme && !windowOverrides.has(windowId)) {
// If no theme has been initialized, nothing to do.
return;
}
Theme.unload(windowId);
},
- onUpdated: new EventManager(context, "theme.onUpdated", fire => {
- let callback = (event, theme, windowId) => {
- if (windowId) {
- fire.async({theme, windowId});
- } else {
- fire.async({theme});
- }
- };
+ onUpdated: new EventManager({
+ context,
+ name: "theme.onUpdated",
+ register: fire => {
+ let callback = (event, theme, windowId) => {
+ if (windowId) {
+ fire.async({theme, windowId});
+ } else {
+ fire.async({theme});
+ }
+ };
- onUpdatedEmitter.on("theme-updated", callback);
- return () => {
- onUpdatedEmitter.off("theme-updated", callback);
- };
+ onUpdatedEmitter.on("theme-updated", callback);
+ return () => {
+ onUpdatedEmitter.off("theme-updated", callback);
+ };
+ },
}).api(),
},
};
}
};
--- a/toolkit/components/extensions/ext-toolkit.js
+++ b/toolkit/components/extensions/ext-toolkit.js
@@ -16,22 +16,16 @@ ChromeUtils.defineModuleGetter(this, "Co
"resource://gre/modules/ContextualIdentityService.jsm");
Cu.importGlobalProperties(["URL"]);
ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
global.EventEmitter = ExtensionUtils.EventEmitter;
global.EventManager = ExtensionCommon.EventManager;
-global.InputEventManager = class extends EventManager {
- constructor(...args) {
- super(...args);
- this.inputHandling = true;
- }
-};
/* globals DEFAULT_STORE, PRIVATE_STORE, CONTAINER_STORE */
global.DEFAULT_STORE = "firefox-default";
global.PRIVATE_STORE = "firefox-private";
global.CONTAINER_STORE = "firefox-container-";
global.getCookieStoreIdForTab = function(data, tab) {
--- a/toolkit/components/extensions/ext-webNavigation.js
+++ b/toolkit/components/extensions/ext-webNavigation.js
@@ -88,89 +88,93 @@ const fillTransitionProperties = (eventN
// Fill the transition properties in the webNavigation event object.
dst.transitionType = transitionType;
dst.transitionQualifiers = transitionQualifiers;
}
};
// Similar to WebRequestEventManager but for WebNavigation.
-function WebNavigationEventManager(context, eventName) {
- let name = `webNavigation.${eventName}`;
- let register = (fire, urlFilters) => {
- // Don't create a MatchURLFilters instance if the listener does not include any filter.
- let filters = urlFilters ? new MatchURLFilters(urlFilters.url) : null;
+class WebNavigationEventManager extends EventManager {
+ constructor(context, eventName) {
+ let name = `webNavigation.${eventName}`;
+ let register = (fire, urlFilters) => {
+ // Don't create a MatchURLFilters instance if the listener does not include any filter.
+ let filters = urlFilters ? new MatchURLFilters(urlFilters.url) : null;
+
+ let listener = data => {
+ if (!data.browser) {
+ return;
+ }
+
+ let data2 = {
+ url: data.url,
+ timeStamp: Date.now(),
+ };
+
+ if (eventName == "onErrorOccurred") {
+ data2.error = data.error;
+ }
- let listener = data => {
- if (!data.browser) {
- return;
- }
+ if (data.frameId != undefined) {
+ data2.frameId = data.frameId;
+ data2.parentFrameId = data.parentFrameId;
+ }
+
+ if (data.sourceFrameId != undefined) {
+ data2.sourceFrameId = data.sourceFrameId;
+ }
- let data2 = {
- url: data.url,
- timeStamp: Date.now(),
+ // Fills in tabId typically.
+ Object.assign(data2, tabTracker.getBrowserData(data.browser));
+ if (data2.tabId < 0) {
+ return;
+ }
+
+ if (data.sourceTabBrowser) {
+ data2.sourceTabId = tabTracker.getBrowserData(data.sourceTabBrowser).tabId;
+ }
+
+ fillTransitionProperties(eventName, data, data2);
+
+ fire.async(data2);
};
- if (eventName == "onErrorOccurred") {
- data2.error = data.error;
- }
-
- if (data.frameId != undefined) {
- data2.frameId = data.frameId;
- data2.parentFrameId = data.parentFrameId;
- }
-
- if (data.sourceFrameId != undefined) {
- data2.sourceFrameId = data.sourceFrameId;
- }
-
- // Fills in tabId typically.
- Object.assign(data2, tabTracker.getBrowserData(data.browser));
- if (data2.tabId < 0) {
- return;
- }
-
- if (data.sourceTabBrowser) {
- data2.sourceTabId = tabTracker.getBrowserData(data.sourceTabBrowser).tabId;
- }
-
- fillTransitionProperties(eventName, data, data2);
-
- fire.async(data2);
+ WebNavigation[eventName].addListener(listener, filters);
+ return () => {
+ WebNavigation[eventName].removeListener(listener);
+ };
};
- WebNavigation[eventName].addListener(listener, filters);
- return () => {
- WebNavigation[eventName].removeListener(listener);
- };
- };
-
- return EventManager.call(this, context, name, register);
+ super({context, name, register});
+ }
}
-WebNavigationEventManager.prototype = Object.create(EventManager.prototype);
-
const convertGetFrameResult = (tabId, data) => {
return {
errorOccurred: data.errorOccurred,
url: data.url,
tabId,
frameId: data.frameId,
parentFrameId: data.parentFrameId,
};
};
this.webNavigation = class extends ExtensionAPI {
getAPI(context) {
let {tabManager} = context.extension;
return {
webNavigation: {
- onTabReplaced: new EventManager(context, "webNavigation.onTabReplaced", fire => {
- return () => {};
+ onTabReplaced: new EventManager({
+ context,
+ name: "webNavigation.onTabReplaced",
+ register: fire => {
+ return () => {};
+ },
}).api(),
onBeforeNavigate: new WebNavigationEventManager(context, "onBeforeNavigate").api(),
onCommitted: new WebNavigationEventManager(context, "onCommitted").api(),
onDOMContentLoaded: new WebNavigationEventManager(context, "onDOMContentLoaded").api(),
onCompleted: new WebNavigationEventManager(context, "onCompleted").api(),
onErrorOccurred: new WebNavigationEventManager(context, "onErrorOccurred").api(),
onReferenceFragmentUpdated: new WebNavigationEventManager(context, "onReferenceFragmentUpdated").api(),
onHistoryStateUpdated: new WebNavigationEventManager(context, "onHistoryStateUpdated").api(),
--- a/toolkit/components/extensions/ext-webRequest.js
+++ b/toolkit/components/extensions/ext-webRequest.js
@@ -79,33 +79,31 @@ function WebRequestEventManager(context,
WebRequest[eventName].addListener(
listener, filter2, info2,
listenerDetails);
return () => {
WebRequest[eventName].removeListener(listener);
};
};
- return EventManager.call(this, context, name, register);
+ return new EventManager({context, name, register}).api();
}
-WebRequestEventManager.prototype = Object.create(EventManager.prototype);
-
this.webRequest = class extends ExtensionAPI {
getAPI(context) {
return {
webRequest: {
- onBeforeRequest: new WebRequestEventManager(context, "onBeforeRequest").api(),
- onBeforeSendHeaders: new WebRequestEventManager(context, "onBeforeSendHeaders").api(),
- onSendHeaders: new WebRequestEventManager(context, "onSendHeaders").api(),
- onHeadersReceived: new WebRequestEventManager(context, "onHeadersReceived").api(),
- onAuthRequired: new WebRequestEventManager(context, "onAuthRequired").api(),
- onBeforeRedirect: new WebRequestEventManager(context, "onBeforeRedirect").api(),
- onResponseStarted: new WebRequestEventManager(context, "onResponseStarted").api(),
- onErrorOccurred: new WebRequestEventManager(context, "onErrorOccurred").api(),
- onCompleted: new WebRequestEventManager(context, "onCompleted").api(),
+ onBeforeRequest: WebRequestEventManager(context, "onBeforeRequest"),
+ onBeforeSendHeaders: WebRequestEventManager(context, "onBeforeSendHeaders"),
+ onSendHeaders: WebRequestEventManager(context, "onSendHeaders"),
+ onHeadersReceived: WebRequestEventManager(context, "onHeadersReceived"),
+ onAuthRequired: WebRequestEventManager(context, "onAuthRequired"),
+ onBeforeRedirect: WebRequestEventManager(context, "onBeforeRedirect"),
+ onResponseStarted: WebRequestEventManager(context, "onResponseStarted"),
+ onErrorOccurred: WebRequestEventManager(context, "onErrorOccurred"),
+ onCompleted: WebRequestEventManager(context, "onCompleted"),
handlerBehaviorChanged: function() {
// TODO: Flush all caches.
},
},
};
}
};
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contexts.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contexts.js
@@ -60,21 +60,25 @@ add_task(async function test_post_unload
await new Promise(resolve => setTimeout(resolve, 0));
});
add_task(async function test_post_unload_listeners() {
let context = new StubContext();
let fire;
- let manager = new EventManager(context, "EventManager", _fire => {
- fire = () => {
- _fire.async();
- };
- return () => {};
+ let manager = new EventManager({
+ context,
+ name: "EventManager",
+ register: _fire => {
+ fire = () => {
+ _fire.async();
+ };
+ return () => {};
+ },
});
let fail = event => {
ok(false, `Unexpected event: ${event}`);
};
// Check that event listeners isn't called after it has been removed.
manager.addListener(fail);