Bug 803067 - EventEmitter should have a decorator that isn't called 'new'. r=paul
authorYura Zenevich <yura.zenevich>
Fri, 14 Dec 2012 08:05:00 +0100
changeset 125534 c7c3914d612797c6acee4c08fb822e46a9213e4f
parent 125533 e64c17c9baffc4cf723c5bc8e681983ba4778042
child 125535 a5793af7e70c262a8d00b82e3e38642516f5406f
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspaul
bugs803067
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 803067 - EventEmitter should have a decorator that isn't called 'new'. r=paul
browser/devtools/debugger/DebuggerPanel.jsm
browser/devtools/framework/Sidebar.jsm
browser/devtools/framework/Target.jsm
browser/devtools/framework/Toolbox.jsm
browser/devtools/framework/ToolboxHosts.jsm
browser/devtools/framework/gDevTools.jsm
browser/devtools/framework/test/browser_devtools_api.js
browser/devtools/inspector/Highlighter.jsm
browser/devtools/inspector/InspectorPanel.jsm
browser/devtools/inspector/Selection.jsm
browser/devtools/profiler/ProfilerPanel.jsm
browser/devtools/responsivedesign/responsivedesign.jsm
browser/devtools/responsivedesign/test/browser_responsiveui.js
browser/devtools/shared/EventEmitter.jsm
browser/devtools/shared/test/browser_eventemitter_basic.js
browser/devtools/styleeditor/StyleEditorPanel.jsm
browser/devtools/webconsole/WebConsolePanel.jsm
--- a/browser/devtools/debugger/DebuggerPanel.jsm
+++ b/browser/devtools/debugger/DebuggerPanel.jsm
@@ -20,17 +20,17 @@ function DebuggerPanel(iframeWindow, too
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
 
   this._controller = this.panelWin.DebuggerController;
   this._view = this.panelWin.DebuggerView;
   this._controller._target = this.target;
   this._bkp = this._controller.Breakpoints;
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 }
 
 DebuggerPanel.prototype = {
   /**
    * open is effectively an asynchronous constructor
    */
   open: function DebuggerPanel_open() {
     let deferred = Promise.defer();
--- a/browser/devtools/framework/Sidebar.jsm
+++ b/browser/devtools/framework/Sidebar.jsm
@@ -21,17 +21,17 @@ const XULNS = "http://www.mozilla.org/ke
  *  <tabbox> node;
  * @param {ToolPanel} panel
  *  Related ToolPanel instance;
  * @param {Boolean} showTabstripe
  *  Show the tabs.
  */
 this.ToolSidebar = function ToolSidebar(tabbox, panel, showTabstripe=true)
 {
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 
   this._tabbox = tabbox;
   this._panelDoc = this._tabbox.ownerDocument;
   this._toolPanel = panel;
 
   this._tabbox.tabpanels.addEventListener("select", this, true);
 
   this._tabs = new Map();
--- a/browser/devtools/framework/Target.jsm
+++ b/browser/devtools/framework/Target.jsm
@@ -165,17 +165,17 @@ Object.defineProperty(Target.prototype, 
 });
 
 
 /**
  * A TabTarget represents a page living in a browser tab. Generally these will
  * be web pages served over http(s), but they don't have to be.
  */
 function TabTarget(tab) {
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
   this._tab = tab;
   this._setupListeners();
 }
 
 TabTarget.prototype = {
   _webProgressListener: null,
 
   supports: supports,
@@ -304,17 +304,17 @@ TabWebProgressListener.prototype = {
 };
 
 
 /**
  * A WindowTarget represents a page living in a xul window or panel. Generally
  * these will have a chrome: URL
  */
 function WindowTarget(window) {
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
   this._window = window;
 }
 
 WindowTarget.prototype = {
   supports: supports,
   get version() { return getVersion(); },
 
   get window() {
@@ -357,17 +357,17 @@ WindowTarget.prototype = {
     return 'WindowTarget:' + this.window;
   },
 };
 
 /**
  * A RemoteTarget represents a page living in a remote Firefox instance.
  */
 function RemoteTarget(form, client, chrome) {
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
   this._client = client;
   this._form = form;
   this._chrome = chrome;
 
   this.destroy = this.destroy.bind(this);
   this.client.addListener("tabDetached", this.destroy);
 
   this._onTabNavigated = function onRemoteTabNavigated() {
--- a/browser/devtools/framework/Toolbox.jsm
+++ b/browser/devtools/framework/Toolbox.jsm
@@ -122,17 +122,17 @@ this.Toolbox = function Toolbox(target, 
   let definitions = gDevTools.getToolDefinitions();
   if (!definitions.get(selectedTool)) {
     selectedTool = "webconsole";
   }
   this._defaultToolId = selectedTool;
 
   this._host = this._createHost(hostType);
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 
   gDevTools.on("tool-registered", this._toolRegistered);
   gDevTools.on("tool-unregistered", this._toolUnregistered);
 }
 
 /**
  * The toolbox can be 'hosted' either embedded in a browser window
  * or in a separate window.
--- a/browser/devtools/framework/ToolboxHosts.jsm
+++ b/browser/devtools/framework/ToolboxHosts.jsm
@@ -28,17 +28,17 @@ this.Hosts = {
 }
 
 /**
  * Host object for the dock on the bottom of the browser
  */
 function BottomHost(hostTab) {
   this.hostTab = hostTab;
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 }
 
 BottomHost.prototype = {
   type: "bottom",
 
   heightPref: "devtools.toolbox.footer.height",
 
   /**
@@ -96,17 +96,17 @@ BottomHost.prototype = {
 
 
 /**
  * Host object for the in-browser sidebar
  */
 function SidebarHost(hostTab) {
   this.hostTab = hostTab;
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 }
 
 SidebarHost.prototype = {
   type: "side",
 
   widthPref: "devtools.toolbox.sidebar.width",
 
   /**
@@ -161,17 +161,17 @@ SidebarHost.prototype = {
 }
 
 /**
  * Host object for the toolbox in a separate window
  */
 function WindowHost() {
   this._boundUnload = this._boundUnload.bind(this);
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 }
 
 WindowHost.prototype = {
   type: "window",
 
   WINDOW_URL: "chrome://browser/content/devtools/framework/toolbox-window.xul",
 
   /**
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -26,17 +26,17 @@ const FORBIDDEN_IDS = new Set("toolbox",
  */
 this.DevTools = function DevTools() {
   this._tools = new Map();
   this._toolboxes = new Map();
 
   // destroy() is an observer's handler so we need to preserve context.
   this.destroy = this.destroy.bind(this);
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 
   Services.obs.addObserver(this.destroy, "quit-application", false);
 
   // Register the set of default tools
   for (let definition of defaultTools) {
     this.registerTool(definition);
   }
 }
--- a/browser/devtools/framework/test/browser_devtools_api.js
+++ b/browser/devtools/framework/test/browser_devtools_api.js
@@ -80,17 +80,17 @@ function finishUp() {
 * When a Toolbox is started it creates a DevToolPanel for each of the tools
 * by calling toolDefinition.build(). The returned object should
 * at least implement these functions. They will be used by the ToolBox.
 *
 * There may be no benefit in doing this as an abstract type, but if nothing
 * else gives us a place to write documentation.
 */
 function DevToolPanel(iframeWindow, toolbox) {
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 
   this._toolbox = toolbox;
 
   /*let doc = iframeWindow.document
   let label = doc.createElement("label");
   let textNode = doc.createTextNode("Some Tool");
 
   label.appendChild(textNode);
--- a/browser/devtools/inspector/Highlighter.jsm
+++ b/browser/devtools/inspector/Highlighter.jsm
@@ -79,17 +79,17 @@ this.Highlighter = function Highlighter(
   this.target = aTarget;
   this.tab = aTarget.tab;
   this.toolbox = aToolbox;
   this.browser = this.tab.linkedBrowser;
   this.chromeDoc = this.tab.ownerDocument;
   this.chromeWin = this.chromeDoc.defaultView;
   this.inspector = aInspector
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 
   this._init();
 }
 
 Highlighter.prototype = {
   get selection() {
     return this.inspector.selection;
   },
--- a/browser/devtools/inspector/InspectorPanel.jsm
+++ b/browser/devtools/inspector/InspectorPanel.jsm
@@ -37,17 +37,17 @@ this.InspectorPanel = function Inspector
   this._target = toolbox._target;
   this.panelDoc = iframeWindow.document;
   this.panelWin = iframeWindow;
   this.panelWin.inspector = this;
 
   this.tabTarget = (this.target.tab != null);
   this.winTarget = (this.target.window != null);
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 }
 
 InspectorPanel.prototype = {
   /**
    * open is effectively an asynchronous constructor
    */
   open: function InspectorPanel_open() {
     let deferred = Promise.defer();
--- a/browser/devtools/inspector/Selection.jsm
+++ b/browser/devtools/inspector/Selection.jsm
@@ -53,17 +53,17 @@ this.EXPORTED_SYMBOLS = ["Selection"];
  *
  * @param node Inner node.
  *    Can be null. Can be (un)set in the future via the "node" property;
  * @param trackAttribute Tell if events should be fired when the attributes of
  *    the ndoe change.
  *
  */
 this.Selection = function Selection(node=null, track={attributes:true,detached:true}) {
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
   this._onMutations = this._onMutations.bind(this);
   this.track = track;
   this.setNode(node);
 }
 
 Selection.prototype = {
   _node: null,
 
--- a/browser/devtools/profiler/ProfilerPanel.jsm
+++ b/browser/devtools/profiler/ProfilerPanel.jsm
@@ -35,17 +35,17 @@ XPCOMUtils.defineLazyGetter(this, "Debug
  *   Unique ID for this profile.
  * @param ProfilerPanel panel
  *   A reference to the container panel.
  */
 function ProfileUI(uid, panel) {
   let doc = panel.document;
   let win = panel.window;
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 
   this.isReady = false;
   this.panel = panel;
   this.uid = uid;
 
   this.iframe = doc.createElement("iframe");
   this.iframe.setAttribute("flex", "1");
   this.iframe.setAttribute("id", "profiler-cleo-" + uid);
@@ -178,17 +178,17 @@ function ProfilerPanel(frame, toolbox) {
   this.window = frame.window;
   this.document = frame.document;
   this.target = toolbox.target;
   this.controller = new ProfilerController();
 
   this.profiles = new Map();
   this._uid = 0;
 
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 }
 
 ProfilerPanel.prototype = {
   isReady:    null,
   window:     null,
   document:   null,
   target:     null,
   controller: null,
@@ -385,9 +385,9 @@ ProfilerPanel.prototype = {
     this.target = null;
     this.controller = null;
     this.profiles = null;
     this._uid = null;
     this._activeUid = null;
 
     this.emit("destroyed");
   }
-};
\ No newline at end of file
+};
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -64,25 +64,20 @@ this.ResponsiveUIManager = {
         if (aTab.__responsiveUI) {
           aTab.__responsiveUI.close();
         }
         break;
       case "resize toggle":
           this.toggle(aWindow, aTab);
       default:
     }
-  },
+  }
+}
 
-  get events() {
-    if (!this._eventEmitter) {
-      this._eventEmitter = new EventEmitter();
-    }
-    return this._eventEmitter;
-  },
-}
+EventEmitter.decorate(ResponsiveUIManager);
 
 let presets = [
   // Phones
   {key: "320x480", width: 320, height: 480},    // iPhone, B2G, with <meta viewport>
   {key: "360x640", width: 360, height: 640},    // Android 4, phones, with <meta viewport>
 
   // Tablets
   {key: "768x1024", width: 768, height: 1024},   // iPad, with <meta viewport>
@@ -170,17 +165,17 @@ function ResponsiveUI(aWindow, aTab)
     if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
       this.rotate();
     }
   } catch(e) {}
 
   if (this._floatingScrollbars)
     switchToFloatingScrollbars(this.tab);
 
-  ResponsiveUIManager.events.emit("on", this.tab, this);
+  ResponsiveUIManager.emit("on", this.tab, this);
 }
 
 ResponsiveUI.prototype = {
   _transitionsEnabled: true,
   _floatingScrollbars: false, // See bug 799471
   get transitionsEnabled() this._transitionsEnabled,
   set transitionsEnabled(aValue) {
     this._transitionsEnabled = aValue;
@@ -227,17 +222,17 @@ ResponsiveUI.prototype = {
     this.stack.removeChild(this.resizer);
     this.stack.removeChild(this.resizeBar);
 
     // Unset the responsive mode.
     this.container.removeAttribute("responsivemode");
     this.stack.removeAttribute("responsivemode");
 
     delete this.tab.__responsiveUI;
-    ResponsiveUIManager.events.emit("off", this.tab, this);
+    ResponsiveUIManager.emit("off", this.tab, this);
   },
 
   /**
    * Handle keypressed.
    *
    * @param aEvent
    */
   onKeypress: function RUI_onKeypress(aEvent) {
--- a/browser/devtools/responsivedesign/test/browser_responsiveui.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveui.js
@@ -1,28 +1,28 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let instance, widthBeforeClose, heightBeforeClose;
-  let events = ResponsiveUI.ResponsiveUIManager.events;
+  let mgr = ResponsiveUI.ResponsiveUIManager;
 
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
     waitForFocus(startTest, content);
   }, true);
 
   content.location = "data:text/html,mop";
 
   function startTest() {
     document.getElementById("Tools:ResponsiveUI").removeAttribute("disabled");
-    events.once("on", function() {executeSoon(onUIOpen)});
+    mgr.once("on", function() {executeSoon(onUIOpen)});
     synthesizeKeyFromKeyTag("key_responsiveUI");
   }
 
   function onUIOpen() {
     // Is it open?
     let container = gBrowser.getBrowserContainer();
     is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
 
@@ -116,36 +116,36 @@ function test() {
     is(content.innerHeight, initialWidth, "The height is now the width.");
     let [width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
     is(width, initialHeight, "Label updated (width).");
     is(height, initialWidth, "Label updated (height).");
 
     widthBeforeClose = content.innerWidth;
     heightBeforeClose = content.innerHeight;
 
-    events.once("off", function() {executeSoon(restart)});
+    mgr.once("off", function() {executeSoon(restart)});
     EventUtils.synthesizeKey("VK_ESCAPE", {});
   }
 
   function restart() {
-    events.once("on", function() {executeSoon(onUIOpen2)});
+    mgr.once("on", function() {executeSoon(onUIOpen2)});
     synthesizeKeyFromKeyTag("key_responsiveUI");
   }
 
   function onUIOpen2() {
     let container = gBrowser.getBrowserContainer();
     is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
 
     // Menus are correctly updated?
     is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
 
     is(content.innerWidth, widthBeforeClose, "width restored.");
     is(content.innerHeight, heightBeforeClose, "height restored.");
 
-    events.once("off", function() {executeSoon(finishUp)});
+    mgr.once("off", function() {executeSoon(finishUp)});
     EventUtils.synthesizeKey("VK_ESCAPE", {});
   }
 
   function finishUp() {
 
     // Menus are correctly updated?
     is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "false", "menu unchecked");
 
--- a/browser/devtools/shared/EventEmitter.jsm
+++ b/browser/devtools/shared/EventEmitter.jsm
@@ -1,29 +1,33 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 this.EXPORTED_SYMBOLS = ["EventEmitter"];
 
 /**
  * EventEmitter.
- *
- * @param Object aObjectToExtend
- *        If aObjectToExtend is not null, the public methods of EventEmitter
- *        are bound to the object.
  */
-this.EventEmitter = function EventEmitter(aObjectToExtend) {
-  if (aObjectToExtend) {
-    aObjectToExtend.on = this.on.bind(this);
-    aObjectToExtend.off = this.off.bind(this);
-    aObjectToExtend.once = this.once.bind(this);
-    aObjectToExtend.emit = this.emit.bind(this);
-  }
-}
+this.EventEmitter = function EventEmitter() {};
+
+/**
+ * Decorate an object with event emitter functionality.
+ *
+ * @param Object aObjectToDecorate
+ *        Bind all public methods of EventEmitter to
+ *        the aObjectToDecorate object.
+ */
+EventEmitter.decorate = function EventEmitter_decorate (aObjectToDecorate) {
+  let emitter = new EventEmitter();
+  aObjectToDecorate.on = emitter.on.bind(emitter);
+  aObjectToDecorate.off = emitter.off.bind(emitter);
+  aObjectToDecorate.once = emitter.once.bind(emitter);
+  aObjectToDecorate.emit = emitter.emit.bind(emitter);
+};
 
 EventEmitter.prototype = {
   /**
    * Connect a listener.
    *
    * @param string aEvent
    *        The event name to which we're connecting.
    * @param function aListener
@@ -98,10 +102,10 @@ EventEmitter.prototype = {
         catch (ex) {
           // Prevent a bad listener from interfering with the others.
           let msg = ex + ": " + ex.stack;
           Components.utils.reportError(msg);
           dump(msg + "\n");
         }
       }
     }
-  },
-}
+  }
+};
--- a/browser/devtools/shared/test/browser_eventemitter_basic.js
+++ b/browser/devtools/shared/test/browser_eventemitter_basic.js
@@ -9,17 +9,17 @@ function test() {
 
 function testEmitter(aObject) {
   Cu.import("resource:///modules/devtools/EventEmitter.jsm", this);
 
   let emitter;
 
   if (aObject) {
     emitter = aObject;
-    new EventEmitter(emitter);
+    EventEmitter.decorate(emitter);
   } else {
     emitter = new EventEmitter();
   }
 
   ok(emitter, "We have an event emitter");
 
   emitter.on("next", next);
   emitter.emit("next", "abc", "def");
--- a/browser/devtools/styleeditor/StyleEditorPanel.jsm
+++ b/browser/devtools/styleeditor/StyleEditorPanel.jsm
@@ -11,17 +11,17 @@ this.EXPORTED_SYMBOLS = ["StyleEditorPan
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/commonjs/promise/core.js");
 Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "StyleEditorChrome",
                         "resource:///modules/devtools/StyleEditorChrome.jsm");
 
 this.StyleEditorPanel = function StyleEditorPanel(panelWin, toolbox) {
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 
   this._toolbox = toolbox;
   this._target = toolbox.target;
 
   this.reset = this.reset.bind(this);
   this.newPage = this.newPage.bind(this);
   this.destroy = this.destroy.bind(this);
 
--- a/browser/devtools/webconsole/WebConsolePanel.jsm
+++ b/browser/devtools/webconsole/WebConsolePanel.jsm
@@ -17,17 +17,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource:///modules/HUDService.jsm");
 
 /**
  * A DevToolPanel that controls the Web Console.
  */
 function WebConsolePanel(iframeWindow, toolbox) {
   this._frameWindow = iframeWindow;
   this._toolbox = toolbox;
-  new EventEmitter(this);
+  EventEmitter.decorate(this);
 }
 
 WebConsolePanel.prototype = {
   /**
    * open is effectively an asynchronous constructor
    */
   open: function StyleEditor_open() {
     let tab = this._toolbox._getHostTab();