modularjs
Version:
Library for building events based apps
248 lines (214 loc) • 6.58 kB
JavaScript
var EventEmitter = function(){
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;
}
this.before = function(type, listener){
if (!this._before)
this._before = {};
if (!this._before[type])
// Optimize the case of one listener. Don't need the extra array object.
this._before[type] = listener;
else if (isObject(this._before[type]))
// If we've already got an array, just append.
this._before[type].push(listener);
else
// Adding the second element, need to change to array.
this._before[type] = [this._before[type], listener];
// Check for listener leak
if (isObject(this._before[type]) && !this._before[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
}
else {
m = this.defaultMaxListeners;
}
if (m && m > 0 && this._before[type].length > m) {
this._before[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._before[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
this.after = function(type, listener){
if (!this._after)
this._after = {};
if (!this._after[type])
// Optimize the case of one listener. Don't need the extra array object.
this._after[type] = listener;
else if (isObject(this._after[type]))
// If we've already got an array, just append.
this._after[type].push(listener);
else
// Adding the second element, need to change to array.
this._after[type] = [this._after[type], listener];
// Check for listener leak
if (isObject(this._after[type]) && !this._after[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
}
else {
m = this.defaultMaxListeners;
}
if (m && m > 0 && this._after[type].length > m) {
this._after[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._after[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
this.emit = function(type) {
var er, handler, len, args, i, listeners, beforeHandler;
if (!this._events)
this._events = {};
if (!this._before)
this._before = {};
if (!this._after)
this._after = {};
// 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
}
throw TypeError('Uncaught, unspecified "error" event.');
}
}
handler = this._events[type];
beforeHandler = this._before[type];
afterHandler = this._after[type];
if (isUndefined(handler))
return false;
//Call before event
if (!isUndefined(beforeHandler)){
if (isFunction(beforeHandler)) {
switch (arguments.length) {
// fast cases
case 1:
beforeHandler.call(this);
break;
case 2:
beforeHandler.call(this, arguments[1]);
break;
case 3:
beforeHandler.call(this, 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];
beforeHandler.apply(this, args);
}
}
else if (isObject(beforeHandler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = beforeHandler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
}
//Call on event
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:
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, 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++)
listeners[i].apply(this, args);
}
//Call after event
if (!isUndefined(afterHandler)){
if (isFunction(afterHandler)) {
switch (arguments.length) {
// fast cases
case 1:
afterHandler.call(this);
break;
case 2:
afterHandler.call(this, arguments[1]);
break;
case 3:
afterHandler.call(this, 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];
afterHandler.apply(this, args);
}
}
else if (isObject(afterHandler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = afterHandler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
}
return true;
};
this._before = {};
this._after = {};
}
var Events = require('events');
EventEmitter.prototype = new Events();
module.exports = new EventEmitter();