/* WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based on @visionmedia's Emitter from UI Kit. Why? I wanted it standalone. I also wanted support for wildcard emitters like this: emitter.on('*', function (eventName, other, event, payloads) { }); emitter.on('somenamespace*', function (eventName, payloads) { }); Please note that callbacks triggered by wildcard registered events also get the event name as the first argument. */ module.exports = WildEmitter; function WildEmitter() { this.callbacks = {}; } // Listen on the given `event` with `fn`. Store a group name if present. WildEmitter.prototype.on = function (event, groupName, fn) { var hasGroup = (arguments.length === 3), group = hasGroup ? arguments[1] : undefined, func = hasGroup ? arguments[2] : arguments[1]; func._groupName = group; (this.callbacks[event] = this.callbacks[event] || []).push(func); return this; }; // Adds an `event` listener that will be invoked a single // time then automatically removed. WildEmitter.prototype.once = function (event, groupName, fn) { var self = this, hasGroup = (arguments.length === 3), group = hasGroup ? arguments[1] : undefined, func = hasGroup ? arguments[2] : arguments[1]; function on() { self.off(event, on); func.apply(this, arguments); } this.on(event, group, on); return this; }; // Unbinds an entire group WildEmitter.prototype.releaseGroup = function (groupName) { var item, i, len, handlers; for (item in this.callbacks) { handlers = this.callbacks[item]; for (i = 0, len = handlers.length; i < len; i++) { if (handlers[i]._groupName === groupName) { //console.log('removing'); // remove it and shorten the array we're looping through handlers.splice(i, 1); i--; len--; } } } return this; }; // Remove the given callback for `event` or all // registered callbacks. WildEmitter.prototype.off = function (event, fn) { var callbacks = this.callbacks[event], i; if (!callbacks) return this; // remove all handlers if (arguments.length === 1) { delete this.callbacks[event]; return this; } // remove specific handler i = callbacks.indexOf(fn); callbacks.splice(i, 1); return this; }; // Emit `event` with the given args. // also calls any `*` handlers WildEmitter.prototype.emit = function (event) { var args = [].slice.call(arguments, 1), callbacks = this.callbacks[event], specialCallbacks = this.getWildcardCallbacks(event), i, len, item; if (callbacks) { for (i = 0, len = callbacks.length; i < len; ++i) { if (callbacks[i]) { callbacks[i].apply(this, args); } else { break; } } } if (specialCallbacks) { for (i = 0, len = specialCallbacks.length; i < len; ++i) { if (specialCallbacks[i]) { specialCallbacks[i].apply(this, [event].concat(args)); } else { break; } } } return this; }; // Helper for for finding special wildcard event handlers that match the event WildEmitter.prototype.getWildcardCallbacks = function (eventName) { var item, split, result = []; for (item in this.callbacks) { split = item.split('*'); if (item === '*' || (split.length === 2 && eventName.slice(0, split[1].length) === split[1])) { result = result.concat(this.callbacks[item]); } } return result; };