--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -75,22 +75,26 @@ const convertBookmarks = result => {
node.url = result.url.href; // Output is always URL object.
} else {
node.dateGroupModified = result.lastModified.getTime();
}
return node;
};
-let observer = {
- skipTags: true,
- skipDescendantsOnItemRemoval: true,
+let observer = new class extends EventEmitter {
+ constructor() {
+ super();
- onBeginUpdateBatch() {},
- onEndUpdateBatch() {},
+ this.skipTags = true;
+ this.skipDescendantsOnItemRemoval = true;
+ }
+
+ onBeginUpdateBatch() {}
+ onEndUpdateBatch() {}
onItemAdded(id, parentId, index, itemType, uri, title, dateAdded, guid, parentGuid, source) {
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
return;
}
let bookmark = {
id: guid,
@@ -102,33 +106,33 @@ let observer = {
if (itemType == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
bookmark.url = uri.spec;
} else {
bookmark.dateGroupModified = bookmark.dateAdded;
}
this.emit("created", bookmark);
- },
+ }
- onItemVisited() {},
+ onItemVisited() {}
onItemMoved(id, oldParentId, oldIndex, newParentId, newIndex, itemType, guid, oldParentGuid, newParentGuid, source) {
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
return;
}
let info = {
parentId: newParentGuid,
index: newIndex,
oldParentId: oldParentGuid,
oldIndex,
};
this.emit("moved", {guid, info});
- },
+ }
onItemRemoved(id, parentId, index, itemType, uri, guid, parentGuid, source) {
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
return;
}
let node = {
id: guid,
@@ -136,17 +140,17 @@ let observer = {
index,
};
if (itemType == PlacesUtils.bookmarks.TYPE_BOOKMARK) {
node.url = uri.spec;
}
this.emit("removed", {guid, info: {parentId: parentGuid, index, node}});
- },
+ }
onItemChanged(id, prop, isAnno, val, lastMod, itemType, parentId, guid, parentGuid, oldVal, source) {
if (itemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) {
return;
}
let info = {};
if (prop == "title") {
@@ -154,19 +158,18 @@ let observer = {
} else if (prop == "uri") {
info.url = val;
} else {
// Not defined yet.
return;
}
this.emit("changed", {guid, info});
- },
-};
-EventEmitter.decorate(observer);
+ }
+}();
const decrementListeners = () => {
listenerCount -= 1;
if (!listenerCount) {
PlacesUtils.bookmarks.removeObserver(observer);
}
};
--- a/browser/components/extensions/ext-browser.js
+++ b/browser/components/extensions/ext-browser.js
@@ -1,15 +1,14 @@
"use strict";
// The ext-* files are imported into the same scopes.
/* import-globals-from ext-utils.js */
-XPCOMUtils.defineLazyModuleGetter(global, "EventEmitter",
- "resource://gre/modules/EventEmitter.jsm");
+global.EventEmitter = ExtensionUtils.EventEmitter;
// This function is pretty tightly tied to Extension.jsm.
// Its job is to fill in the |tab| property of the sender.
const getSender = (extension, target, sender) => {
let tabId;
if ("tabId" in sender) {
// The message came from a privileged extension page running in a tab. In
// that case, it should include a tabId property (which is filled in by the
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -100,18 +100,16 @@ this.browserAction = class extends Exten
if (options.browser_style === null) {
this.extension.logger.warn("Please specify whether you want browser_style " +
"or not in your browser_action options.");
}
this.tabContext = new TabContext(tab => Object.create(this.defaults),
extension);
- EventEmitter.decorate(this);
-
this.build();
browserActionMap.set(extension, this);
}
onShutdown(reason) {
browserActionMap.delete(this.extension);
this.tabContext.shutdown();
--- a/browser/components/extensions/ext-c-devtools-panels.js
+++ b/browser/components/extensions/ext-c-devtools-panels.js
@@ -1,34 +1,32 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
// The ext-* files are imported into the same scopes.
/* import-globals-from ../../../toolkit/components/extensions/ext-c-toolkit.js */
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
- "resource://gre/modules/EventEmitter.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionChildDevToolsUtils",
"resource://gre/modules/ExtensionChildDevToolsUtils.jsm");
var {
promiseDocumentLoaded,
} = ExtensionUtils;
/**
* Represents an addon devtools panel in the child process.
*
* @param {DevtoolsExtensionContext}
* A devtools extension context running in a child process.
* @param {object} panelOptions
* @param {string} panelOptions.id
* The id of the addon devtools panel registered in the main process.
*/
-class ChildDevToolsPanel extends EventEmitter {
+class ChildDevToolsPanel extends ExtensionUtils.EventEmitter {
constructor(context, {id}) {
super();
this.context = context;
this.context.callOnClose(this);
this.id = id;
this._panelContext = null;
--- a/browser/components/extensions/ext-commands.js
+++ b/browser/components/extensions/ext-commands.js
@@ -20,17 +20,16 @@ this.commands = class extends ExtensionA
// Map[{String} commandName -> {Object} commandProperties]
this.commands = this.loadCommandsFromManifest(this.extension.manifest);
// WeakMap[Window -> <xul:keyset>]
this.keysetsMap = new WeakMap();
this.register();
- EventEmitter.decorate(this);
}
onShutdown(reason) {
this.unregister();
}
/**
* Registers the commands to all open windows and to any which
--- a/browser/components/extensions/ext-history.js
+++ b/browser/components/extensions/ext-history.js
@@ -87,47 +87,46 @@ const convertNavHistoryContainerResultNo
container.containerOpen = false;
return results;
};
var _observer;
const getHistoryObserver = () => {
if (!_observer) {
- _observer = {
- onDeleteURI: function(uri, guid, reason) {
+ _observer = new class extends EventEmitter {
+ onDeleteURI(uri, guid, reason) {
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
- },
- onVisit: function(uri, visitId, time, sessionId, referringId, transitionType, guid, hidden, visitCount, typed, lastKnownTitle) {
+ }
+ onVisit(uri, visitId, time, sessionId, referringId, transitionType, guid, hidden, visitCount, typed, lastKnownTitle) {
let data = {
id: guid,
url: uri.spec,
title: lastKnownTitle || "",
lastVisitTime: time / 1000, // time from Places is microseconds,
visitCount,
typedCount: typed,
};
this.emit("visited", data);
- },
- onBeginUpdateBatch: function() {},
- onEndUpdateBatch: function() {},
- onTitleChanged: function(uri, title) {
+ }
+ onBeginUpdateBatch() {}
+ onEndUpdateBatch() {}
+ onTitleChanged(uri, title) {
this.emit("titleChanged", {url: uri.spec, title: title});
- },
- onClearHistory: function() {
+ }
+ onClearHistory() {
this.emit("visitRemoved", {allHistory: true, urls: []});
- },
- onPageChanged: function() {},
- onFrecencyChanged: function() {},
- onManyFrecenciesChanged: function() {},
- onDeleteVisits: function(uri, time, guid, reason) {
+ }
+ onPageChanged() {}
+ onFrecencyChanged() {}
+ onManyFrecenciesChanged() {}
+ onDeleteVisits(uri, time, guid, reason) {
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
- },
- };
- EventEmitter.decorate(_observer);
+ }
+ }();
PlacesUtils.history.addObserver(_observer);
}
return _observer;
};
this.history = class extends ExtensionAPI {
getAPI(context) {
return {
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -58,18 +58,16 @@ this.pageAction = class extends Extensio
this.tabContext = new TabContext(tab => Object.create(this.defaults),
extension);
this.tabContext.on("location-change", this.handleLocationChange.bind(this)); // eslint-disable-line mozilla/balanced-listeners
// WeakMap[ChromeWindow -> <xul:image>]
this.buttons = new WeakMap();
- EventEmitter.decorate(this);
-
pageActionMap.set(extension, this);
}
onShutdown(reason) {
pageActionMap.delete(this.extension);
this.tabContext.shutdown();
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -27,74 +27,74 @@ let windowTracker;
global.makeWidgetId = id => {
id = id.toLowerCase();
// FIXME: This allows for collisions.
return id.replace(/[^a-z0-9_-]/g, "_");
};
// Manages tab-specific context data, and dispatching tab select events
// across all windows.
-global.TabContext = function TabContext(getDefaults, extension) {
- this.extension = extension;
- this.getDefaults = getDefaults;
+global.TabContext = class extends EventEmitter {
+ constructor(getDefaults, extension) {
+ super();
- this.tabData = new WeakMap();
- this.lastLocation = new WeakMap();
+ this.extension = extension;
+ this.getDefaults = getDefaults;
- windowTracker.addListener("progress", this);
- windowTracker.addListener("TabSelect", this);
+ this.tabData = new WeakMap();
+ this.lastLocation = new WeakMap();
- EventEmitter.decorate(this);
-};
+ windowTracker.addListener("progress", this);
+ windowTracker.addListener("TabSelect", this);
+ }
-TabContext.prototype = {
get(nativeTab) {
if (!this.tabData.has(nativeTab)) {
this.tabData.set(nativeTab, this.getDefaults(nativeTab));
}
return this.tabData.get(nativeTab);
- },
+ }
clear(nativeTab) {
this.tabData.delete(nativeTab);
- },
+ }
handleEvent(event) {
if (event.type == "TabSelect") {
let nativeTab = event.target;
this.emit("tab-select", nativeTab);
this.emit("location-change", nativeTab);
}
- },
+ }
onStateChange(browser, webProgress, request, stateFlags, statusCode) {
let flags = Ci.nsIWebProgressListener;
if (!(~stateFlags & (flags.STATE_IS_WINDOW | flags.STATE_START) ||
this.lastLocation.has(browser))) {
this.lastLocation.set(browser, request.URI);
}
- },
+ }
onLocationChange(browser, webProgress, request, locationURI, flags) {
let gBrowser = browser.ownerGlobal.gBrowser;
let lastLocation = this.lastLocation.get(browser);
if (browser === gBrowser.selectedBrowser &&
!(lastLocation && lastLocation.equalsExceptRef(browser.currentURI))) {
let nativeTab = gBrowser.getTabForBrowser(browser);
this.emit("location-change", nativeTab, true);
}
this.lastLocation.set(browser, browser.currentURI);
- },
+ }
shutdown() {
windowTracker.removeListener("progress", this);
windowTracker.removeListener("TabSelect", this);
- },
+ }
};
class WindowTracker extends WindowTrackerBase {
addProgressListener(window, listener) {
window.gBrowser.addTabsProgressListener(listener);
}
--- a/toolkit/components/extensions/ExtensionAPI.jsm
+++ b/toolkit/components/extensions/ExtensionAPI.jsm
@@ -13,20 +13,24 @@ const {classes: Cc, interfaces: Ci, util
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI",
"resource://gre/modules/Console.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
"resource://gre/modules/Schemas.jsm");
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+
const global = this;
-class ExtensionAPI {
+class ExtensionAPI extends ExtensionUtils.EventEmitter {
constructor(extension) {
+ super();
+
this.extension = extension;
extension.once("shutdown", () => {
if (this.onShutdown) {
this.onShutdown(extension.shutdownReason);
}
this.extension = null;
});
--- a/toolkit/components/extensions/ext-downloads.js
+++ b/toolkit/components/extensions/ext-downloads.js
@@ -8,20 +8,19 @@ XPCOMUtils.defineLazyModuleGetter(this,
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
"resource://gre/modules/DownloadPaths.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
- "resource://gre/modules/EventEmitter.jsm");
var {
+ EventEmitter,
normalizeTime,
} = ExtensionUtils;
var {
ignoreEvent,
} = ExtensionCommon;
const DOWNLOAD_ITEM_FIELDS = ["id", "url", "referrer", "filename", "incognito",
@@ -137,29 +136,32 @@ class DownloadItem {
}
}
}
// DownloadMap maps back and forth betwen the numeric identifiers used in
// the downloads WebExtension API and a Download object from the Downloads jsm.
// todo: make id and extension info persistent (bug 1247794)
-const DownloadMap = {
- currentId: 0,
- loadPromise: null,
+const DownloadMap = new class extends EventEmitter {
+ constructor() {
+ super();
+
+ this.currentId = 0;
+ this.loadPromise = null;
- // Maps numeric id -> DownloadItem
- byId: new Map(),
+ // Maps numeric id -> DownloadItem
+ this.byId = new Map();
- // Maps Download object -> DownloadItem
- byDownload: new WeakMap(),
+ // Maps Download object -> DownloadItem
+ this.byDownload = new WeakMap();
+ }
lazyInit() {
if (this.loadPromise == null) {
- EventEmitter.decorate(this);
this.loadPromise = Downloads.getList(Downloads.ALL).then(list => {
let self = this;
return list.addView({
onDownloadAdded(download) {
const item = self.newFromDownload(download, null);
self.emit("create", item);
item._storePrechange();
},
@@ -187,54 +189,54 @@ const DownloadMap = {
downloads.forEach(download => {
this.newFromDownload(download, null);
});
})
.then(() => list);
});
}
return this.loadPromise;
- },
+ }
getDownloadList() {
return this.lazyInit();
- },
+ }
getAll() {
return this.lazyInit().then(() => this.byId.values());
- },
+ }
fromId(id) {
const download = this.byId.get(id);
if (!download) {
throw new Error(`Invalid download id ${id}`);
}
return download;
- },
+ }
newFromDownload(download, extension) {
if (this.byDownload.has(download)) {
return this.byDownload.get(download);
}
const id = ++this.currentId;
let item = new DownloadItem(id, download, extension);
this.byId.set(id, item);
this.byDownload.set(download, item);
return item;
- },
+ }
erase(item) {
// This will need to get more complicated for bug 1255507 but for now we
// only work with downloads in the DownloadList from getAll()
return this.getDownloadList().then(list => {
list.remove(item.download);
});
- },
-};
+ }
+}();
// Create a callable function that filters a DownloadItem based on a
// query object of the type passed to search() or erase().
const downloadQuery = query => {
let queryTerms = [];
let queryNegativeTerms = [];
if (query.query != null) {
for (let term of query.query) {
--- a/toolkit/components/extensions/ext-idle.js
+++ b/toolkit/components/extensions/ext-idle.js
@@ -1,15 +1,13 @@
"use strict";
// The ext-* files are imported into the same scopes.
/* import-globals-from ext-toolkit.js */
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
- "resource://gre/modules/EventEmitter.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "idleService",
"@mozilla.org/widget/idleservice;1",
"nsIIdleService");
// WeakMap[Extension -> Object]
let observersMap = new WeakMap();
const getIdleObserverInfo = (extension, context) => {
@@ -32,24 +30,23 @@ const getIdleObserverInfo = (extension,
}
return observerInfo;
};
const getIdleObserver = (extension, context) => {
let observerInfo = getIdleObserverInfo(extension, context);
let {observer, detectionInterval} = observerInfo;
if (!observer) {
- observer = {
- observe: function(subject, topic, data) {
+ observer = new class extends ExtensionUtils.EventEmitter {
+ observe(subject, topic, data) {
if (topic == "idle" || topic == "active") {
this.emit("stateChanged", topic);
}
- },
- };
- EventEmitter.decorate(observer);
+ }
+ }();
idleService.addIdleObserver(observer, detectionInterval);
observerInfo.observer = observer;
observerInfo.detectionInterval = detectionInterval;
}
return observer;
};
const setDetectionInterval = (extension, context, newInterval) => {
--- a/toolkit/components/extensions/ext-management.js
+++ b/toolkit/components/extensions/ext-management.js
@@ -9,18 +9,16 @@ XPCOMUtils.defineLazyGetter(this, "strBu
const stringSvc = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
return stringSvc.createBundle("chrome://global/locale/extensions.properties");
});
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "promptService",
"@mozilla.org/embedcomp/prompt-service;1",
"nsIPromptService");
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
- "resource://gre/modules/EventEmitter.jsm");
XPCOMUtils.defineLazyGetter(this, "GlobalManager", () => {
const {GlobalManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
return GlobalManager;
});
var {
ExtensionError,
@@ -86,20 +84,19 @@ const getExtensionInfoForAddon = (extens
}
return extInfo;
};
const listenerMap = new WeakMap();
// Some management APIs are intentionally limited.
const allowedTypes = ["theme", "extension"];
-class AddonListener {
+class AddonListener extends ExtensionUtils.EventEmitter {
constructor() {
AddonManager.addAddonListener(this);
- EventEmitter.decorate(this);
}
release() {
AddonManager.removeAddonListener(this);
}
getExtensionInfo(addon) {
let ext = addon.isWebExtension && GlobalManager.extensionMap.get(addon.id);
--- a/toolkit/components/extensions/ext-notifications.js
+++ b/toolkit/components/extensions/ext-notifications.js
@@ -1,14 +1,16 @@
"use strict";
// The ext-* files are imported into the same scopes.
/* import-globals-from ext-toolkit.js */
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
+const ToolkitModules = {};
+
+XPCOMUtils.defineLazyModuleGetter(ToolkitModules, "EventEmitter",
"resource://gre/modules/EventEmitter.jsm");
var {
ignoreEvent,
} = ExtensionCommon;
// WeakMap[Extension -> Map[id -> Notification]]
let notificationsMap = new WeakMap();
@@ -93,17 +95,17 @@ this.notifications = class extends Exten
notificationsMap.delete(extension);
}
}
getAPI(context) {
let {extension} = context;
let map = new Map();
- EventEmitter.decorate(map);
+ ToolkitModules.EventEmitter.decorate(map);
notificationsMap.set(extension, map);
return {
notifications: {
create: (notificationId, options) => {
if (!notificationId) {
notificationId = String(this.nextId++);
}