@nathanfaucett/event_emitter
Version:
EventEmitter for the browser and node.js
427 lines (346 loc) • 10.2 kB
JavaScript
var isFunction = require("@nathanfaucett/is_function"),
inherits = require("@nathanfaucett/inherits"),
apply = require("@nathanfaucett/apply"),
fastSlice = require("@nathanfaucett/fast_slice"),
keys = require("@nathanfaucett/keys"),
isNumber = require("@nathanfaucett/is_number"),
isNullOrUndefined = require("@nathanfaucett/is_null_or_undefined");
var EventEmitterPrototype;
module.exports = EventEmitter;
function EventEmitter(maxListeners) {
this._events = {};
this._maxListeners = isNumber(maxListeners)
? +maxListeners
: EventEmitter.defaultMaxListeners;
}
EventEmitterPrototype = EventEmitter.prototype;
EventEmitterPrototype.on = function(name, listener) {
var events, eventList, maxListeners;
if (!isFunction(listener)) {
throw new TypeError(
"EventEmitter.on(name, listener) listener must be a function"
);
}
events = this._events || (this._events = {});
eventList = events[name] || (events[name] = []);
maxListeners = this._maxListeners || -1;
eventList.push(listener);
if (maxListeners !== -1 && eventList.length > maxListeners) {
console.error(
"EventEmitter.on(type, listener) possible EventEmitter memory leak detected. " +
maxListeners +
" listeners added"
);
}
return this;
};
EventEmitterPrototype.addEventListener = EventEmitterPrototype.addListener =
EventEmitterPrototype.on;
EventEmitterPrototype.once = function(name, listener) {
var _this = this;
function once() {
var result = apply(listener, arguments, _this);
_this.off(name, once);
return result;
}
this.on(name, once);
return once;
};
EventEmitterPrototype.listenTo = function(value, name) {
var _this = this;
if (!value || !(isFunction(value.on) || isFunction(value.addListener))) {
throw new TypeError(
"EventEmitter.listenTo(value, name) value must have a on function taking (name, listener[, ctx])"
);
}
function handler() {
_this.emitArgs(name, arguments);
}
value.on(name, handler);
return handler;
};
EventEmitterPrototype.off = function(name, listener) {
var events = this._events || (this._events = {}),
eventList = events[name],
event,
i;
if (!eventList) {
return this;
} else {
if (!listener) {
i = eventList.length;
while (i--) {
this.emit("removeListener", name, eventList[i]);
}
delete events[name];
} else {
i = eventList.length;
while (i--) {
event = eventList[i];
if (event === listener) {
this.emit("removeListener", name, event);
eventList.splice(i, 1);
}
}
if (eventList.length === 0) {
delete events[name];
}
}
return this;
}
};
EventEmitterPrototype.removeEventListener = EventEmitterPrototype.removeListener =
EventEmitterPrototype.off;
EventEmitterPrototype.removeAllListeners = function() {
var events = this._events || (this._events = {}),
objectKeys = keys(events),
i = objectKeys.length,
key,
eventList,
j;
while (i--) {
key = objectKeys[i];
eventList = events[key];
if (eventList) {
j = eventList.length;
while (j--) {
this.emit("removeListener", key, eventList[j]);
}
delete events[key];
}
}
return this;
};
EventEmitterPrototype.dispatchEvent = function(event) {
return this.emitArg(event.type, event);
};
EventEmitterPrototype.attachEvent = function(type, listener) {
return this.on(type.slice(2), listener);
};
EventEmitterPrototype.detachEvent = function(type, listener) {
return this.off(type.slice(2), listener);
};
EventEmitterPrototype.fireEvent = function(type, event) {
return this.emitArg(type.slice(2), event);
};
function emit0(_this, eventList) {
var i = -1,
il = eventList.length - 1,
event;
while (i++ < il) {
if ((event = eventList[i])) {
event.call(_this);
}
}
}
function emit1(_this, eventList, a0) {
var i = -1,
il = eventList.length - 1,
event;
while (i++ < il) {
if ((event = eventList[i])) {
event.call(_this, a0);
}
}
}
function emit2(_this, eventList, args) {
var a0 = args[0],
a1 = args[1],
i = -1,
il = eventList.length - 1,
event;
while (i++ < il) {
if ((event = eventList[i])) {
event.call(_this, a0, a1);
}
}
}
function emit3(_this, eventList, args) {
var a0 = args[0],
a1 = args[1],
a2 = args[2],
i = -1,
il = eventList.length - 1,
event;
while (i++ < il) {
if ((event = eventList[i])) {
event.call(_this, a0, a1, a2);
}
}
}
function emit4(_this, eventList, args) {
var a0 = args[0],
a1 = args[1],
a2 = args[2],
a3 = args[3],
i = -1,
il = eventList.length - 1,
event;
while (i++ < il) {
if ((event = eventList[i])) {
event.call(_this, a0, a1, a2, a3);
}
}
}
function emit5(_this, eventList, args) {
var a0 = args[0],
a1 = args[1],
a2 = args[2],
a3 = args[3],
a4 = args[4],
i = -1,
il = eventList.length - 1,
event;
while (i++ < il) {
if ((event = eventList[i])) {
event.call(_this, a0, a1, a2, a3, a4);
}
}
}
function emitApply(_this, eventList, args) {
var i = -1,
il = eventList.length - 1,
event;
while (i++ < il) {
if ((event = eventList[i])) {
event.apply(_this, args);
}
}
}
function emit(_this, eventList, args) {
switch (args.length) {
case 0:
emit0(_this, eventList);
break;
case 1:
emit1(_this, eventList, args[0]);
break;
case 2:
emit2(_this, eventList, args);
break;
case 3:
emit3(_this, eventList, args);
break;
case 4:
emit4(_this, eventList, args);
break;
case 5:
emit5(_this, eventList, args);
break;
default:
emitApply(_this, eventList, args);
break;
}
}
EventEmitterPrototype.emitArg = function(name, arg) {
var eventList = (this._events || (this._events = {}))[name];
if (!eventList || !eventList.length) {
return this;
} else {
emit1(this, eventList, arg);
return this;
}
};
EventEmitterPrototype.emitArgs = function(name, args) {
var eventList = (this._events || (this._events = {}))[name];
if (!eventList || !eventList.length) {
return this;
} else {
emit(this, eventList, args);
return this;
}
};
EventEmitterPrototype.emit = function(name) {
return this.emitArgs(name, fastSlice(arguments, 1));
};
function emitAsync(_this, eventList, args, callback) {
var length = eventList.length,
index = 0,
called = false;
function next(error) {
if (called !== true) {
if (error || index === length) {
called = true;
callback(error);
} else {
apply(eventList[index++], args, _this);
}
}
}
args.push(next);
next();
}
EventEmitterPrototype.emitAsync = function(name) {
var eventList = (this._events || (this._events = {}))[name],
args = fastSlice(arguments, 1),
callback = args.pop();
if (!isFunction(callback)) {
throw new TypeError(
"EventEmitter.emitAsync(name [, ...args], callback) callback must be a function"
);
} else {
if (!eventList || !eventList.length) {
callback();
} else {
emitAsync(this, eventList, args, callback);
}
return this;
}
};
EventEmitterPrototype.listeners = function(name) {
var eventList = (this._events || (this._events = {}))[name];
return eventList ? eventList.slice() : [];
};
EventEmitterPrototype.listenerCount = function(name) {
var events = this._events,
eventList;
if (events) {
eventList = events[name];
return eventList ? eventList.length : 0;
} else {
return 0;
}
};
EventEmitterPrototype.setMaxListeners = function(value) {
if ((value = +value) !== value) {
throw new TypeError(
"EventEmitter.setMaxListeners(value) value must be a number"
);
}
this._maxListeners = value < 0 ? -1 : value;
return this;
};
inherits.defineProperty(EventEmitter, "defaultMaxListeners", 10);
inherits.defineProperty(EventEmitter, "listeners", function(value, name) {
var eventList;
if (isNullOrUndefined(value)) {
throw new TypeError(
"EventEmitter.listeners(value, name) value required"
);
}
eventList = value._events && value._events[name];
return eventList ? eventList.slice() : [];
});
inherits.defineProperty(EventEmitter, "listenerCount", function(value, name) {
var eventList;
if (isNullOrUndefined(value)) {
throw new TypeError(
"EventEmitter.listenerCount(value, name) value required"
);
}
eventList = value._events && value._events[name];
return eventList ? eventList.length : 0;
});
inherits.defineProperty(EventEmitter, "setMaxListeners", function(value) {
if ((value = +value) !== value) {
throw new TypeError(
"EventEmitter.setMaxListeners(value) value must be a number"
);
}
EventEmitter.defaultMaxListeners = value < 0 ? -1 : value;
return value;
});
EventEmitter.extend = function(child) {
inherits(child, this);
return child;
};