You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
2.9 KiB

  1. /**
  2. * Expose `Emitter`.
  3. */
  4. module.exports = 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. var self = this;
  52. this._callbacks = this._callbacks || {};
  53. function on() {
  54. self.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. return this;
  98. };
  99. /**
  100. * Emit `event` with the given args.
  101. *
  102. * @param {String} event
  103. * @param {Mixed} ...
  104. * @return {Emitter}
  105. */
  106. Emitter.prototype.emit = function(event){
  107. this._callbacks = this._callbacks || {};
  108. var args = [].slice.call(arguments, 1)
  109. , callbacks = this._callbacks[event];
  110. if (callbacks) {
  111. callbacks = callbacks.slice(0);
  112. for (var i = 0, len = callbacks.length; i < len; ++i) {
  113. callbacks[i].apply(this, args);
  114. }
  115. }
  116. return this;
  117. };
  118. /**
  119. * Return array of callbacks for `event`.
  120. *
  121. * @param {String} event
  122. * @return {Array}
  123. * @api public
  124. */
  125. Emitter.prototype.listeners = function(event){
  126. this._callbacks = this._callbacks || {};
  127. return this._callbacks[event] || [];
  128. };
  129. /**
  130. * Check if this emitter has `event` handlers.
  131. *
  132. * @param {String} event
  133. * @return {Boolean}
  134. * @api public
  135. */
  136. Emitter.prototype.hasListeners = function(event){
  137. return !! this.listeners(event).length;
  138. };