Bug 1356231 - Remove boilerplate r=Mossop draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Tue, 25 Apr 2017 17:42:34 +0200
changeset 568522 2786b18b1aae108b37d89b9b262a8265137d21a4
parent 568521 a15053d74aaf82074e00674b0469228f7cd6d1fa
child 568523 a032f5220aac08263b1006249060b46814069262
push id55886
push userbmo:poirot.alex@gmail.com
push dateWed, 26 Apr 2017 08:10:38 +0000
reviewersMossop
bugs1356231
milestone55.0a1
Bug 1356231 - Remove boilerplate r=Mossop MozReview-Commit-ID: 8QEQeYvtObf
toolkit/modules/EventEmitter.jsm
--- a/toolkit/modules/EventEmitter.jsm
+++ b/toolkit/modules/EventEmitter.jsm
@@ -1,266 +1,210 @@
 /* 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/. */
 
 "use strict";
 
-// module, require are exposed when loaded as a CommonJS module
-// isWorker is exposed when loaded as a DevTools module
-/* globals module, isWorker */
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "console",
+                                  "resource://gre/modules/Console.jsm");
+
+this.EXPORTED_SYMBOLS = ["EventEmitter"];
+
+let EventEmitter = this.EventEmitter = function() {};
+
+let loggingEnabled = Services.prefs.getBoolPref("toolkit.dump.emit");
+Services.prefs.addObserver("toolkit.dump.emit", {
+  observe: () => {
+    loggingEnabled = Services.prefs.getBoolPref("toolkit.dump.emit");
+  }
+});
 
