UNPKG

nativeloop

Version:

⭐ Axway Amplify module for using nativeloop with Appcelerator Titanium SDK Framework

709 lines (611 loc) 19.3 kB
/*! * 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._events.maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners; conf.wildcard && ( this.wildcard = conf.wildcard ); conf.newListener && ( this.newListener = conf.newListener ); conf.verboseMemoryLeak && ( this.verboseMemoryLeak = conf.verboseMemoryLeak ); if( this.wildcard ) { this.listenerTree = {}; } } else { this._events.maxListeners = defaultMaxListeners; } } function logPossibleMemoryLeak( count, eventName ) { var errorMsg = '(node) warning: possible EventEmitter memory ' + 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.'; if( this.verboseMemoryLeak ) { errorMsg += ' Event name: %s.'; console.error( errorMsg, count, eventName ); } else { console.error( errorMsg, count ); } if( console.trace ) { console.trace(); } } function EventEmitter( conf ) { this._events = {}; this.newListener = 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._events.maxListeners > 0 && tree._listeners.length > this._events.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._events || init.call( this ); this._events.maxListeners = n; if( !this._conf ) this._conf = {}; this._conf.maxListeners = n; } }; EventEmitter.prototype.event = ''; EventEmitter.prototype.once = function( event, fn ) { this.many( event, 1, fn ); return this; }; EventEmitter.prototype.many = function( event, ttl, fn ) { 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 ); } fn.apply( this, arguments ); } listener._origin = fn; this.on( event, listener ); 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 ) { 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 ) { if( typeof type === 'function' ) { this.onAny( type ); 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". 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 append. this._events[ type ].push( listener ); // Check for listener leak if( !this._events[ type ].warned && this._events.maxListeners > 0 && this._events[ type ].length > this._events.maxListeners ) { this._events[ type ].warned = true; logPossibleMemoryLeak.call( this, this._events[ type ].length, type ); } } return this; }; EventEmitter.prototype.onAny = function( fn ) { 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. this._all.push( fn ); return this; }; EventEmitter.prototype.addListener = EventEmitter.prototype.on; 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 < leafs.length; iLeaf++ ) { var leaf = leafs[ iLeaf ]; handlers = leaf._listeners; if( isArray( handlers ) ) { var position = -1; for( var i = 0, length = handlers.length; i < length; i++ ) { if( handlers[ i ] === listener || ( handlers[ i ].listener && handlers[ i ].listener === listener ) || ( handlers[ i ]._origin && handlers[ i ]._origin === listener ) ) { position = i; break; } } if( position < 0 ) { continue; } if( this.wildcard ) { leaf._listeners.splice( position, 1 ); } else { this._events[ type ].splice( position, 1 ); } if( handlers.length === 0 ) { if( this.wildcard ) { delete leaf._listeners; } else { delete this._events[ type ]; } } this.emit( "removeListener", type, listener ); return this; } else if( handlers === listener || ( handlers.listener && handlers.listener === listener ) || ( handlers._origin && handlers._origin === listener ) ) { if( this.wildcard ) { delete leaf._listeners; } else { delete this._events[ type ]; } this.emit( "removeListener", type, listener ); } } function recursivelyGarbageCollect( root ) { if( root === undefined ) { return; } var keys = Object.keys( root ); for( var i in keys ) { var key = keys[ i ]; var obj = root[ key ]; if( ( obj instanceof Function ) || ( typeof obj !== "object" ) || ( obj === null ) ) continue; if( Object.keys( obj ).length > 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 ); this.emit( "removeListenerAny", fn ); return this; } } } else { fns = this._all; 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( arguments.length === 0 ) { !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 < leafs.length; iLeaf++ ) { var leaf = leafs[ iLeaf ]; leaf._listeners = null; } } else if( this._events ) { this._events[ type ] = null; } return this; }; EventEmitter.prototype.listeners = function( type ) { if( this.wildcard ) { var handlers = []; var ns = typeof type === 'string' ? type.split( this.delimiter ) : type.slice(); searchListenerTree.call( this, handlers, ns, this.listenerTree, 0 ); return handlers; } this._events || init.call( this ); if( !this._events[ type ] ) this._events[ type ] = []; if( !isArray( this._events[ type ] ) ) { this._events[ type ] = [ this._events[ type ] ]; } return this._events[ type ]; }; EventEmitter.prototype.listenerCount = function( type ) { return this.listeners( type ).length; }; EventEmitter.prototype.listenersAny = function() { if( this._all ) { return this._all; } else { return []; } }; if( typeof define === 'function' && define.amd ) { // AMD. Register as an anonymous module. define( function() { return EventEmitter; } ); } else if( typeof exports === 'object' ) { // CommonJS module.exports = EventEmitter; } else { // Browser global. window.EventEmitter2 = EventEmitter; } }();