Projekt

Obecné

Profil

Stáhnout (8.93 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2

    
3
var has = Object.prototype.hasOwnProperty
4
  , prefix = '~';
5

    
6
/**
7
 * Constructor to create a storage for our `EE` objects.
8
 * An `Events` instance is a plain object whose properties are event names.
9
 *
10
 * @constructor
11
 * @private
12
 */
13
function Events() {}
14

    
15
//
16
// We try to not inherit from `Object.prototype`. In some engines creating an
17
// instance in this way is faster than calling `Object.create(null)` directly.
18
// If `Object.create(null)` is not supported we prefix the event names with a
19
// character to make sure that the built-in object properties are not
20
// overridden or used as an attack vector.
21
//
22
if (Object.create) {
23
  Events.prototype = Object.create(null);
24

    
25
  //
26
  // This hack is needed because the `__proto__` property is still inherited in
27
  // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
28
  //
29
  if (!new Events().__proto__) prefix = false;
30
}
31

    
32
/**
33
 * Representation of a single event listener.
34
 *
35
 * @param {Function} fn The listener function.
36
 * @param {*} context The context to invoke the listener with.
37
 * @param {Boolean} [once=false] Specify if the listener is a one-time listener.
38
 * @constructor
39
 * @private
40
 */
41
function EE(fn, context, once) {
42
  this.fn = fn;
43
  this.context = context;
44
  this.once = once || false;
45
}
46

    
47
/**
48
 * Add a listener for a given event.
49
 *
50
 * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
51
 * @param {(String|Symbol)} event The event name.
52
 * @param {Function} fn The listener function.
53
 * @param {*} context The context to invoke the listener with.
54
 * @param {Boolean} once Specify if the listener is a one-time listener.
55
 * @returns {EventEmitter}
56
 * @private
57
 */
58
function addListener(emitter, event, fn, context, once) {
59
  if (typeof fn !== 'function') {
60
    throw new TypeError('The listener must be a function');
61
  }
62

    
63
  var listener = new EE(fn, context || emitter, once)
64
    , evt = prefix ? prefix + event : event;
65

    
66
  if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
67
  else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
68
  else emitter._events[evt] = [emitter._events[evt], listener];
69

    
70
  return emitter;
71
}
72

    
73
/**
74
 * Clear event by name.
75
 *
76
 * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
77
 * @param {(String|Symbol)} evt The Event name.
78
 * @private
79
 */
80
function clearEvent(emitter, evt) {
81
  if (--emitter._eventsCount === 0) emitter._events = new Events();
82
  else delete emitter._events[evt];
83
}
84

    
85
/**
86
 * Minimal `EventEmitter` interface that is molded against the Node.js
87
 * `EventEmitter` interface.
88
 *
89
 * @constructor
90
 * @public
91
 */
92
function EventEmitter() {
93
  this._events = new Events();
94
  this._eventsCount = 0;
95
}
96

    
97
/**
98
 * Return an array listing the events for which the emitter has registered
99
 * listeners.
100
 *
101
 * @returns {Array}
102
 * @public
103
 */
104
EventEmitter.prototype.eventNames = function eventNames() {
105
  var names = []
106
    , events
107
    , name;
108

    
109
  if (this._eventsCount === 0) return names;
110

    
111
  for (name in (events = this._events)) {
112
    if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
113
  }
114

    
115
  if (Object.getOwnPropertySymbols) {
116
    return names.concat(Object.getOwnPropertySymbols(events));
117
  }
118

    
119
  return names;
120
};
121

    
122
/**
123
 * Return the listeners registered for a given event.
124
 *
125
 * @param {(String|Symbol)} event The event name.
126
 * @returns {Array} The registered listeners.
127
 * @public
128
 */
129
EventEmitter.prototype.listeners = function listeners(event) {
130
  var evt = prefix ? prefix + event : event
131
    , handlers = this._events[evt];
132

    
133
  if (!handlers) return [];
134
  if (handlers.fn) return [handlers.fn];
135

    
136
  for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
137
    ee[i] = handlers[i].fn;
138
  }
139

    
140
  return ee;
141
};
142

    
143
/**
144
 * Return the number of listeners listening to a given event.
145
 *
146
 * @param {(String|Symbol)} event The event name.
147
 * @returns {Number} The number of listeners.
148
 * @public
149
 */
150
EventEmitter.prototype.listenerCount = function listenerCount(event) {
151
  var evt = prefix ? prefix + event : event
152
    , listeners = this._events[evt];
153

    
154
  if (!listeners) return 0;
155
  if (listeners.fn) return 1;
156
  return listeners.length;
157
};
158

    
159
/**
160
 * Calls each of the listeners registered for a given event.
161
 *
162
 * @param {(String|Symbol)} event The event name.
163
 * @returns {Boolean} `true` if the event had listeners, else `false`.
164
 * @public
165
 */
