1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/deprecated/events.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,182 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +module.metadata = { 1.11 + "stability": "deprecated" 1.12 +}; 1.13 + 1.14 +const ERROR_TYPE = 'error', 1.15 + UNCAUGHT_ERROR = 'An error event was dispatched for which there was' 1.16 + + ' no listener.', 1.17 + BAD_LISTENER = 'The event listener must be a function.'; 1.18 +/** 1.19 + * This object is used to create an `EventEmitter` that, useful for composing 1.20 + * objects that emit events. It implements an interface like `EventTarget` from 1.21 + * DOM Level 2, which is implemented by Node objects in implementations that 1.22 + * support the DOM Event Model. 1.23 + * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget 1.24 + * @see http://nodejs.org/api.html#EventEmitter 1.25 + * @see http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/events/EventDispatcher.html 1.26 + */ 1.27 +const eventEmitter = { 1.28 + /** 1.29 + * Registers an event `listener` that is called every time events of 1.30 + * specified `type` are emitted. 1.31 + * @param {String} type 1.32 + * The type of event. 1.33 + * @param {Function} listener 1.34 + * The listener function that processes the event. 1.35 + * @example 1.36 + * worker.on('message', function (data) { 1.37 + * console.log('data received: ' + data) 1.38 + * }) 1.39 + */ 1.40 + on: function on(type, listener) { 1.41 + if ('function' !== typeof listener) 1.42 + throw new Error(BAD_LISTENER); 1.43 + let listeners = this._listeners(type); 1.44 + if (0 > listeners.indexOf(listener)) 1.45 + listeners.push(listener); 1.46 + // Use of `_public` is required by the legacy traits code that will go away 1.47 + // once bug-637633 is fixed. 1.48 + return this._public || this; 1.49 + }, 1.50 + 1.51 + /** 1.52 + * Registers an event `listener` that is called once the next time an event 1.53 + * of the specified `type` is emitted. 1.54 + * @param {String} type 1.55 + * The type of the event. 1.56 + * @param {Function} listener 1.57 + * The listener function that processes the event. 1.58 + */ 1.59 + once: function once(type, listener) { 1.60 + this.on(type, function selfRemovableListener() { 1.61 + this.removeListener(type, selfRemovableListener); 1.62 + listener.apply(this, arguments); 1.63 + }); 1.64 + }, 1.65 + 1.66 + /** 1.67 + * Unregister `listener` for the specified event type. 1.68 + * @param {String} type 1.69 + * The type of event. 1.70 + * @param {Function} listener 1.71 + * The listener function that processes the event. 1.72 + */ 1.73 + removeListener: function removeListener(type, listener) { 1.74 + if ('function' !== typeof listener) 1.75 + throw new Error(BAD_LISTENER); 1.76 + let listeners = this._listeners(type), 1.77 + index = listeners.indexOf(listener); 1.78 + if (0 <= index) 1.79 + listeners.splice(index, 1); 1.80 + // Use of `_public` is required by the legacy traits code, that will go away 1.81 + // once bug-637633 is fixed. 1.82 + return this._public || this; 1.83 + }, 1.84 + 1.85 + /** 1.86 + * Hash of listeners on this EventEmitter. 1.87 + */ 1.88 + _events: null, 1.89 + 1.90 + /** 1.91 + * Returns an array of listeners for the specified event `type`. This array 1.92 + * can be manipulated, e.g. to remove listeners. 1.93 + * @param {String} type 1.94 + * The type of event. 1.95 + */ 1.96 + _listeners: function listeners(type) { 1.97 + let events = this._events || (this._events = {}); 1.98 + return (events.hasOwnProperty(type) && events[type]) || (events[type] = []); 1.99 + }, 1.100 + 1.101 + /** 1.102 + * Execute each of the listeners in order with the supplied arguments. 1.103 + * Returns `true` if listener for this event was called, `false` if there are 1.104 + * no listeners for this event `type`. 1.105 + * 1.106 + * All the exceptions that are thrown by listeners during the emit 1.107 + * are caught and can be handled by listeners of 'error' event. Thrown 1.108 + * exceptions are passed as an argument to an 'error' event listener. 1.109 + * If no 'error' listener is registered exception will propagate to a 1.110 + * caller of this method. 1.111 + * 1.112 + * **It's recommended to have a default 'error' listener in all the complete 1.113 + * composition that in worst case may dump errors to the console.** 1.114 + * 1.115 + * @param {String} type 1.116 + * The type of event. 1.117 + * @params {Object|Number|String|Boolean} 1.118 + * Arguments that will be passed to listeners. 1.119 + * @returns {Boolean} 1.120 + */ 1.121 + _emit: function _emit(type, event) { 1.122 + let args = Array.slice(arguments); 1.123 + // Use of `_public` is required by the legacy traits code that will go away 1.124 + // once bug-637633 is fixed. 1.125 + args.unshift(this._public || this); 1.126 + return this._emitOnObject.apply(this, args); 1.127 + }, 1.128 + 1.129 + /** 1.130 + * A version of _emit that lets you specify the object on which listeners are 1.131 + * called. This is a hack that is sometimes necessary when such an object 1.132 + * (exports, for example) cannot be an EventEmitter for some reason, but other 1.133 + * object(s) managing events for the object are EventEmitters. Once bug 1.134 + * 577782 is fixed, this method shouldn't be necessary. 1.135 + * 1.136 + * @param {object} targetObj 1.137 + * The object on which listeners will be called. 1.138 + * @param {string} type 1.139 + * The event name. 1.140 + * @param {value} event 1.141 + * The first argument to pass to listeners. 1.142 + * @param {value} ... 1.143 + * More arguments to pass to listeners. 1.144 + * @returns {boolean} 1.145 + */ 1.146 + _emitOnObject: function _emitOnObject(targetObj, type, event /* , ... */) { 1.147 + let listeners = this._listeners(type).slice(0); 1.148 + // If there is no 'error' event listener then throw. 1.149 + if (type === ERROR_TYPE && !listeners.length) 1.150 + console.exception(event); 1.151 + if (!listeners.length) 1.152 + return false; 1.153 + let params = Array.slice(arguments, 2); 1.154 + for each (let listener in listeners) { 1.155 + try { 1.156 + listener.apply(targetObj, params); 1.157 + } catch(e) { 1.158 + // Bug 726967: Ignore exceptions being throws while notifying the error 1.159 + // in order to avoid infinite loops. 1.160 + if (type !== ERROR_TYPE) 1.161 + this._emit(ERROR_TYPE, e); 1.162 + else 1.163 + console.exception("Exception in error event listener " + e); 1.164 + } 1.165 + } 1.166 + return true; 1.167 + }, 1.168 + 1.169 + /** 1.170 + * Removes all the event listeners for the specified event `type`. 1.171 + * @param {String} type 1.172 + * The type of event. 1.173 + */ 1.174 + _removeAllListeners: function _removeAllListeners(type) { 1.175 + if (typeof type == "undefined") { 1.176 + this._events = null; 1.177 + return this; 1.178 + } 1.179 + 1.180 + this._listeners(type).splice(0); 1.181 + return this; 1.182 + } 1.183 +}; 1.184 +exports.EventEmitter = require("./traits").Trait.compose(eventEmitter); 1.185 +exports.EventEmitterTrait = require('./light-traits').Trait(eventEmitter);