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