-(function(factory) {
-  // This file can be loaded in several different ways.  It can be
-  // require()d, either from the main thread or from a worker thread;
-  // or it can be imported via Cu.import.  These different forms
-  // explain some of the hairiness of this code.
-  //
-  // It's important for the devtools-as-html project that a require()
-  // on the main thread not use any chrome privileged APIs.  Instead,
-  // the body of the main function can only require() (not Cu.import)
-  // modules that are available in the devtools content mode.  This,
-  // plus the lack of |console| in workers, results in some gyrations
-  // in the definition of |console|.
-  if (this.module && module.id.indexOf("event-emitter") >= 0) {
-    let console;
-    if (isWorker) {
-      console = {
-        error: () => {}
-      };
-    } else {
-      console = this.console;
-    }
-    // require
-    factory.call(this, require, exports, module, console);
-  } else {
-    // Cu.import.  This snippet implements a sort of miniature loader,
-    // which is responsible for appropriately translating require()
-    // requests from the client function.  This code can use
-    // Cu.import, because it is never run in the devtools-in-content
-    // mode.
-    this.isWorker = false;
-    const Cu = Components.utils;
-    let console = Cu.import("resource://gre/modules/Console.jsm", {}).console;
-    // Bug 1259045: This module is loaded early in firefox startup as a JSM,
-    // but it doesn't depends on any real module. We can save a few cycles
-    // and bytes by not loading Loader.jsm.
-    let require = function(module) {
-      switch (module) {
-        case "Services":
-          return Cu.import("resource://gre/modules/Services.jsm", {}).Services;
-        case "devtools/shared/platform/stack": {
-          let obj = {};
-          Cu.import("resource://devtools/shared/platform/chrome/stack.js", obj);
-          return obj;
-        }
-      }
-      return null;
-    };
-    factory.call(this, require, this, { exports: this }, console);
-    this.EXPORTED_SYMBOLS = ["EventEmitter"];
-  }
-}).call(this, function(require, exports, module, console) {
-  // ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
-  // After this point the code may not use Cu.import, and should only
-  // require() modules that are "clean-for-content".
-  let EventEmitter = this.EventEmitter = function() {};
-  module.exports = EventEmitter;
+/**
+ * Decorate an object with event emitter functionality.
+ *
+ * @param Object objectToDecorate
+ *        Bind all public methods of EventEmitter to
+ *        the objectToDecorate object.
+ */
+EventEmitter.decorate = function(objectToDecorate) {
+  let emitter = new EventEmitter();
+  objectToDecorate.on = emitter.on.bind(emitter);
+  objectToDecorate.off = emitter.off.bind(emitter);
+  objectToDecorate.once = emitter.once.bind(emitter);
+  objectToDecorate.emit = emitter.emit.bind(emitter);
+};
 
-  // See comment in JSM module boilerplate when adding a new dependency.
-  const Services = require("Services");
-  let loggingEnabled = true;
-
-  if (!isWorker) {
-    loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
-    Services.prefs.addObserver("devtools.dump.emit", {
-      observe: () => {
-        loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
-      }
-    });
-  }
-
-  /**
-   * Decorate an object with event emitter functionality.
-   *
-   * @param Object objectToDecorate
-   *        Bind all public methods of EventEmitter to
-   *        the objectToDecorate object.
-   */
-  EventEmitter.decorate = function(objectToDecorate) {
-    let emitter = new EventEmitter();
-    objectToDecorate.on = emitter.on.bind(emitter);
-    objectToDecorate.off = emitter.off.bind(emitter);
-    objectToDecorate.once = emitter.once.bind(emitter);
-    objectToDecorate.emit = emitter.emit.bind(emitter);
-  };
-
-  function describeNthCaller(n) {
-    let caller = Components.stack;
-    // Do one extra iteration to skip this function.
-    while (n >= 0) {
-      --n;
-      caller = caller.caller;
-    }
-
-    let func = caller.name;
-    let file = caller.filename;
-    if (file.includes(" -> ")) {
-      file = caller.filename.split(/ -> /)[1];
-    }
-    let path = file + ":" + caller.lineNumber;
-
-    return func + "() -> " + path;
+function describeNthCaller(n) {
+  let caller = Components.stack;
+  // Do one extra iteration to skip this function.
+  while (n >= 0) {
+    --n;
+    caller = caller.caller;
   }
 
-  EventEmitter.prototype = {
-    /**
-     * Connect a listener.
-     *
-     * @param string event
-     *        The event name to which we're connecting.
-     * @param function listener
-     *        Called when the event is fired.
-     */
-    on(event, listener) {
-      if (!this._eventEmitterListeners) {
-        this._eventEmitterListeners = new Map();
-      }
-      if (!this._eventEmitterListeners.has(event)) {
-        this._eventEmitterListeners.set(event, []);
-      }
-      this._eventEmitterListeners.get(event).push(listener);
-    },
+  let func = caller.name;
+  let file = caller.filename;
+  if (file.includes(" -> ")) {
+    file = caller.filename.split(/ -> /)[1];
+  }
+  let path = file + ":" + caller.lineNumber;
+
+  return func + "() -> " + path;
+}
+
+EventEmitter.prototype = {
+  /**
+   * Connect a listener.
+   *
+   * @param string event
+   *        The event name to which we're connecting.
+   * @param function listener
+   *        Called when the event is fired.
+   */
+  on(event, listener) {
+    if (!this._eventEmitterListeners) {
+      this._eventEmitterListeners = new Map();
+    }
+    if (!this._eventEmitterListeners.has(event)) {
+      this._eventEmitterListeners.set(event, []);
+    }
+    this._eventEmitterListeners.get(event).push(listener);
+  },
 
-    /**
-     * Listen for the next time an event is fired.
-     *
-     * @param string event
-     *        The event name to which we're connecting.
-     * @param function listener
-     *        (Optional) Called when the event is fired. Will be called at most
-     *        one time.
-     * @return promise
-     *        A promise which is resolved when the event next happens. The
-     *        resolution value of the promise is the first event argument. If
-     *        you need access to second or subsequent event arguments (it's rare
-     *        that this is needed) then use listener
-     */
-    once(event, listener) {
-      return new Promise(resolve => {
-        let handler = (_, first, ...rest) => {
-          this.off(event, handler);
-          if (listener) {
-            listener(event, first, ...rest);
-          }
-          resolve(first);
-        };
+  /**
+   * Listen for the next time an event is fired.
+   *
+   * @param string event
+   *        The event name to which we're connecting.
+   * @param function listener
+   *        (Optional) Called when the event is fired. Will be called at most
+   *        one time.
+   * @return promise
+   *        A promise which is resolved when the event next happens. The
+   *        resolution value of the promise is the first event argument. If
+   *        you need access to second or subsequent event arguments (it's rare
+   *        that this is needed) then use listener
+   */
+  once(event, listener) {
+    return new Promise(resolve => {
+      let handler = (_, first, ...rest) => {
+        this.off(event, handler);
+        if (listener) {
+          listener(event, first, ...rest);
+        }
+        resolve(first);
+      };
 
-        handler._originalListener = listener;
-        this.on(event, handler);
-      });
-    },
+      handler._originalListener = listener;
+      this.on(event, handler);
+    });
+  },
 
-    /**
-     * Remove a previously-registered event listener.  Works for events
-     * registered with either on or once.
-     *
-     * @param string event
-     *        The event name whose listener we're disconnecting.
-     * @param function listener
-     *        The listener to remove.
-     */
-    off(event, listener) {
+  /**
+   * Remove a previously-registered event listener.  Works for events
+   * registered with either on or once.
+   *
+   * @param string event
+   *        The event name whose listener we're disconnecting.
+   * @param function listener
+   *        The listener to remove.
+   */
+  off(event, listener) {
+    if (!this._eventEmitterListeners) {
+      return;
+    }
+    let listeners = this._eventEmitterListeners.get(event);
+    if (listeners) {
+      this._eventEmitterListeners.set(event, listeners.filter(l => {
+        return l !== listener && l._originalListener !== listener;
+      }));
+    }
+  },
+
+  /**
+   * Emit an event.  All arguments to this method will
+   * be sent to listener functions.
+   */
+  emit(event) {
+    this.logEvent(event, arguments);
+
+    if (!this._eventEmitterListeners || !this._eventEmitterListeners.has(event)) {
+      return;
+    }
+
+    let originalListeners = this._eventEmitterListeners.get(event);
+    for (let listener of this._eventEmitterListeners.get(event)) {
+      // If the object was destroyed during event emission, stop
+      // emitting.
       if (!this._eventEmitterListeners) {
-        return;
-      }
-      let listeners = this._eventEmitterListeners.get(event);
-      if (listeners) {
-        this._eventEmitterListeners.set(event, listeners.filter(l => {
-          return l !== listener && l._originalListener !== listener;
-        }));
-      }
-    },
-
-    /**
-     * Emit an event.  All arguments to this method will
-     * be sent to listener functions.
-     */
-    emit(event) {
-      this.logEvent(event, arguments);
-
-      if (!this._eventEmitterListeners || !this._eventEmitterListeners.has(event)) {
-        return;
+        break;
       }
 
-      let originalListeners = this._eventEmitterListeners.get(event);
-      for (let listener of this._eventEmitterListeners.get(event)) {
-        // If the object was destroyed during event emission, stop
-        // emitting.
-        if (!this._eventEmitterListeners) {
-          break;
-        }
-
-        // If listeners were removed during emission, make sure the
-        // event handler we're going to fire wasn't removed.
-        if (originalListeners === this._eventEmitterListeners.get(event) ||
-          this._eventEmitterListeners.get(event).some(l => l === listener)) {
-          try {
-            listener.apply(null, arguments);
-          } catch (ex) {
-            // Prevent a bad listener from interfering with the others.
-            let msg = ex + ": " + ex.stack;
-            console.error(msg);
-            dump(msg + "\n");
-          }
+      // If listeners were removed during emission, make sure the
+      // event handler we're going to fire wasn't removed.
+      if (originalListeners === this._eventEmitterListeners.get(event) ||
+        this._eventEmitterListeners.get(event).some(l => l === listener)) {
+        try {
+          listener.apply(null, arguments);
+        } catch (ex) {
+          // Prevent a bad listener from interfering with the others.
+          let msg = ex + ": " + ex.stack;
+          console.error(msg);
+          dump(msg + "\n");
         }
       }
-    },
+    }
+  },
 
-    logEvent(event, args) {
-      if (!loggingEnabled) {
-        return;
-      }
+  logEvent(event, args) {
+    if (!loggingEnabled) {
+      return;
+    }
 
-      let description = describeNthCaller(2);
+    let description = describeNthCaller(2);
 
-      let argOut = "(";
-      if (args.length === 1) {
-        argOut += event;
-      }
+    let argOut = "(";
+    if (args.length === 1) {
+      argOut += event;
+    }
 
-      let out = "EMITTING: ";
+    let out = "EMITTING: ";
 
-      // We need this try / catch to prevent any dead object errors.
-      try {
-        for (let i = 1; i < args.length; i++) {
-          if (i === 1) {
-            argOut = "(" + event + ", ";
-          } else {
-            argOut += ", ";
-          }
+    // We need this try / catch to prevent any dead object errors.
+    try {
+      for (let i = 1; i < args.length; i++) {
+        if (i === 1) {
+          argOut = "(" + event + ", ";
+        } else {
+          argOut += ", ";
+        }
 
-          let arg = args[i];
-          argOut += arg;
+        let arg = args[i];
+        argOut += arg;
 
-          if (arg && arg.nodeName) {
-            argOut += " (" + arg.nodeName;
-            if (arg.id) {
-              argOut += "#" + arg.id;
-            }
-            if (arg.className) {
-              argOut += "." + arg.className;
-            }
-            argOut += ")";
+        if (arg && arg.nodeName) {
+          argOut += " (" + arg.nodeName;
+          if (arg.id) {
+            argOut += "#" + arg.id;
+          }
+          if (arg.className) {
+            argOut += "." + arg.className;
           }
+          argOut += ")";
         }
-      } catch (e) {
-        // Object is dead so the toolbox is most likely shutting down,
-        // do nothing.
       }
+    } catch (e) {
+      // Object is dead so the toolbox is most likely shutting down,
+      // do nothing.
+    }
 
-      argOut += ")";
-      out += "emit" + argOut + " from " + description + "\n";
+    argOut += ")";
+    out += "emit" + argOut + " from " + description + "\n";
 
-      dump(out);
-    },
-  };
-});
+    dump(out);
+  },
+};