File: src/BB.EventEmitter.js
/**
* A class for providing a basic event-based programming interface.
* Often used as a base class extended by other classes that require
* event based programming patterns.
* @module BB.EventEmitter
*/
define(['./BB'],
function( BB){
'use strict';
/**
* A class for providing a basic event-based programming interface.
* Often used as a base class extended by other classes that require
* event based programming patterns.
* @class BB.EventEmitter
* @constructor
* @example
* <code class="code prettyprint"><br>
* // SHOULD LOG LIKE:<br>
* // Fired "now" event 1457470144<br>
* // seconds since the unix epoch.<br>
* // Fired "often" event 1457470145 seconds since the unix epoch.<br>
* // Fired "often" event 1457470146 seconds since the unix epoch.<br>
* // Fired "often" event 1457470147 seconds since the unix epoch.<br>
* // Fired "often" event 1457470148 seconds since the unix epoch.<br>
* // Fired "later" event 1457470149 seconds since the unix epoch.<br>
* // Removed "often" event.<br>
* <br>
* var emitter = new BB.EventEmitter();<br>
*<br>
* emitter.createEvent('now');<br>
* emitter.createEvent('later');<br>
* emitter.createEvent('often');<br>
* <br>
* // because this 'now' callback was registered first<br>
* // it will be called first.<br>
* emitter.on('now', function(unixTimestamp) {<br>
* console.log('Fired "now" event ' + unixTimestamp);<br>
* });<br>
*<br>
* // this one will be called second.<br>
* emitter.on('now', function(unixTimestamp) {<br>
* console.log('seconds since the unix epoch.');<br>
* });<br>
*<br>
* emitter.on('often', function(unixTimestamp) {<br>
* console.log('Fired "often" event ' + unixTimestamp + ' seconds since the unix epoch.');<br>
* });<br>
*<br>
* emitter.on('later', function(unixTimestamp) {<br>
* console.log('Fired "later" event ' + unixTimestamp + ' seconds since the unix epoch.');<br>
* emitter.removeEvent('often');<br>
* console.log('Removed "often" event.');<br>
* });<br>
*<br>
* emitter.notify('now', Math.floor(Date.now() / 1000));<br>
*<br>
* setTimeout(function(){ emitter.notify('later', Math.floor(Date.now() / 1000)) }, 5000);<br>
* setInterval(function(){ emitter.notify('often', Math.floor(Date.now() / 1000)) }, 1000);<br>
*<br>
* </code>
*/
BB.EventEmitter = function() {
this._eventStack = {};
};
/**
* Create a new event. This event can then have callbacks registered to it
* with on() and trigger those callbacks with notify().
*
* __Note__: if eventName
* has already been created this function does nothing.
* @method createEvent
* @param {String} eventName The name of the event.
*/
BB.EventEmitter.prototype.createEvent = function(eventName) {
if (typeof eventName !== 'string') {
throw new Error('BB.EventEmitter.createEvent(): eventName parameter must be provided as a string.');
}
if (!(this._eventStack[eventName] instanceof Array)) {
this._eventStack[eventName] = [];
}
};
/**
* Register a callback function to an event.
*
* __Note__: callback functions
* registered with on() will be called via notify() with a "this" variable
* bound to the event emitter itself independent of the function call
* context.
* @method on
* @param {String} eventName The name of the event to register the
* callback to.
* @param {Function} callback The callback function to call when the event
* is notified.
* @return {Boolean} True if the callback was successfully
* registered to the event.
*/
BB.EventEmitter.prototype.on = function(eventName, callback) {
if (typeof eventName !== 'string') {
throw new Error('BB.EventEmitter.on(): eventName parameter must be provided as a string.');
}
if (typeof callback !== 'function') {
throw new Error('BB.EventEmitter.on(): callback parameter must be a function.');
}
if (this._eventStack.hasOwnProperty(eventName) && typeof callback === 'function') {
this._eventStack[eventName].push(callback);
return true;
} else return false;
};
/**
* Notify an event by name, causing all callbacks registered to that event
* to be called in the order they were registered. Any arguments included in
* this function call after eventName will be passed directly to each
* callback that has been registered to this event.
* @method notify
* @param {String} eventName The event to notify.
* @param {Arguments} [arguments] Any arguments included in this function
* call after eventName will be passed directly to each callback that has
* been registered to this event.
* @return {Boolean} True if at least one callback function was
* called.
*/
BB.EventEmitter.prototype.notify = function(eventName) {
if (typeof eventName !== 'string') {
throw new Error('BB.EventEmitter.notify(): eventName parameter must be provided as a string.');
}
if (this._eventStack.hasOwnProperty(eventName)) {
for (var i = 0; i < this._eventStack[eventName].length; i++) {
// potential trap, this now equals instance of
// PianoRoll no matter where it is called from
this._eventStack[eventName][i].apply(this,
Array.prototype.slice.call(arguments, 1));
}
return this._eventStack[eventName].length > 0;
}
return false;
};
/**
* Remove an event by name. This function also removes all registered
* callbacks to that event.
* @method removeEvent
* @param {String} eventName The name of the event to remove.
* @return {Boolean} True if the event existed and was removed.
*/
BB.EventEmitter.prototype.removeEvent = function(eventName) {
if (this._eventStack.hasOwnProperty(eventName)) {
delete this._eventStack[eventName];
return true;
}
return false;
};
/**
* Remove a callback registered to an event by index.
* @method removeEventCallbackAtIndex
* @param {[type]} eventName The name of the event to remove a callback
* from.
* @param {[type]} index The index of that callback starting at 0
* (counting up in the order the callbacks were registered). Negative
* numbers remove from the internal event array starting at the back (e.g.
* -1 removes the callback most recently registered).
* @return {[type]} Returns the callback function if one was
* succesfully removed or false otherwise.
*/
BB.EventEmitter.prototype.removeEventCallbackAtIndex = function(eventName, index) {
if (typeof eventName !== 'string') {
throw new Error('BB.EventEmitter.removeEventAtIndex(): eventName parameter must be provided as a string.');
}
if (typeof eventName !== 'number') {
throw new Error('BB.EventEmitter.index(): index parameter must be a number type.');
}
if (this._eventStack[eventName] instanceof Array && index > 0) {
return this._eventStack[eventName].splice(index, 1);
}
return false;
};
return BB.EventEmitter;
});