index.js 3.4 KB

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