Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
108 additions
and
320 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,294 +1,71 @@ | ||
(function (exports) { | ||
// Backbone.Events | ||
// ----------------- | ||
|
||
/** | ||
* ## Events module | ||
* | ||
* This is a browser port of the node.js events module. Many objects and | ||
* modules emit events and these are instances of events.EventEmitter. | ||
* | ||
* You can access this module by doing: `require("events")` | ||
* | ||
* Functions can then be attached to objects, to be executed when an event is | ||
* emitted. These functions are called listeners. | ||
* | ||
* @module | ||
*/ | ||
|
||
|
||
var EventEmitter = exports.EventEmitter = function () {}; | ||
|
||
var isArray = Array.isArray || function (obj) { | ||
return toString.call(obj) === '[object Array]'; | ||
}; | ||
|
||
|
||
/** | ||
* By default EventEmitters will print a warning if more than 10 listeners are | ||
* added for a particular event. 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. | ||
* | ||
* @name emitter.setMaxListeners(n) | ||
* @param {Number} n - The maximum number of listeners | ||
* @api public | ||
*/ | ||
|
||
// 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. | ||
// A module that can be mixed in to *any object* in order to provide it with | ||
// custom events. You may `bind` or `unbind` a callback function to an event; | ||
// `trigger`-ing an event fires all callbacks in succession. | ||
// | ||
// Obviously not all Emitters should be limited to 10. This function allows | ||
// that to be increased. Set to zero for unlimited. | ||
var defaultMaxListeners = 10; | ||
EventEmitter.prototype.setMaxListeners = function(n) { | ||
if (!this._events) this._events = {}; | ||
this._events.maxListeners = n; | ||
}; | ||
|
||
|
||
/** | ||
* Execute each of the listeners in order with the supplied arguments. | ||
* | ||
* @name emitter.emit(event, [arg1], [arg2], [...]) | ||
* @param {String} event - The event name/id to fire | ||
* @api public | ||
*/ | ||
|
||
EventEmitter.prototype.emit = function(type) { | ||
// If there is no 'error' event listener then throw. | ||
if (type === 'error') { | ||
if (!this._events || !this._events.error || | ||
(isArray(this._events.error) && !this._events.error.length)) | ||
{ | ||
if (arguments[1] instanceof Error) { | ||
throw arguments[1]; // Unhandled 'error' event | ||
} else { | ||
throw new Error("Uncaught, unspecified 'error' event."); | ||
} | ||
return false; | ||
} | ||
} | ||
|
||
if (!this._events) return false; | ||
var handler = this._events[type]; | ||
if (!handler) return false; | ||
|
||
if (typeof handler == 'function') { | ||
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: | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
handler.apply(this, args); | ||
} | ||
return true; | ||
|
||
} else if (isArray(handler)) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
|
||
var listeners = handler.slice(); | ||
for (var i = 0, l = listeners.length; i < l; i++) { | ||
listeners[i].apply(this, args); | ||
} | ||
return true; | ||
|
||
} else { | ||
return false; | ||
} | ||
}; | ||
|
||
|
||
/** | ||
* Adds a listener to the end of the listeners array for the specified event. | ||
* | ||
* @name emitter.on(event, listener) | emitter.addListener(event, listener) | ||
* @param {String} event - The event name/id to listen for | ||
* @param {Function} listener - The function to bind to the event | ||
* @api public | ||
* | ||
* ```javascript | ||
* session.on('change', function (userCtx) { | ||
* console.log('session changed!'); | ||
* }); | ||
* ``` | ||
*/ | ||
|
||
// EventEmitter is defined in src/node_events.cc | ||
// EventEmitter.prototype.emit() is also defined there. | ||
EventEmitter.prototype.addListener = function(type, listener) { | ||
if ('function' !== typeof listener) { | ||
throw new Error('addListener only takes instances of Function'); | ||
} | ||
|
||
if (!this._events) this._events = {}; | ||
|
||
// 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._events[type]) { | ||
// Optimize the case of one listener. Don't need the extra array object. | ||
this._events[type] = listener; | ||
} else if (isArray(this._events[type])) { | ||
|
||
// Check for listener leak | ||
if (!this._events[type].warned) { | ||
var m; | ||
if (this._events.maxListeners !== undefined) { | ||
m = this._events.maxListeners; | ||
} else { | ||
m = defaultMaxListeners; | ||
// var object = {}; | ||
// _.extend(object, Backbone.Events); | ||
// object.bind('expand', function(){ alert('expanded'); }); | ||
// object.trigger('expand'); | ||
// | ||
Events = { | ||
|
||
// Bind an event, specified by a string name, `ev`, to a `callback` function. | ||
// Passing `"all"` will bind the callback to all events fired. | ||
bind : function(ev, callback, context) { | ||
var calls = this._callbacks || (this._callbacks = {}); | ||
var list = calls[ev] || (calls[ev] = []); | ||
list.push([callback, context]); | ||
return this; | ||
}, | ||
|
||
// Remove one or many callbacks. If `callback` is null, removes all | ||
// callbacks for the event. If `ev` is null, removes all bound callbacks | ||
// for all events. | ||
unbind : function(ev, callback) { | ||
var calls; | ||
if (!ev) { | ||
this._callbacks = {}; | ||
} else if (calls = this._callbacks) { | ||
if (!callback) { | ||
calls[ev] = []; | ||
} else { | ||
var list = calls[ev]; | ||
if (!list) return this; | ||
for (var i = 0, l = list.length; i < l; i++) { | ||
if (list[i] && callback === list[i][0]) { | ||
list[i] = null; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
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(); | ||
return this; | ||
}, | ||
|
||
// Trigger an event, firing all bound callbacks. Callbacks are passed the | ||
// same arguments as `trigger` is, apart from the event name. | ||
// Listening for `"all"` passes the true event name as the first argument. | ||
trigger : function(eventName) { | ||
var list, calls, ev, callback, args; | ||
var both = 2; | ||
if (!(calls = this._callbacks)) return this; | ||
while (both--) { | ||
ev = both ? eventName : 'all'; | ||
if (list = calls[ev]) { | ||
for (var i = 0, l = list.length; i < l; i++) { | ||
if (!(callback = list[i])) { | ||
list.splice(i, 1); i--; l--; | ||
} else { | ||
args = both ? Array.prototype.slice.call(arguments, 1) : arguments; | ||
callback[0].apply(callback[1] || this, args); | ||
} | ||
} | ||
} | ||
} | ||
return this; | ||
} | ||
|
||
// 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]; | ||
} | ||
|
||
return this; | ||
}; | ||
|
||
EventEmitter.prototype.on = EventEmitter.prototype.addListener; | ||
|
||
/** | ||
* Adds a one time listener for the event. This listener is invoked only the | ||
* next time the event is fired, after which it is removed. | ||
* | ||
* @name emitter.once(event, listener) | ||
* @param {String} event- The event name/id to listen for | ||
* @param {Function} listener - The function to bind to the event | ||
* @api public | ||
* | ||
* ```javascript | ||
* db.once('unauthorized', function (req) { | ||
* // this event listener will fire once, then be unbound | ||
* }); | ||
* ``` | ||
*/ | ||
|
||
EventEmitter.prototype.once = function(type, listener) { | ||
var self = this; | ||
self.on(type, function g() { | ||
self.removeListener(type, g); | ||
listener.apply(this, arguments); | ||
}); | ||
|
||
return this; | ||
}; | ||
|
||
/** | ||
* Remove a listener from the listener array for the specified event. Caution: | ||
* changes array indices in the listener array behind the listener. | ||
* | ||
* @name emitter.removeListener(event, listener) | ||
* @param {String} event - The event name/id to remove the listener from | ||
* @param {Function} listener - The listener function to remove | ||
* @api public | ||
* | ||
* ```javascript | ||
* var callback = function (init) { | ||
* console.log('duality app loaded'); | ||
* }; | ||
* devents.on('init', callback); | ||
* // ... | ||
* devents.removeListener('init', callback); | ||
* ``` | ||
*/ | ||
|
||
EventEmitter.prototype.removeListener = function(type, listener) { | ||
if ('function' !== typeof listener) { | ||
throw new Error('removeListener only takes instances of Function'); | ||
} | ||
|
||
// does not use listeners(), so no side effect of creating _events[type] | ||
if (!this._events || !this._events[type]) return this; | ||
|
||
var list = this._events[type]; | ||
|
||
if (isArray(list)) { | ||
var i = list.indexOf(listener); | ||
if (i < 0) return this; | ||
list.splice(i, 1); | ||
if (list.length == 0) | ||
delete this._events[type]; | ||
} else if (this._events[type] === listener) { | ||
delete this._events[type]; | ||
} | ||
|
||
return this; | ||
}; | ||
|
||
/** | ||
* Removes all listeners, or those of the specified event. | ||
* | ||
* @name emitter.removeAllListeners([event]) | ||
* @param {String} event - Event name/id to remove all listeners for (optional) | ||
* @api public | ||
*/ | ||
|
||
EventEmitter.prototype.removeAllListeners = function(type) { | ||
// does not use listeners(), so no side effect of creating _events[type] | ||
if (type && this._events && this._events[type]) this._events[type] = null; | ||
return this; | ||
}; | ||
|
||
/** | ||
* Returns an array of listeners for the specified event. This array can be | ||
* manipulated, e.g. to remove listeners. | ||
* | ||
* @name emitter.listeners(event) | ||
* @param {String} events - The event name/id to return listeners for | ||
* @api public | ||
* | ||
* ```javascript | ||
* session.on('change', function (stream) { | ||
* console.log('session changed'); | ||
* }); | ||
* console.log(util.inspect(session.listeners('change'))); // [ [Function] ] | ||
* ``` | ||
*/ | ||
|
||
EventEmitter.prototype.listeners = function(type) { | ||
if (!this._events) this._events = {}; | ||
if (!this._events[type]) this._events[type] = []; | ||
if (!isArray(this._events[type])) { | ||
this._events[type] = [this._events[type]]; | ||
} | ||
return this._events[type]; | ||
}; | ||
|
||
|
||
/** | ||
* @name emitter Event: 'newListener' | ||
* | ||
* This event is emitted any time someone adds a new listener. | ||
* | ||
* ```javascript | ||
* emitter.on('newListener', function (event, listener) { | ||
* // new listener added | ||
* }); | ||
* ``` | ||
*/ | ||
|
||
}(window)); | ||
}; |
Oops, something went wrong.