105
|
1 /**
|
|
2 * EventEmitter v3.1.5
|
|
3 * https://github.com/Wolfy87/EventEmitter
|
|
4 *
|
|
5 * Oliver Caldwell (http://oli.me.uk)
|
|
6 * Creative Commons Attribution 3.0 Unported License (http://creativecommons.org/licenses/by/3.0/)
|
|
7 */
|
|
8
|
|
9 ;(function(exports) {
|
|
10 // JSHint config
|
|
11 /*jshint smarttabs:true,devel:true*/
|
|
12 /*global define:true*/
|
|
13
|
|
14 // Place the script into strict mode
|
|
15 'use strict';
|
|
16
|
|
17 /**
|
|
18 * EventEmitter class
|
|
19 * Creates an object with event registering and firing methods
|
|
20 */
|
|
21 function EventEmitter() {
|
|
22 // Initialise required storage variables
|
|
23 this._events = {};
|
|
24 this._maxListeners = 10;
|
|
25 }
|
|
26
|
|
27 /**
|
|
28 * Event class
|
|
29 * Contains Event methods and property storage
|
|
30 *
|
|
31 * @param {String} type Event type name
|
|
32 * @param {Function} listener Function to be called when the event is fired
|
|
33 * @param {Object} scope Object that this should be set to when the listener is called
|
|
34 * @param {Boolean} once If true then the listener will be removed after the first call
|
|
35 * @param {Object} instance The parent EventEmitter instance
|
|
36 */
|
|
37 function Event(type, listener, scope, once, instance) {
|
|
38 // Store arguments
|
|
39 this.type = type;
|
|
40 this.listener = listener;
|
|
41 this.scope = scope;
|
|
42 this.once = once;
|
|
43 this.instance = instance;
|
|
44 }
|
|
45
|
|
46 /**
|
|
47 * Executes the listener
|
|
48 *
|
|
49 * @param {Array} args List of arguments to pass to the listener
|
|
50 * @return {Boolean} If false then it was a once event
|
|
51 */
|
|
52 Event.prototype.fire = function(args) {
|
|
53 this.listener.apply(this.scope || this.instance, args);
|
|
54
|
|
55 // Remove the listener if this is a once only listener
|
|
56 if(this.once) {
|
|
57 this.instance.removeListener(this.type, this.listener, this.scope);
|
|
58 return false;
|
|
59 }
|
|
60 };
|
|
61
|
|
62 /**
|
|
63 * Passes every listener for a specified event to a function one at a time
|
|
64 *
|
|
65 * @param {String} type Event type name
|
|
66 * @param {Function} callback Function to pass each listener to
|
|
67 * @return {Object} The current EventEmitter instance to allow chaining
|
|
68 */
|
|
69 EventEmitter.prototype.eachListener = function(type, callback) {
|
|
70 // Initialise variables
|
|
71 var i = null,
|
|
72 possibleListeners = null,
|
|
73 result = null;
|
|
74
|
|
75 // Only loop if the type exists
|
|
76 if(this._events.hasOwnProperty(type)) {
|
|
77 possibleListeners = this._events[type];
|
|
78
|
|
79 for(i = 0; i < possibleListeners.length; i += 1) {
|
|
80 result = callback.call(this, possibleListeners[i], i);
|
|
81
|
|
82 if(result === false) {
|
|
83 i -= 1;
|
|
84 }
|
|
85 else if(result === true) {
|
|
86 break;
|
|
87 }
|
|
88 }
|
|
89 }
|
|
90
|
|
91 // Return the instance to allow chaining
|
|
92 return this;
|
|
93 };
|
|
94
|
|
95 /**
|
|
96 * Adds an event listener for the specified event
|
|
97 *
|
|
98 * @param {String} type Event type name
|
|
99 * @param {Function} listener Function to be called when the event is fired
|
|
100 * @param {Object} scope Object that this should be set to when the listener is called
|
|
101 * @param {Boolean} once If true then the listener will be removed after the first call
|
|
102 * @return {Object} The current EventEmitter instance to allow chaining
|
|
103 */
|
|
104 EventEmitter.prototype.addListener = function(type, listener, scope, once) {
|
|
105 // Create the listener array if it does not exist yet
|
|
106 if(!this._events.hasOwnProperty(type)) {
|
|
107 this._events[type] = [];
|
|
108 }
|
|
109
|
|
110 // Push the new event to the array
|
|
111 this._events[type].push(new Event(type, listener, scope, once, this));
|
|
112
|
|
113 // Emit the new listener event
|
|
114 this.emit('newListener', type, listener, scope, once);
|
|
115
|
|
116 // Check if we have exceeded the maxListener count
|
|
117 // Ignore this check if the count is 0
|
|
118 // Also don't check if we have already fired a warning
|
|
119 if(this._maxListeners && !this._events[type].warned && this._events[type].length > this._maxListeners) {
|
|
120 // The max listener count has been exceeded!
|
|
121 // Warn via the console if it exists
|
|
122 if(typeof console !== 'undefined') {
|
|
123 console.warn('Possible EventEmitter memory leak detected. ' + this._events[type].length + ' listeners added. Use emitter.setMaxListeners() to increase limit.');
|
|
124 }
|
|
125
|
|
126 // Set the flag so it doesn't fire again
|
|
127 this._events[type].warned = true;
|
|
128 }
|
|
129
|
|
130 // Return the instance to allow chaining
|
|
131 return this;
|
|
132 };
|
|
133
|
|
134 /**
|
|
135 * Alias of the addListener method
|
|
136 *
|
|
137 * @param {String} type Event type name
|
|
138 * @param {Function} listener Function to be called when the event is fired
|
|
139 * @param {Object} scope Object that this should be set to when the listener is called
|
|
140 * @param {Boolean} once If true then the listener will be removed after the first call
|
|
141 */
|
|
142 EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
|
143
|
|
144 /**
|
|
145 * Alias of the addListener method but will remove the event after the first use
|
|
146 *
|
|
147 * @param {String} type Event type name
|
|
148 * @param {Function} listener Function to be called when the event is fired
|
|
149 * @param {Object} scope Object that this should be set to when the listener is called
|
|
150 * @return {Object} The current EventEmitter instance to allow chaining
|
|
151 */
|
|
152 EventEmitter.prototype.once = function(type, listener, scope) {
|
|
153 return this.addListener(type, listener, scope, true);
|
|
154 };
|
|
155
|
|
156 /**
|
|
157 * Removes the a listener for the specified event
|
|
158 *
|
|
159 * @param {String} type Event type name the listener must have for the event to be removed
|
|
160 * @param {Function} listener Listener the event must have to be removed
|
|
161 * @param {Object} scope The scope the event must have to be removed
|
|
162 * @return {Object} The current EventEmitter instance to allow chaining
|
|
163 */
|
|
164 EventEmitter.prototype.removeListener = function(type, listener, scope) {
|
|
165 this.eachListener(type, function(currentListener, index) {
|
|
166 // If this is the listener remove it from the array
|
|
167 // We also compare the scope if it was passed
|
|
168 if(currentListener.listener === listener && (!scope || currentListener.scope === scope)) {
|
|
169 this._events[type].splice(index, 1);
|
|
170 }
|
|
171 });
|
|
172
|
|
173 // Remove the property if there are no more listeners
|
|
174 if(this._events[type] && this._events[type].length === 0) {
|
|
175 delete this._events[type];
|
|
176 }
|
|
177
|
|
178 // Return the instance to allow chaining
|
|
179 return this;
|
|
180 };
|
|
181
|
|
182 /**
|
|
183 * Alias of the removeListener method
|
|
184 *
|
|
185 * @param {String} type Event type name the listener must have for the event to be removed
|
|
186 * @param {Function} listener Listener the event must have to be removed
|
|
187 * @param {Object} scope The scope the event must have to be removed
|
|
188 * @return {Object} The current EventEmitter instance to allow chaining
|
|
189 */
|
|
190 EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
191
|
|
192 /**
|
|
193 * Removes all listeners for a specified event
|
|
194 * If no event type is passed it will remove every listener
|
|
195 *
|
|
196 * @param {String} type Event type name to remove all listeners from
|
|
197 * @return {Object} The current EventEmitter instance to allow chaining
|
|
198 */
|
|
199 EventEmitter.prototype.removeAllListeners = function(type) {
|
|
200 // Check for a type, if there is none remove all listeners
|
|
201 // If there is a type however, just remove the listeners for that type
|
|
202 if(type && this._events.hasOwnProperty(type)) {
|
|
203 delete this._events[type];
|
|
204 }
|
|
205 else if(!type) {
|
|
206 this._events = {};
|
|
207 }
|
|
208
|
|
209 // Return the instance to allow chaining
|
|
210 return this;
|
|
211 };
|
|
212
|
|
213 /**
|
|
214 * Retrieves the array of listeners for a specified event
|
|
215 *
|
|
216 * @param {String} type Event type name to return all listeners from
|
|
217 * @return {Array} Will return either an array of listeners or an empty array if there are none
|
|
218 */
|
|
219 EventEmitter.prototype.listeners = function(type) {
|
|
220 // Return the array of listeners or an empty array if it does not exist
|
|
221 if(this._events.hasOwnProperty(type)) {
|
|
222 // It does exist, loop over building the array
|
|
223 var listeners = [];
|
|
224
|
|
225 this.eachListener(type, function(evt) {
|
|
226 listeners.push(evt.listener);
|
|
227 });
|
|
228
|
|
229 return listeners;
|
|
230 }
|
|
231
|
|
232 return [];
|
|
233 };
|
|
234
|
|
235 /**
|
|
236 * Emits an event executing all appropriate listeners
|
|
237 * All values passed after the type will be passed as arguments to the listeners
|
|
238 *
|
|
239 * @param {String} type Event type name to run all listeners from
|
|
240 * @return {Object} The current EventEmitter instance to allow chaining
|
|
241 */
|
|
242 EventEmitter.prototype.emit = function(type) {
|
|
243 // Calculate the arguments
|
|
244 var args = [],
|
|
245 i = null;
|
|
246
|
|
247 for(i = 1; i < arguments.length; i += 1) {
|
|
248 args.push(arguments[i]);
|
|
249 }
|
|
250
|
|
251 this.eachListener(type, function(currentListener) {
|
|
252 return currentListener.fire(args);
|
|
253 });
|
|
254
|
|
255 // Return the instance to allow chaining
|
|
256 return this;
|
|
257 };
|
|
258
|
|
259 /**
|
|
260 * Sets the max listener count for the EventEmitter
|
|
261 * When the count of listeners for an event exceeds this limit a warning will be printed
|
|
262 * Set to 0 for no limit
|
|
263 *
|
|
264 * @param {Number} maxListeners The new max listener limit
|
|
265 * @return {Object} The current EventEmitter instance to allow chaining
|
|
266 */
|
|
267 EventEmitter.prototype.setMaxListeners = function(maxListeners) {
|
|
268 this._maxListeners = maxListeners;
|
|
269
|
|
270 // Return the instance to allow chaining
|
|
271 return this;
|
|
272 };
|
|
273
|
|
274 /**
|
|
275 * Builds a clone of the prototype object for you to extend with
|
|
276 *
|
|
277 * @return {Object} A clone of the EventEmitter prototype object
|
|
278 */
|
|
279 EventEmitter.extend = function() {
|
|
280 // First thing we need to do is create our new prototype
|
|
281 // Then we loop over the current one copying each method out
|
|
282 // When done, simply return the clone
|
|
283 var clone = {},
|
|
284 current = this.prototype,
|
|
285 key = null;
|
|
286
|
|
287 for(key in current) {
|
|
288 // Make sure this is actually a property of the object before copying it
|
|
289 // We don't want any default object methods leaking though
|
|
290 if(current.hasOwnProperty(key)) {
|
|
291 clone[key] = current[key];
|
|
292 }
|
|
293 }
|
|
294
|
|
295 // All done, return the clone
|
|
296 return clone;
|
|
297 };
|
|
298
|
|
299 // Export the class
|
|
300 // If AMD is available then use it
|
|
301 if(typeof define === 'function' && define.amd) {
|
|
302 define(function() {
|
|
303 return EventEmitter;
|
|
304 });
|
|
305 }
|
|
306
|
|
307 // No matter what it will be added to the global object
|
|
308 exports.EventEmitter = EventEmitter;
|
|
309 }(this));
|