events.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. 'use strict';
  2. /**
  3. * Module exports.
  4. */
  5. exports.EventEmitter = EventEmitter;
  6. /**
  7. * Object#toString reference.
  8. */
  9. var objToString = Object.prototype.toString;
  10. /**
  11. * Check if a value is an array.
  12. *
  13. * @api private
  14. * @param {*} val The value to test.
  15. * @return {boolean} true if the value is an array, otherwise false.
  16. */
  17. function isArray (val) {
  18. return objToString.call(val) === '[object Array]';
  19. }
  20. /**
  21. * Event emitter constructor.
  22. *
  23. * @api public
  24. */
  25. function EventEmitter () {}
  26. /**
  27. * Add a listener.
  28. *
  29. * @api public
  30. * @param {string} name Event name.
  31. * @param {Function} fn Event handler.
  32. * @return {EventEmitter} Emitter instance.
  33. */
  34. EventEmitter.prototype.on = function (name, fn) {
  35. if (!this.$events) {
  36. this.$events = {};
  37. }
  38. if (!this.$events[name]) {
  39. this.$events[name] = fn;
  40. } else if (isArray(this.$events[name])) {
  41. this.$events[name].push(fn);
  42. } else {
  43. this.$events[name] = [this.$events[name], fn];
  44. }
  45. return this;
  46. };
  47. EventEmitter.prototype.addListener = EventEmitter.prototype.on;
  48. /**
  49. * Adds a volatile listener.
  50. *
  51. * @api public
  52. * @param {string} name Event name.
  53. * @param {Function} fn Event handler.
  54. * @return {EventEmitter} Emitter instance.
  55. */
  56. EventEmitter.prototype.once = function (name, fn) {
  57. var self = this;
  58. function on () {
  59. self.removeListener(name, on);
  60. fn.apply(this, arguments);
  61. }
  62. on.listener = fn;
  63. this.on(name, on);
  64. return this;
  65. };
  66. /**
  67. * Remove a listener.
  68. *
  69. * @api public
  70. * @param {string} name Event name.
  71. * @param {Function} fn Event handler.
  72. * @return {EventEmitter} Emitter instance.
  73. */
  74. EventEmitter.prototype.removeListener = function (name, fn) {
  75. if (this.$events && this.$events[name]) {
  76. var list = this.$events[name];
  77. if (isArray(list)) {
  78. var pos = -1;
  79. for (var i = 0, l = list.length; i < l; i++) {
  80. if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
  81. pos = i;
  82. break;
  83. }
  84. }
  85. if (pos < 0) {
  86. return this;
  87. }
  88. list.splice(pos, 1);
  89. if (!list.length) {
  90. delete this.$events[name];
  91. }
  92. } else if (list === fn || (list.listener && list.listener === fn)) {
  93. delete this.$events[name];
  94. }
  95. }
  96. return this;
  97. };
  98. /**
  99. * Remove all listeners for an event.
  100. *
  101. * @api public
  102. * @param {string} name Event name.
  103. * @return {EventEmitter} Emitter instance.
  104. */
  105. EventEmitter.prototype.removeAllListeners = function (name) {
  106. if (name === undefined) {
  107. this.$events = {};
  108. return this;
  109. }
  110. if (this.$events && this.$events[name]) {
  111. this.$events[name] = null;
  112. }
  113. return this;
  114. };
  115. /**
  116. * Get all listeners for a given event.
  117. *
  118. * @api public
  119. * @param {string} name Event name.
  120. * @return {EventEmitter} Emitter instance.
  121. */
  122. EventEmitter.prototype.listeners = function (name) {
  123. if (!this.$events) {
  124. this.$events = {};
  125. }
  126. if (!this.$events[name]) {
  127. this.$events[name] = [];
  128. }
  129. if (!isArray(this.$events[name])) {
  130. this.$events[name] = [this.$events[name]];
  131. }
  132. return this.$events[name];
  133. };
  134. /**
  135. * Emit an event.
  136. *
  137. * @api public
  138. * @param {string} name Event name.
  139. * @return {boolean} true if at least one handler was invoked, else false.
  140. */
  141. EventEmitter.prototype.emit = function (name) {
  142. if (!this.$events) {
  143. return false;
  144. }
  145. var handler = this.$events[name];
  146. if (!handler) {
  147. return false;
  148. }
  149. var args = Array.prototype.slice.call(arguments, 1);
  150. if (typeof handler === 'function') {
  151. handler.apply(this, args);
  152. } else if (isArray(handler)) {
  153. var listeners = handler.slice();
  154. for (var i = 0, l = listeners.length; i < l; i++) {
  155. listeners[i].apply(this, args);
  156. }
  157. } else {
  158. return false;
  159. }
  160. return true;
  161. };