/* var emitter = EventEmitter.create(); emitter.emit('my_event', args); emitter.on('my_event', function(args){ ...... }); http://nodejs.org/api/events.html */ const isUndefined = function (arg) { return arg === void 0; }; const isObject = function (arg) { return typeof arg === "object" && arg !== null; }; const isFunction = function (arg) { return typeof arg === "function"; }; function EventEmitter(maxListeners) { this._events = this._events || {}; this._maxListeners = maxListeners || undefined; } // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._maxListeners = undefined; // 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. EventEmitter.defaultMaxListeners = 10; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function (n) { if (isNaN(n) || n < 0) throw TypeError("n must be a positive number"); this._maxListeners = n; return this; }; EventEmitter.prototype.emit = function (type) { var er, handler, len, args, i, listeners; if (!this._events) this._events = {}; // If there is no 'error' event listener then throw. if (type === "error" && !this._events.error) { er = arguments[1]; if (er instanceof Error) { throw er; // Unhandled 'error' event } else { throw Error("Uncaught, unspecified \"error\" event."); } return false; } handler = this._events[type]; if (isUndefined(handler)) return false; if (isFunction(handler)) { var __caller = handler.__caller || this; switch (arguments.length) { // fast cases case 1: handler.call(__caller); break; case 2: handler.call(__caller, arguments[1]); break; case 3: handler.call(__caller, arguments[1], arguments[2]); break; // slower default: len = arguments.length; args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; handler.apply(__caller, args); } } else if (isObject(handler)) { len = arguments.length; args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; listeners = handler.slice(); len = listeners.length; for (i = 0; i < len; i++) { var __caller = listeners[i].__caller || this; listeners[i].apply(__caller, args); } } return true; }; EventEmitter.prototype.addListener = function (type, listener, caller, returnListenter) { if (!isFunction(listener)) throw TypeError("listener must be a function"); listener.__caller = caller; if (!this._events) this._events = {}; // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (this._events.newListener) this.emit("newListener", type, isFunction(listener.listener) ? listener.listener : listener); if (!this._events[type]) // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; else if (isObject(this._events[type])) // If we've already got an array, just append. this._events[type].push(listener); else // Adding the second element, need to change to array. this._events[type] = [this._events[type], listener]; // Check for listener leak if (isObject(this._events[type]) && !this._events[type].warned) { var m; if (!isUndefined(this._maxListeners)) { m = this._maxListeners; } else { m = EventEmitter.defaultMaxListeners; } if (m && m > 0 && this._events[type].length > m) { this._events[type].warned = true; console.error("(node) warning: possible EventEmitter memory " + "leak detected. %d listeners added. " + "Use emitter.setMaxListeners() to increase limit.", this._events[type].length); //console.trace(); } } if (returnListenter) { return listener; } else { return this; } }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.once = function (type, listener, caller) { if (!isFunction(listener)) throw TypeError("listener must be a function"); var fired = false; var that = this; function g() { that.removeListener(type, g); if (!fired) { fired = true; listener.apply(caller || that, arguments); } } g.listener = listener; this.on(type, g, caller); return this; }; EventEmitter.prototype.onnp = function (type, listener, key) { if (!isFunction(listener)) throw TypeError("listener must be a function"); if (!this._noRepeatKey) this._noRepeatKey = {}; var _key = key; if (_key == null) _key = type + "_" + listener.toString(); if (this._noRepeatKey[_key]) { this.removeListener(type, this._noRepeatKey[_key]); } this._noRepeatKey[_key] = listener; this.on(type, listener); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = EventEmitter.prototype.off = function (type, listener, caller) { var list, position, length, i; if (!isFunction(listener)) { throw TypeError("listener must be a function"); //return this; } if (!this._events || !this._events[type]) return this; list = this._events[type]; length = list.length; position = -1; if (list === listener || (isFunction(list.listener) && list.listener === listener)) { delete this._events[type]; if (this._events.removeListener) this.emit("removeListener", type, listener); } else if (isObject(list)) { for (i = length; i-- > 0;) { if (list[i] === listener || (list[i].listener && list[i].listener === listener) || list[i].__caller == caller) { position = i; break; } } if (position < 0) return this; if (list.length === 1) { list.length = 0; delete this._events[type]; } else { list.splice(position, 1); } if (this._events.removeListener) this.emit("removeListener", type, listener); } return this; }; EventEmitter.prototype.removeAllListenersExcept = function (type) { for (var key in this._events) { if (key === type) continue; this.removeAllListeners(key); } }; EventEmitter.prototype.removeAllListeners = function (type) { var key, listeners; if (!this._events) return this; // not listening for removeListener, no need to emit if (!this._events.removeListener) { if (arguments.length === 0) this._events = {}; else if (this._events[type]) delete this._events[type]; return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { for (key in this._events) { if (key === "removeListener") continue; this.removeAllListeners(key); } this.removeAllListeners("removeListener"); this._events = {}; return this; } listeners = this._events[type]; if (isFunction(listeners)) { this.removeListener(type, listeners); } else if (Array.isArray(listeners)) { // LIFO order while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } delete this._events[type]; this._noRepeatKey = {}; return this; }; EventEmitter.prototype.listeners = function (type) { var ret; if (!this._events || !this._events[type]) ret = []; else if (isFunction(this._events[type])) ret = [this._events[type]]; else ret = this._events[type].slice(); return ret; }; EventEmitter.prototype.debug = function () { console.log(this._events); }; export const MyEvent = EventEmitter as any as { (maxListeners: number): void; on(type: any, callback: any): any; once(type: any, callback: any): any; off(type: any, callback: any, caller?: any): void; emit(type: any, ...args: any[]): void; debug(): any; removeAllListeners(type?:any):void; };