/*! * EventEmitter2 * https://github.com/hij1nx/EventEmitter2 * * Copyright (c) 2013 hij1nx * Licensed under the MIT license. */ ;!function(undefined) { var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { return Object.prototype.toString.call(obj) === "[object Array]"; }; var defaultMaxListeners = 10; function init() { this._events = {}; if (this._conf) { configure.call(this, this._conf); } } function configure(conf) { if (conf) { this._conf = conf; conf.delimiter && (this.delimiter = conf.delimiter); this._maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners; conf.wildcard && (this.wildcard = conf.wildcard); conf.newListener && (this._newListener = conf.newListener); conf.removeListener && (this._removeListener = conf.removeListener); conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak); if (this.wildcard) { this.listenerTree = {}; } } else { this._maxListeners = defaultMaxListeners; } } function logPossibleMemoryLeak(count, eventName) { var errorMsg = '(node) warning: possible EventEmitter memory ' + 'leak detected. ' + count + ' listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.'; if(this.verboseMemoryLeak){ errorMsg += ' Event name: ' + eventName + '.'; } if(typeof process !== 'undefined' && process.emitWarning){ var e = new Error(errorMsg); e.name = 'MaxListenersExceededWarning'; e.emitter = this; e.count = count; process.emitWarning(e); } else { console.error(errorMsg); if (console.trace){ console.trace(); } } } function EventEmitter(conf) { this._events = {}; this._newListener = false; this._removeListener = false; this.verboseMemoryLeak = false; configure.call(this, conf); } EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property // // Attention, function return type now is array, always ! // It has zero elements if no any matches found and one or more // elements (leafs) if there are matches // function searchListenerTree(handlers, type, tree, i) { if (!tree) { return []; } var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, typeLength = type.length, currentType = type[i], nextType = type[i+1]; if (i === typeLength && tree._listeners) { // // If at the end of the event(s) list and the tree has listeners // invoke those listeners. // if (typeof tree._listeners === 'function') { handlers && handlers.push(tree._listeners); return [tree]; } else { for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { handlers && handlers.push(tree._listeners[leaf]); } return [tree]; } } if ((currentType === '*' || currentType === '**') || tree[currentType]) { // // If the event emitted is '*' at this part // or there is a concrete match at this patch // if (currentType === '*') { for (branch in tree) { if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); } } return listeners; } else if(currentType === '**') { endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); if(endReached && tree._listeners) { // The next element has a _listeners, add it to the handlers. listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); } for (branch in tree) { if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { if(branch === '*' || branch === '**') { if(tree[branch]._listeners && !endReached) { listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); } listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); } else if(branch === nextType) { listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); } else { // No match on this one, shift into the tree but not in the type array. listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); } } } return listeners; } listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); } xTree = tree['*']; if (xTree) { // // If the listener tree will allow any match for this part, // then recursively explore all branches of the tree // searchListenerTree(handlers, type, xTree, i+1); } xxTree = tree['**']; if(xxTree) { if(i < typeLength) { if(xxTree._listeners) { // If we have a listener on a '**', it will catch all, so add its handler. searchListenerTree(handlers, type, xxTree, typeLength); } // Build arrays of matching next branches and others. for(branch in xxTree) { if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { if(branch === nextType) { // We know the next element will match, so jump twice. searchListenerTree(handlers, type, xxTree[branch], i+2); } else if(branch === currentType) { // Current node matches, move into the tree. searchListenerTree(handlers, type, xxTree[branch], i+1); } else { isolatedBranch = {}; isolatedBranch[branch] = xxTree[branch]; searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); } } } } else if(xxTree._listeners) { // We have reached the end and still on a '**' searchListenerTree(handlers, type, xxTree, typeLength); } else if(xxTree['*'] && xxTree['*']._listeners) { searchListenerTree(handlers, type, xxTree['*'], typeLength); } } return listeners; } function growListenerTree(type, listener) { type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); // // Looks for two consecutive '**', if so, don't add the event at all. // for(var i = 0, len = type.length; i+1 < len; i++) { if(type[i] === '**' && type[i+1] === '**') { return; } } var tree = this.listenerTree; var name = type.shift(); while (name !== undefined) { if (!tree[name]) { tree[name] = {}; } tree = tree[name]; if (type.length === 0) { if (!tree._listeners) { tree._listeners = listener; } else { if (typeof tree._listeners === 'function') { tree._listeners = [tree._listeners]; } tree._listeners.push(listener); if ( !tree._listeners.warned && this._maxListeners > 0 && tree._listeners.length > this._maxListeners ) { tree._listeners.warned = true; logPossibleMemoryLeak.call(this, tree._listeners.length, name); } } return true; } name = type.shift(); } return true; } // By default EventEmitters will print a warning if more than // 10 listeners are added to it. This is a useful default which // helps finding memory leaks. // // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.delimiter = '.'; EventEmitter.prototype.setMaxListeners = function(n) { if (n !== undefined) { this._maxListeners = n; if (!this._conf) this._conf = {}; this._conf.maxListeners = n; } }; EventEmitter.prototype.event = ''; EventEmitter.prototype.once = function(event, fn) { return this._once(event, fn, false); }; EventEmitter.prototype.prependOnceListener = function(event, fn) { return this._once(event, fn, true); }; EventEmitter.prototype._once = function(event, fn, prepend) { this._many(event, 1, fn, prepend); return this; }; EventEmitter.prototype.many = function(event, ttl, fn) { return this._many(event, ttl, fn, false); } EventEmitter.prototype.prependMany = function(event, ttl, fn) { return this._many(event, ttl, fn, true); } EventEmitter.prototype._many = function(event, ttl, fn, prepend) { var self = this; if (typeof fn !== 'function') { throw new Error('many only accepts instances of Function'); } function listener() { if (--ttl === 0) { self.off(event, listener); } return fn.apply(this, arguments); } listener._origin = fn; this._on(event, listener, prepend); return self; }; EventEmitter.prototype.emit = function() { this._events || init.call(this); var type = arguments[0]; if (type === 'newListener' && !this._newListener) { if (!this._events.newListener) { return false; } } var al = arguments.length; var args,l,i,j; var handler; if (this._all && this._all.length) { handler = this._all.slice(); if (al > 3) { args = new Array(al); for (j = 0; j < al; j++) args[j] = arguments[j]; } for (i = 0, l = handler.length; i < l; i++) { this.event = type; switch (al) { case 1: handler[i].call(this, type); break; case 2: handler[i].call(this, type, arguments[1]); break; case 3: handler[i].call(this, type, arguments[1], arguments[2]); break; default: handler[i].apply(this, args); } } } if (this.wildcard) { handler = []; var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); searchListenerTree.call(this, handler, ns, this.listenerTree, 0); } else { handler = this._events[type]; if (typeof handler === 'function') { this.event = type; switch (al) { case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; default: args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; handler.apply(this, args); } return true; } else if (handler) { // need to make copy of handlers because list can change in the middle // of emit call handler = handler.slice(); } } if (handler && handler.length) { if (al > 3) { args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; } for (i = 0, l = handler.length; i < l; i++) { this.event = type; switch (al) { case 1: handler[i].call(this); break; case 2: handler[i].call(this, arguments[1]); break; case 3: handler[i].call(this, arguments[1], arguments[2]); break; default: handler[i].apply(this, args); } } return true; } else if (!this._all && type === 'error') { if (arguments[1] instanceof Error) { throw arguments[1]; // Unhandled 'error' event } else { throw new Error("Uncaught, unspecified 'error' event."); } return false; } return !!this._all; }; EventEmitter.prototype.emitAsync = function() { this._events || init.call(this); var type = arguments[0]; if (type === 'newListener' && !this._newListener) { if (!this._events.newListener) { return Promise.resolve([false]); } } var promises= []; var al = arguments.length; var args,l,i,j; var handler; if (this._all) { if (al > 3) { args = new Array(al); for (j = 1; j < al; j++) args[j] = arguments[j]; } for (i = 0, l = this._all.length; i < l; i++) { this.event = type; switch (al) { case 1: promises.push(this._all[i].call(this, type)); break; case 2: promises.push(this._all[i].call(this, type, arguments[1])); break; case 3: promises.push(this._all[i].call(this, type, arguments[1], arguments[2])); break; default: promises.push(this._all[i].apply(this, args)); } } } if (this.wildcard) { handler = []; var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); searchListenerTree.call(this, handler, ns, this.listenerTree, 0); } else { handler = this._events[type]; } if (typeof handler === 'function') { this.event = type; switch (al) { case 1: promises.push(handler.call(this)); break; case 2: promises.push(handler.call(this, arguments[1])); break; case 3: promises.push(handler.call(this, arguments[1], arguments[2])); break; default: args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; promises.push(handler.apply(this, args)); } } else if (handler && handler.length) { handler = handler.slice(); if (al > 3) { args = new Array(al - 1); for (j = 1; j < al; j++) args[j - 1] = arguments[j]; } for (i = 0, l = handler.length; i < l; i++) { this.event = type; switch (al) { case 1: promises.push(handler[i].call(this)); break; case 2: promises.push(handler[i].call(this, arguments[1])); break; case 3: promises.push(handler[i].call(this, arguments[1], arguments[2])); break; default: promises.push(handler[i].apply(this, args)); } } } else if (!this._all && type === 'error') { if (arguments[1] instanceof Error) { return Promise.reject(arguments[1]); // Unhandled 'error' event } else { return Promise.reject("Uncaught, unspecified 'error' event."); } } return Promise.all(promises); }; EventEmitter.prototype.on = function(type, listener) { return this._on(type, listener, false); }; EventEmitter.prototype.prependListener = function(type, listener) { return this._on(type, listener, true); }; EventEmitter.prototype.onAny = function(fn) { return this._onAny(fn, false); }; EventEmitter.prototype.prependAny = function(fn) { return this._onAny(fn, true); }; EventEmitter.prototype.addListener = EventEmitter.prototype.on; EventEmitter.prototype._onAny = function(fn, prepend){ if (typeof fn !== 'function') { throw new Error('onAny only accepts instances of Function'); } if (!this._all) { this._all = []; } // Add the function to the event listener collection. if(prepend){ this._all.unshift(fn); }else{ this._all.push(fn); } return this; } EventEmitter.prototype._on = function(type, listener, prepend) { if (typeof type === 'function') { this._onAny(type, listener); return this; } if (typeof listener !== 'function') { throw new Error('on only accepts instances of Function'); } this._events || init.call(this); // To avoid recursion in the case that type == "newListeners"! Before // adding it to the listeners, first emit "newListeners". if (this._newListener) this.emit('newListener', type, listener); if (this.wildcard) { growListenerTree.call(this, type, listener); return this; } if (!this._events[type]) { // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; } else { if (typeof this._events[type] === 'function') { // Change to array. this._events[type] = [this._events[type]]; } // If we've already got an array, just add if(prepend){ this._events[type].unshift(listener); }else{ this._events[type].push(listener); } // Check for listener leak if ( !this._events[type].warned && this._maxListeners > 0 && this._events[type].length > this._maxListeners ) { this._events[type].warned = true; logPossibleMemoryLeak.call(this, this._events[type].length, type); } } return this; } EventEmitter.prototype.off = function(type, listener) { if (typeof listener !== 'function') { throw new Error('removeListener only takes instances of Function'); } var handlers,leafs=[]; if(this.wildcard) { var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); } else { // does not use listeners(), so no side effect of creating _events[type] if (!this._events[type]) return this; handlers = this._events[type]; leafs.push({_listeners:handlers}); } for (var iLeaf=0; iLeaf 0) { recursivelyGarbageCollect(root[key]); } if (Object.keys(obj).length === 0) { delete root[key]; } } } recursivelyGarbageCollect(this.listenerTree); return this; }; EventEmitter.prototype.offAny = function(fn) { var i = 0, l = 0, fns; if (fn && this._all && this._all.length > 0) { fns = this._all; for(i = 0, l = fns.length; i < l; i++) { if(fn === fns[i]) { fns.splice(i, 1); if (this._removeListener) this.emit("removeListenerAny", fn); return this; } } } else { fns = this._all; if (this._removeListener) { for(i = 0, l = fns.length; i < l; i++) this.emit("removeListenerAny", fns[i]); } this._all = []; } return this; }; EventEmitter.prototype.removeListener = EventEmitter.prototype.off; EventEmitter.prototype.removeAllListeners = function(type) { if (type === undefined) { !this._events || init.call(this); return this; } if (this.wildcard) { var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); for (var iLeaf=0; iLeaf