UNPKG

emitter-b

Version:

An enhanced EventEmitter with extra methods for detecting whether an event has any handlers or not for efficient event handler attachment.

761 lines (649 loc) 24.9 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["EmitterB"] = factory(); else root["EmitterB"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 2); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /* unknown exports provided */ /* all exports used */ /*!*****************************!*\ !*** ../~/events/events.js ***! \*****************************/ /***/ (function(module, exports) { // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. function EventEmitter() { this._events = this._events || {}; this._maxListeners = this._maxListeners || undefined; } module.exports = EventEmitter; // 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 (!isNumber(n) || n < 0 || isNaN(n)) 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') { if (!this._events.error || (isObject(this._events.error) && !this._events.error.length)) { er = arguments[1]; if (er instanceof Error) { throw er; // Unhandled 'error' event } else { // At least give some kind of context to the user var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); err.context = er; throw err; } } } handler = this._events[type]; if (isUndefined(handler)) return false; if (isFunction(handler)) { switch (arguments.length) { // fast cases case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; // slower default: args = Array.prototype.slice.call(arguments, 1); handler.apply(this, args); } } else if (isObject(handler)) { args = Array.prototype.slice.call(arguments, 1); listeners = handler.slice(); len = listeners.length; for (i = 0; i < len; i++) listeners[i].apply(this, args); } return true; }; EventEmitter.prototype.addListener = function(type, listener) { var m; if (!isFunction(listener)) throw TypeError('listener must be a function'); 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) { 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); if (typeof console.trace === 'function') { // not supported in IE 10 console.trace(); } } } return this; }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.once = function(type, listener) { if (!isFunction(listener)) throw TypeError('listener must be a function'); var fired = false; function g() { this.removeListener(type, g); if (!fired) { fired = true; listener.apply(this, arguments); } } g.listener = listener; this.on(type, g); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = function(type, listener) { var list, position, length, i; if (!isFunction(listener)) throw TypeError('listener must be a function'); 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)) { 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.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 (listeners) { // LIFO order while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } delete this._events[type]; 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.listenerCount = function(type) { if (this._events) { var evlistener = this._events[type]; if (isFunction(evlistener)) return 1; else if (evlistener) return evlistener.length; } return 0; }; EventEmitter.listenerCount = function(emitter, type) { return emitter.listenerCount(type); }; function isFunction(arg) { return typeof arg === 'function'; } function isNumber(arg) { return typeof arg === 'number'; } function isObject(arg) { return typeof arg === 'object' && arg !== null; } function isUndefined(arg) { return arg === void 0; } /***/ }), /* 1 */ /* unknown exports provided */ /* all exports used */ /*!***************************!*\ !*** ../~/proto/proto.js ***! \***************************/ /***/ (function(module, exports, __webpack_require__) { "use strict"; /* Copyright (c) 2013 Billy Tetrud - Free to use for any purpose: MIT License*/ var noop = function() {} var prototypeName='prototype', undefined, protoUndefined='undefined', init='init', ownProperty=({}).hasOwnProperty; // minifiable variables function proto() { var args = arguments // minifiable variables if(args.length == 1) { var parent = {init: noop} var prototypeBuilder = args[0] } else { // length == 2 var parent = args[0] var prototypeBuilder = args[1] } // special handling for Error objects var namePointer = {} // name used only for Error Objects if([Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError].indexOf(parent) !== -1) { parent = normalizeErrorObject(parent, namePointer) } // set up the parent into the prototype chain if a parent is passed var parentIsFunction = typeof(parent) === "function" if(parentIsFunction) { prototypeBuilder[prototypeName] = parent[prototypeName] } else { prototypeBuilder[prototypeName] = parent } // the prototype that will be used to make instances var prototype = new prototypeBuilder(parent) namePointer.name = prototype.name // if there's no init, assume its inheriting a non-proto class, so default to applying the superclass's constructor. if(!prototype[init] && parentIsFunction) { prototype[init] = function() { parent.apply(this, arguments) } } // constructor for empty object which will be populated via the constructor var F = function() {} F[prototypeName] = prototype // set the prototype for created instances var constructorName = prototype.name?prototype.name:'' if(prototype[init] === undefined || prototype[init] === noop) { var ProtoObjectFactory = new Function('F', "return function " + constructorName + "(){" + "return new F()" + "}" )(F) } else { // dynamically creating this function cause there's no other way to dynamically name a function var ProtoObjectFactory = new Function('F','i','u','n', // shitty variables cause minifiers aren't gonna minify my function string here "return function " + constructorName + "(){ " + "var x=new F(),r=i.apply(x,arguments)\n" + // populate object via the constructor "if(r===n)\n" + "return x\n" + "else if(r===u)\n" + "return n\n" + "else\n" + "return r\n" + "}" )(F, prototype[init], proto[protoUndefined]) // note that n is undefined } prototype.constructor = ProtoObjectFactory; // set the constructor property on the prototype // add all the prototype properties onto the static class as well (so you can access that class when you want to reference superclass properties) for(var n in prototype) { addProperty(ProtoObjectFactory, prototype, n) } // add properties from parent that don't exist in the static class object yet for(var n in parent) { if(ownProperty.call(parent, n) && ProtoObjectFactory[n] === undefined) { addProperty(ProtoObjectFactory, parent, n) } } ProtoObjectFactory.parent = parent; // special parent property only available on the returned proto class ProtoObjectFactory[prototypeName] = prototype // set the prototype on the object factory return ProtoObjectFactory; } proto[protoUndefined] = {} // a special marker for when you want to return undefined from a constructor module.exports = proto function normalizeErrorObject(ErrorObject, namePointer) { function NormalizedError() { var tmp = new ErrorObject(arguments[0]) tmp.name = namePointer.name this.message = tmp.message if(Object.defineProperty) { /*this.stack = */Object.defineProperty(this, 'stack', { // getter for more optimizy goodness get: function() { return tmp.stack }, configurable: true // so you can change it if you want }) } else { this.stack = tmp.stack } return this } var IntermediateInheritor = function() {} IntermediateInheritor.prototype = ErrorObject.prototype NormalizedError.prototype = new IntermediateInheritor() return NormalizedError } function addProperty(factoryObject, prototype, property) { try { var info = Object.getOwnPropertyDescriptor(prototype, property) if(info.get !== undefined || info.get !== undefined && Object.defineProperty !== undefined) { Object.defineProperty(factoryObject, property, info) } else { factoryObject[property] = prototype[property] } } catch(e) { // do nothing, if a property (like `name`) can't be set, just ignore it } } /***/ }), /* 2 */ /* unknown exports provided */ /* all exports used */ /*!*********************!*\ !*** ./EmitterB.js ***! \*********************/ /***/ (function(module, exports, __webpack_require__) { var EventEmitter = __webpack_require__(/*! events */ 0).EventEmitter var proto = __webpack_require__(/*! proto */ 1) module.exports = proto(EventEmitter, function(superclass) { this.init = function() { superclass.apply(this, arguments) this.ifonHandlers = {} this.ifoffHandlers = {} this.ifonAllHandlers = [] this.ifoffAllHandlers = [] } // callback will be triggered immediately if there is already a listener attached, or // callback will be triggered when the first listener for the event is added // (regardless of whether its done through on or once) // parameters can be: // event, callback - attach an ifon handler for the passed event // callback - attach an ifon handler for all events this.ifon = function(event, callback) { if(event instanceof Function) { // event not passed, only a callback callback = event // fix the argument for(var eventName in this._events) { if(this.listeners(eventName).length > 0) { callback(eventName) } } } else if(this.listeners(event).length > 0) { callback(event) } addHandlerToList(this, 'ifonHandlers', event, callback) } // removes either: // removeIfon() - all ifon handlers (if no arguments are passed), or // removeIfon(event) - all ifon handlers for the passed event, or // removeIfon(callback) - the passed ifon-all handler (if the first parameter is the callback) // removeIfon(event, callback) - the specific passed callback for the passed event this.removeIfon = function(event, callback) { removeFromHandlerList(this, 'ifonHandlers', event, callback) } // callback will be triggered when the last listener for the 'click' event is removed (will not trigger immediately if there is no event listeners on call of ifoff) // (regardless of whether this is done through removeListener or as a result of 'once' being fulfilled) // parameters can be: // event, callback - attach an ifoff handler for the passed event // callback - attach an ifoff handler for all events this.ifoff = function(event, callback) { addHandlerToList(this, 'ifoffHandlers', event, callback) } // removes either: // removeIfoff() - all ifoff handlers (if no arguments are passed), or // removeIfoff(event) - all ifoff handlers for the passed event, or // removeIfoff(callback) - the passed ifoff-all handler (if the first parameter is the callback) // removeIfoff(event, callback) - the specific passed callback for the passed event this.removeIfoff = function(event, callback) { removeFromHandlerList(this, 'ifoffHandlers', event, callback) } // emitter is the emitter to proxy handler binding to // options can have one of the following properties: // only - an array of events to proxy // except - an array of events to *not* proxy this.proxy = function(emitter, options) { if(options === undefined) options = {} if(options.except !== undefined) { var except = arrayToMap(options.except) var handleIt = function(event){return !(event in except)} } else if(options.only !== undefined) { var only = arrayToMap(options.only) var handleIt = function(event){return event in only} } else { var handleIt = function(){return true} } var that = this, handler; this.ifon(function(event) { if(handleIt(event)) { emitter.on(event, handler = function() { that.emit.apply(that, [event].concat(Array.prototype.slice.call(arguments))) }) } }) this.ifoff(function(event) { if(handleIt(event)) emitter.off(event, handler) }) } /*override*/ this.on = this.addListener = function(event, callback) { var triggerIfOn = this.listeners(event).length === 0 superclass.prototype.on.apply(this,arguments) if(triggerIfOn) triggerIfHandlers(this, 'ifonHandlers', event) } /*override*/ this.off = this.removeListener = function(event, callback) { var triggerIfOff = this.listeners(event).length === 1 superclass.prototype.removeListener.apply(this,arguments) if(triggerIfOff) triggerIfHandlers(this, 'ifoffHandlers', event) } /*override*/ this.removeAllListeners = function(event) { var triggerIfOffForEvents = [] if(event !== undefined) { if(this.listeners(event).length > 0) { triggerIfOffForEvents.push(event) } } else { for(var event in this._events) { if(this.listeners(event).length > 0) { triggerIfOffForEvents.push(event) } } } superclass.prototype.removeAllListeners.apply(this,arguments) for(var n=0; n<triggerIfOffForEvents.length; n++) { triggerIfHandlers(this, 'ifoffHandlers', triggerIfOffForEvents[n]) } } }) // triggers the if handlers from the normal list and the "all" list function triggerIfHandlers(that, handlerListName, event) { triggerIfHandlerList(that[handlerListName][event], event) triggerIfHandlerList(that[normalHandlerToAllHandlerProperty(handlerListName)], event) } // triggers the if handlers from a specific list // ya these names are confusing, sorry : ( function triggerIfHandlerList(handlerList, event) { if(handlerList !== undefined) { for(var n=0; n<handlerList.length; n++) { handlerList[n](event) } } } function addHandlerToList(that, handlerListName, event, callback) { if(event instanceof Function) { // correct arguments callback = event event = undefined } if(event !== undefined && callback !== undefined) { var handlerList = that[handlerListName][event] if(handlerList === undefined) { handlerList = that[handlerListName][event] = [] } handlerList.push(callback) } else { that[normalHandlerToAllHandlerProperty(handlerListName)].push(callback) } } function removeFromHandlerList(that, handlerListName, event, callback) { if(event instanceof Function) { // correct arguments callback = event event = undefined } if(event !== undefined && callback !== undefined) { removeCallbackFromList(that[handlerListName][event], callback) } else if(event !== undefined) { delete that[handlerListName][event] } else if(callback !== undefined) { var allHandlerListName = normalHandlerToAllHandlerProperty(handlerListName) removeCallbackFromList(that[allHandlerListName], callback) } else { var allHandlerListName = normalHandlerToAllHandlerProperty(handlerListName) that[handlerListName] = {} that[allHandlerListName] = [] } } function normalHandlerToAllHandlerProperty(handlerListName) { if(handlerListName === 'ifonHandlers') return 'ifonAllHandlers' if(handlerListName === 'ifoffHandlers') return 'ifoffAllHandlers' } function removeCallbackFromList(list, callback) { var index = list.indexOf(callback) list.splice(index,1) } function getTrace() { try { throw new Error() } catch(e) { return e } } // turns an array of values into a an object where those values are all keys that point to 'true' function arrayToMap(array) { var result = {} array.forEach(function(v) { result[v] = true }) return result } /***/ }) /******/ ]); }); //# sourceMappingURL=EmitterB.dev.umd.js.map