index.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /**
  2. * Expose `Emitter`.
  3. */
  4. exports.Emitter = Emitter;
  5. /**
  6. * Initialize a new `Emitter`.
  7. *
  8. * @api public
  9. */
  10. function Emitter(obj) {
  11. if (obj) return mixin(obj);
  12. }
  13. /**
  14. * Mixin the emitter properties.
  15. *
  16. * @param {Object} obj
  17. * @return {Object}
  18. * @api private
  19. */
  20. function mixin(obj) {
  21. for (var key in Emitter.prototype) {
  22. obj[key] = Emitter.prototype[key];
  23. }
  24. return obj;
  25. }
  26. /**
  27. * Listen on the given `event` with `fn`.
  28. *
  29. * @param {String} event
  30. * @param {Function} fn
  31. * @return {Emitter}
  32. * @api public
  33. */
  34. Emitter.prototype.on =
  35. Emitter.prototype.addEventListener = function(event, fn){
  36. this._callbacks = this._callbacks || {};
  37. (this._callbacks['$' + event] = this._callbacks['$' + event] || [])
  38. .push(fn);
  39. return this;
  40. };
  41. /**
  42. * Adds an `event` listener that will be invoked a single
  43. * time then automatically removed.
  44. *
  45. * @param {String} event
  46. * @param {Function} fn
  47. * @return {Emitter}
  48. * @api public
  49. */
  50. Emitter.prototype.once = function(event, fn){
  51. function on() {
  52. this.off(event, on);
  53. fn.apply(this, arguments);
  54. }
  55. on.fn = fn;
  56. this.on(event, on);
  57. return this;
  58. };
  59. /**
  60. * Remove the given callback for `event` or all
  61. * registered callbacks.
  62. *
  63. * @param {String} event
  64. * @param {Function} fn
  65. * @return {Emitter}
  66. * @api public
  67. */
  68. Emitter.prototype.off =
  69. Emitter.prototype.removeListener =
  70. Emitter.prototype.removeAllListeners =
  71. Emitter.prototype.removeEventListener = function(event, fn){
  72. this._callbacks = this._callbacks || {};
  73. // all
  74. if (0 == arguments.length) {
  75. this._callbacks = {};
  76. return this;
  77. }
  78. // specific event
  79. var callbacks = this._callbacks['$' + event];
  80. if (!callbacks) return this;
  81. // remove all handlers
  82. if (1 == arguments.length) {
  83. delete this._callbacks['$' + event];
  84. return this;
  85. }
  86. // remove specific handler
  87. var cb;
  88. for (var i = 0; i < callbacks.length; i++) {
  89. cb = callbacks[i];
  90. if (cb === fn || cb.fn === fn) {
  91. callbacks.splice(i, 1);
  92. break;
  93. }
  94. }
  95. // Remove event specific arrays for event types that no
  96. // one is subscribed for to avoid memory leak.
  97. if (callbacks.length === 0) {
  98. delete this._callbacks['$' + event];
  99. }
  100. return this;
  101. };
  102. /**
  103. * Emit `event` with the given args.
  104. *
  105. * @param {String} event
  106. * @param {Mixed} ...
  107. * @return {Emitter}
  108. */
  109. Emitter.prototype.emit = function(event){
  110. this._callbacks = this._callbacks || {};
  111. var args = new Array(arguments.length - 1)
  112. , callbacks = this._callbacks['$' + event];
  113. for (var i = 1; i < arguments.length; i++) {
  114. args[i - 1] = arguments[i];
  115. }
  116. if (callbacks) {
  117. callbacks = callbacks.slice(0);
  118. for (var i = 0, len = callbacks.length; i < len; ++i) {
  119. callbacks[i].apply(this, args);
  120. }
  121. }
  122. return this;
  123. };
  124. // alias used for reserved events (protected method)
  125. Emitter.prototype.emitReserved = Emitter.prototype.emit;
  126. /**
  127. * Return array of callbacks for `event`.
  128. *
  129. * @param {String} event
  130. * @return {Array}
  131. * @api public
  132. */
  133. Emitter.prototype.listeners = function(event){
  134. this._callbacks = this._callbacks || {};
  135. return this._callbacks['$' + event] || [];
  136. };
  137. /**
  138. * Check if this emitter has `event` handlers.
  139. *
  140. * @param {String} event
  141. * @return {Boolean}
  142. * @api public
  143. */
  144. Emitter.prototype.hasListeners = function(event){
  145. return !! this.listeners(event).length;
  146. };