diff options
Diffstat (limited to 'tools/addon-sdk-1.7/packages/api-utils/lib/events.js')
-rw-r--r-- | tools/addon-sdk-1.7/packages/api-utils/lib/events.js | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.7/packages/api-utils/lib/events.js b/tools/addon-sdk-1.7/packages/api-utils/lib/events.js new file mode 100644 index 0000000..531a7a3 --- /dev/null +++ b/tools/addon-sdk-1.7/packages/api-utils/lib/events.js @@ -0,0 +1,178 @@ +/* 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"; + +const ERROR_TYPE = 'error', + UNCAUGHT_ERROR = 'An error event was dispatched for which there was' + + ' no listener.', + BAD_LISTENER = 'The event listener must be a function.'; +/** + * This object is used to create an `EventEmitter` that, useful for composing + * objects that emit events. It implements an interface like `EventTarget` from + * DOM Level 2, which is implemented by Node objects in implementations that + * support the DOM Event Model. + * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget + * @see http://nodejs.org/api.html#EventEmitter + * @see http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/events/EventDispatcher.html + */ +const eventEmitter = { + /** + * Registers an event `listener` that is called every time events of + * specified `type` are emitted. + * @param {String} type + * The type of event. + * @param {Function} listener + * The listener function that processes the event. + * @example + * worker.on('message', function (data) { + * console.log('data received: ' + data) + * }) + */ + on: function on(type, listener) { + if ('function' !== typeof listener) + throw new Error(BAD_LISTENER); + let listeners = this._listeners(type); + if (0 > listeners.indexOf(listener)) + listeners.push(listener); + // Use of `_public` is required by the legacy traits code that will go away + // once bug-637633 is fixed. + return this._public || this; + }, + + /** + * Registers an event `listener` that is called once the next time an event + * of the specified `type` is emitted. + * @param {String} type + * The type of the event. + * @param {Function} listener + * The listener function that processes the event. + */ + once: function once(type, listener) { + this.on(type, function selfRemovableListener() { + this.removeListener(type, selfRemovableListener); + listener.apply(this, arguments); + }); + }, + + /** + * Unregister `listener` for the specified event type. + * @param {String} type + * The type of event. + * @param {Function} listener + * The listener function that processes the event. + */ + removeListener: function removeListener(type, listener) { + if ('function' !== typeof listener) + throw new Error(BAD_LISTENER); + let listeners = this._listeners(type), + index = listeners.indexOf(listener); + if (0 <= index) + listeners.splice(index, 1); + // Use of `_public` is required by the legacy traits code, that will go away + // once bug-637633 is fixed. + return this._public || this; + }, + + /** + * Hash of listeners on this EventEmitter. + */ + _events: null, + + /** + * Returns an array of listeners for the specified event `type`. This array + * can be manipulated, e.g. to remove listeners. + * @param {String} type + * The type of event. + */ + _listeners: function listeners(type) { + let events = this._events || (this._events = {}); + return events[type] || (events[type] = []); + }, + + /** + * Execute each of the listeners in order with the supplied arguments. + * Returns `true` if listener for this event was called, `false` if there are + * no listeners for this event `type`. + * + * All the exceptions that are thrown by listeners during the emit + * are caught and can be handled by listeners of 'error' event. Thrown + * exceptions are passed as an argument to an 'error' event listener. + * If no 'error' listener is registered exception will propagate to a + * caller of this method. + * + * **It's recommended to have a default 'error' listener in all the complete + * composition that in worst case may dump errors to the console.** + * + * @param {String} type + * The type of event. + * @params {Object|Number|String|Boolean} + * Arguments that will be passed to listeners. + * @returns {Boolean} + */ + _emit: function _emit(type, event) { + let args = Array.slice(arguments); + // Use of `_public` is required by the legacy traits code that will go away + // once bug-637633 is fixed. + args.unshift(this._public || this); + return this._emitOnObject.apply(this, args); + }, + + /** + * A version of _emit that lets you specify the object on which listeners are + * called. This is a hack that is sometimes necessary when such an object + * (exports, for example) cannot be an EventEmitter for some reason, but other + * object(s) managing events for the object are EventEmitters. Once bug + * 577782 is fixed, this method shouldn't be necessary. + * + * @param {object} targetObj + * The object on which listeners will be called. + * @param {string} type + * The event name. + * @param {value} event + * The first argument to pass to listeners. + * @param {value} ... + * More arguments to pass to listeners. + * @returns {boolean} + */ + _emitOnObject: function _emitOnObject(targetObj, type, event /* , ... */) { + let listeners = this._listeners(type).slice(0); + // If there is no 'error' event listener then throw. + if (type === ERROR_TYPE && !listeners.length) + console.exception(event); + if (!listeners.length) + return false; + let params = Array.slice(arguments, 2); + for each (let listener in listeners) { + try { + listener.apply(targetObj, params); + } catch(e) { + // Bug 726967: Ignore exceptions being throws while notifying the error + // in order to avoid infinite loops. + if (type !== ERROR_TYPE) + this._emit(ERROR_TYPE, e); + else + console.exception("Exception in error event listener " + e); + } + } + return true; + }, + + /** + * Removes all the event listeners for the specified event `type`. + * @param {String} type + * The type of event. + */ + _removeAllListeners: function _removeAllListeners(type) { + if (typeof type == "undefined") { + this._events = null; + return this; + } + + this._listeners(type).splice(0); + return this; + } +}; +exports.EventEmitter = require("./traits").Trait.compose(eventEmitter); +exports.EventEmitterTrait = require('./light-traits').Trait(eventEmitter); |