166
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
167
  var evt = prefix ? prefix + event : event;
168

    
169
  if (!this._events[evt]) return false;
170

    
171
  var listeners = this._events[evt]
172
    , len = arguments.length
173
    , args
174
    , i;
175

    
176
  if (listeners.fn) {
177
    if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
178

    
179
    switch (len) {
180
      case 1: return listeners.fn.call(listeners.context), true;
181
      case 2: return listeners.fn.call(listeners.context, a1), true;
182
      case 3: return listeners.fn.call(listeners.context, a1, a2), true;
183
      case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
184
      case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
185
      case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
186
    }
187

    
188
    for (i = 1, args = new Array(len -1); i < len; i++) {
189
      args[i - 1] = arguments[i];
190
    }
191

    
192
    listeners.fn.apply(listeners.context, args);
193
  } else {
194
    var length = listeners.length
195
      , j;
196

    
197
    for (i = 0; i < length; i++) {
198
      if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
199

    
200
      switch (len) {
201
        case 1: listeners[i].fn.call(listeners[i].context); break;
202
        case 2: listeners[i].fn.call(listeners[i].context, a1); break;
203
        case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
204
        case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
205
        default:
206
          if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
207
            args[j - 1] = arguments[j];
208
          }
209

    
210
          listeners[i].fn.apply(listeners[i].context, args);
211
      }
212
    }
213
  }
214

    
215
  return true;
216
};
217

    
218
/**
219
 * Add a listener for a given event.
220
 *
221
 * @param {(String|Symbol)} event The event name.
222
 * @param {Function} fn The listener function.
223
 * @param {*} [context=this] The context to invoke the listener with.
224
 * @returns {EventEmitter} `this`.
225
 * @public
226
 */
227
EventEmitter.prototype.on = function on(event, fn, context) {
228
  return addListener(this, event, fn, context, false);
229
};
230

    
231
/**
232
 * Add a one-time listener for a given event.
233
 *
234
 * @param {(String|Symbol)} event The event name.
235
 * @param {Function} fn The listener function.
236
 * @param {*} [context=this] The context to invoke the listener with.
237
 * @returns {EventEmitter} `this`.
238
 * @public
239
 */
240
EventEmitter.prototype.once = function once(event, fn, context) {
241
  return addListener(this, event, fn, context, true);
242
};
243

    
244
/**
245
 * Remove the listeners of a given event.
246
 *
247
 * @param {(String|Symbol)} event The event name.
248
 * @param {Function} fn Only remove the listeners that match this function.
249
 * @param {*} context Only remove the listeners that have this context.
250
 * @param {Boolean} once Only remove one-time listeners.
251
 * @returns {EventEmitter} `this`.
252
 * @public
253
 */
254
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
255
  var evt = prefix ? prefix + event : event;
256

    
257
  if (!this._events[evt]) return this;
258
  if (!fn) {
259
    clearEvent(this, evt);
260
    return this;
261
  }
262

    
263
  var listeners = this._events[evt];
264

    
265
  if (listeners.fn) {
266
    if (
267
      listeners.fn === fn &&
268
      (!once || listeners.once) &&
269
      (!context || listeners.context === context)
270
    ) {
271
      clearEvent(this, evt);
272
    }
273
  } else {
274
    for (var i = 0, events = [], length = listeners.length; i < length; i++) {
275
      if (
276
        listeners[i].fn !== fn ||
277
        (once && !listeners[i].once) ||
278
        (context && listeners[i].context !== context)
279
      ) {
280
        events.push(listeners[i]);
281
      }
282
    }
283

    
284
    //
285
    // Reset the array, or remove it completely if we have no more listeners.
286
    //
287
    if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
288
    else clearEvent(this, evt);
289
  }
290

    
291
  return this;
292
};
293

    
294
/**
295
 * Remove all listeners, or those of the specified event.
296
 *
297
 * @param {(String|Symbol)} [event] The event name.
298
 * @returns {EventEmitter} `this`.
299
 * @public
300
 */
301
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
302
  var evt;
303

    
304
  if (event) {
305
    evt = prefix ? prefix + event : event;
306
    if (this._events[evt]) clearEvent(this, evt);
307
  } else {
308
    this._events = new Events();
309
    this._eventsCount = 0;
310
  }
311

    
312
  return this;
313
};
314

    
315
//
316
// Alias methods names because people roll like that.
317
//
318
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
319
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
320

    
321
//
322
// Expose the prefix.
323
//
324
EventEmitter.prefixed = prefix;
325

    
326
//
327
// Allow `EventEmitter` to be imported as module namespace.
328
//
329
EventEmitter.EventEmitter = EventEmitter;
330

    
331
//
332
// Expose the module.
333
//
334
if ('undefined' !== typeof module) {
335
  module.exports = EventEmitter;
336
}
(4-4/5)