index.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. 'use strict';
  2. var has = Object.prototype.hasOwnProperty
  3. , prefix = '~';
  4. /**
  5. * Constructor to create a storage for our `EE` objects.
  6. * An `Events` instance is a plain object whose properties are event names.
  7. *
  8. * @constructor
  9. * @api private
  10. */
  11. function Events() {}
  12. //
  13. // We try to not inherit from `Object.prototype`. In some engines creating an
  14. // instance in this way is faster than calling `Object.create(null)` directly.
  15. // If `Object.create(null)` is not supported we prefix the event names with a
  16. // character to make sure that the built-in object properties are not
  17. // overridden or used as an attack vector.
  18. //
  19. if (Object.create) {
  20. Events.prototype = Object.create(null);
  21. //
  22. // This hack is needed because the `__proto__` property is still inherited in
  23. // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
  24. //
  25. if (!new Events().__proto__) prefix = false;
  26. }
  27. /**
  28. * Representation of a single event listener.
  29. *
  30. * @param {Function} fn The listener function.
  31. * @param {Mixed} context The context to invoke the listener with.
  32. * @param {Boolean} [once=false] Specify if the listener is a one-time listener.
  33. * @constructor
  34. * @api private
  35. */
  36. function EE(fn, context, once) {
  37. this.fn = fn;
  38. this.context = context;
  39. this.once = once || false;
  40. }
  41. /**
  42. * Minimal `EventEmitter` interface that is molded against the Node.js
  43. * `EventEmitter` interface.
  44. *
  45. * @constructor
  46. * @api public
  47. */
  48. function EventEmitter() {
  49. this._events = new Events();
  50. this._eventsCount = 0;
  51. }
  52. /**
  53. * Return an array listing the events for which the emitter has registered
  54. * listeners.
  55. *
  56. * @returns {Array}
  57. * @api public
  58. */
  59. EventEmitter.prototype.eventNames = function eventNames() {
  60. var names = []
  61. , events
  62. , name;
  63. if (this._eventsCount === 0) return names;
  64. for (name in (events = this._events)) {
  65. if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
  66. }
  67. if (Object.getOwnPropertySymbols) {
  68. return names.concat(Object.getOwnPropertySymbols(events));
  69. }
  70. return names;
  71. };
  72. /**
  73. * Return the listeners registered for a given event.
  74. *
  75. * @param {String|Symbol} event The event name.
  76. * @param {Boolean} exists Only check if there are listeners.
  77. * @returns {Array|Boolean}
  78. * @api public
  79. */
  80. EventEmitter.prototype.listeners = function listeners(event, exists) {
  81. var evt = prefix ? prefix + event : event
  82. , available = this._events[evt];
  83. if (exists) return !!available;
  84. if (!available) return [];
  85. if (available.fn) return [available.fn];
  86. for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) {
  87. ee[i] = available[i].fn;
  88. }
  89. return ee;
  90. };
  91. /**
  92. * Calls each of the listeners registered for a given event.
  93. *
  94. * @param {String|Symbol} event The event name.
  95. * @returns {Boolean} `true` if the event had listeners, else `false`.
  96. * @api public
  97. */
  98. EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
  99. var evt = prefix ? prefix + event : event;
  100. if (!this._events[evt]) return false;
  101. var listeners = this._events[evt]
  102. , len = arguments.length
  103. , args
  104. , i;
  105. if (listeners.fn) {
  106. if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
  107. switch (len) {
  108. case 1: return listeners.fn.call(listeners.context), true;
  109. case 2: return listeners.fn.call(listeners.context, a1), true;
  110. case 3: return listeners.fn.call(listeners.context, a1, a2), true;
  111. case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
  112. case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
  113. case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
  114. }
  115. for (i = 1, args = new Array(len -1); i < len; i++) {
  116. args[i - 1] = arguments[i];
  117. }
  118. listeners.fn.apply(listeners.context, args);
  119. } else {
  120. var length = listeners.length
  121. , j;
  122. for (i = 0; i < length; i++) {
  123. if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
  124. switch (len) {
  125. case 1: listeners[i].fn.call(listeners[i].context); break;
  126. case 2: listeners[i].fn.call(listeners[i].context, a1); break;
  127. case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
  128. case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
  129. default:
  130. if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
  131. args[j - 1] = arguments[j];
  132. }
  133. listeners[i].fn.apply(listeners[i].context, args);
  134. }
  135. }
  136. }
  137. return true;
  138. };
  139. /**
  140. * Add a listener for a given event.
  141. *
  142. * @param {String|Symbol} event The event name.
  143. * @param {Function} fn The listener function.
  144. * @param {Mixed} [context=this] The context to invoke the listener with.
  145. * @returns {EventEmitter} `this`.
  146. * @api public
  147. */
  148. EventEmitter.prototype.on = function on(event, fn, context) {
  149. var listener = new EE(fn, context || this)
  150. , evt = prefix ? prefix + event : event;
  151. if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
  152. else if (!this._events[evt].fn) this._events[evt].push(listener);
  153. else this._events[evt] = [this._events[evt], listener];
  154. return this;
  155. };
  156. /**
  157. * Add a one-time listener for a given event.
  158. *
  159. * @param {String|Symbol} event The event name.
  160. * @param {Function} fn The listener function.
  161. * @param {Mixed} [context=this] The context to invoke the listener with.
  162. * @returns {EventEmitter} `this`.
  163. * @api public
  164. */
  165. EventEmitter.prototype.once = function once(event, fn, context) {
  166. var listener = new EE(fn, context || this, true)
  167. , evt = prefix ? prefix + event : event;
  168. if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
  169. else if (!this._events[evt].fn) this._events[evt].push(listener);
  170. else this._events[evt] = [this._events[evt], listener];
  171. return this;
  172. };
  173. /**
  174. * Remove the listeners of a given event.
  175. *
  176. * @param {String|Symbol} event The event name.
  177. * @param {Function} fn Only remove the listeners that match this function.
  178. * @param {Mixed} context Only remove the listeners that have this context.
  179. * @param {Boolean} once Only remove one-time listeners.
  180. * @returns {EventEmitter} `this`.
  181. * @api public
  182. */
  183. EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
  184. var evt = prefix ? prefix + event : event;
  185. if (!this._events[evt]) return this;
  186. if (!fn) {
  187. if (--this._eventsCount === 0) this._events = new Events();
  188. else delete this._events[evt];
  189. return this;
  190. }
  191. var listeners = this._events[evt];
  192. if (listeners.fn) {
  193. if (
  194. listeners.fn === fn
  195. && (!once || listeners.once)
  196. && (!context || listeners.context === context)
  197. ) {
  198. if (--this._eventsCount === 0) this._events = new Events();
  199. else delete this._events[evt];
  200. }
  201. } else {
  202. for (var i = 0, events = [], length = listeners.length; i < length; i++) {
  203. if (
  204. listeners[i].fn !== fn
  205. || (once && !listeners[i].once)
  206. || (context && listeners[i].context !== context)
  207. ) {
  208. events.push(listeners[i]);
  209. }
  210. }
  211. //
  212. // Reset the array, or remove it completely if we have no more listeners.
  213. //
  214. if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
  215. else if (--this._eventsCount === 0) this._events = new Events();
  216. else delete this._events[evt];
  217. }
  218. return this;
  219. };
  220. /**
  221. * Remove all listeners, or those of the specified event.
  222. *
  223. * @param {String|Symbol} [event] The event name.
  224. * @returns {EventEmitter} `this`.
  225. * @api public
  226. */
  227. EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
  228. var evt;
  229. if (event) {
  230. evt = prefix ? prefix + event : event;
  231. if (this._events[evt]) {
  232. if (--this._eventsCount === 0) this._events = new Events();
  233. else delete this._events[evt];
  234. }
  235. } else {
  236. this._events = new Events();
  237. this._eventsCount = 0;
  238. }
  239. return this;
  240. };
  241. //
  242. // Alias methods names because people roll like that.
  243. //
  244. EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
  245. EventEmitter.prototype.addListener = EventEmitter.prototype.on;
  246. //
  247. // This function doesn't apply anymore.
  248. //
  249. EventEmitter.prototype.setMaxListeners = function setMaxListeners() {
  250. return this;
  251. };
  252. //
  253. // Expose the prefix.
  254. //
  255. EventEmitter.prefixed = prefix;
  256. //
  257. // Allow `EventEmitter` to be imported as module namespace.
  258. //
  259. EventEmitter.EventEmitter = EventEmitter;
  260. //
  261. // Expose the module.
  262. //
  263. if ('undefined' !== typeof module) {
  264. module.exports = EventEmitter;
  265. }