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  };