/** * Module exports. */ exports.EventEmitter = EventEmitter; /** * Object#hasOwnProperty reference. */ var objToString = Object.prototype.toString; /** * Check if a value is an array. * * @api private * @param {*} val The value to test. * @return {boolean} true if the value is a boolean, otherwise false. */ function isArray(val) { return objToString.call(val) === '[object Array]'; } /** * Event emitter constructor. * * @api public */ function EventEmitter() {} /** * Add a listener. * * @api public * @param {string} name Event name. * @param {Function} fn Event handler. * @return {EventEmitter} Emitter instance. */ EventEmitter.prototype.on = function(name, fn) { if (!this.$events) { this.$events = {}; } if (!this.$events[name]) { this.$events[name] = fn; } else if (isArray(this.$events[name])) { this.$events[name].push(fn); } else { this.$events[name] = [this.$events[name], fn]; } return this; }; EventEmitter.prototype.addListener = EventEmitter.prototype.on; /** * Adds a volatile listener. * * @api public * @param {string} name Event name. * @param {Function} fn Event handler. * @return {EventEmitter} Emitter instance. */ EventEmitter.prototype.once = function(name, fn) { var self = this; function on() { self.removeListener(name, on); fn.apply(this, arguments); } on.listener = fn; this.on(name, on); return this; }; /** * Remove a listener. * * @api public * @param {string} name Event name. * @param {Function} fn Event handler. * @return {EventEmitter} Emitter instance. */ EventEmitter.prototype.removeListener = function(name, fn) { if (this.$events && this.$events[name]) { var list = this.$events[name]; if (isArray(list)) { var pos = -1; for (var i = 0, l = list.length; i < l; i++) { if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { pos = i; break; } } if (pos < 0) { return this; } list.splice(pos, 1); if (!list.length) { delete this.$events[name]; } } else if (list === fn || (list.listener && list.listener === fn)) { delete this.$events[name]; } } return this; }; /** * Remove all listeners for an event. * * @api public * @param {string} name Event name. * @return {EventEmitter} Emitter instance. */ EventEmitter.prototype.removeAllListeners = function(name) { if (name === undefined) { this.$events = {}; return this; } if (this.$events && this.$events[name]) { this.$events[name] = null; } return this; }; /** * Get all listeners for a given event. * * @api public * @param {string} name Event name. * @return {EventEmitter} Emitter instance. */ EventEmitter.prototype.listeners = function(name) { if (!this.$events) { this.$events = {}; } if (!this.$events[name]) { this.$events[name] = []; } if (!isArray(this.$events[name])) { this.$events[name] = [this.$events[name]]; } return this.$events[name]; }; /** * Emit an event. * * @api public * @param {string} name Event name. * @return {boolean} true if at least one handler was invoked, else false. */ EventEmitter.prototype.emit = function(name) { if (!this.$events) { return false; } var handler = this.$events[name]; if (!handler) { return false; } var args = Array.prototype.slice.call(arguments, 1); if (typeof handler === 'function') { handler.apply(this, args); } else if (isArray(handler)) { var listeners = handler.slice(); for (var i = 0, l = listeners.length; i < l; i++) { listeners[i].apply(this, args); } } else { return false; } return true; };