Skip to content

Instantly share code, notes, and snippets.

@couto
Created July 28, 2013 19:06
Show Gist options
  • Save couto/6099712 to your computer and use it in GitHub Desktop.
Save couto/6099712 to your computer and use it in GitHub Desktop.
define([
//<validation>
'mout/lang/isString',
'mout/lang/isFunction',
'mout/lang/isBoolean',
//</validation>
'mout/lang/toArray'
], function (
//<validation>
isString,
isFunction,
isBoolean,
//</validation>
toArray
) {
'use strict';
/**
* clear all events from the instance
*
* @api private
* @param {EventEmitter} instance
* @return {EventEmitter}
*/
var clearAll = function (instance) {
instance.__events = {};
return instance;
},
/**
* clear all events with the given name, from the instance
*
* @api private
* @param {String} name event name
* @param {EventEmitter} instance
* @return {EventEmitter}
*/
clearName = function (name, instance) {
instance.__events[name] = [];
return instance;
};
/**
* EventEmitter
*
* var emitter = new EventEmiiter();
*
* emitter.on(superAwesomeEvent, function () {
* destroyTheWorld('zombies');
* });
*
* emitter.emit('superAwesomeEvent', 42, 'meaning of life')
*
* @constructor
*/
function EventEmitter() {
this.__events = {};
}
EventEmitter.prototype = {
/**
* on
* Add an event listener. If the ctx argument is a boolean (true)
* the event will only be called once.
*
* emitter.on('firsTime', function () {
* console.log('Called!')
* }, true);
*
* emitter.emit('firstTime'); // Called!
* emitter.emit('firstTime'); // undefined
*
* @param {String} name event name
* @param {Function} fn function that will be called
* @param {Boolean} [once] if true, the event will be removed after being called once
* @chainable
*/
on: function (name, fn, once) {
//<validation>
if (!isString(name)) {
throw new TypeError('EventEmitter#on requires first argument to be a string.');
}
if (!isFunction(fn)) {
throw new TypeError('EventEmitter#on requires second argument to be a function.');
}
if (once && !isBoolean(once)) {
throw new TypeError('EventEmitter#on requires third argument to be a boolean, if given.');
}
//</validation>
// Create an array to save all handlers for that one.
this.__events[name] = this.__events[name] || [];
// Save the handler to the array
this.__events[name].push({
fn: fn,
once: !!once
});
return this;
},
/**
* off
* Remove an event listener
*
* @param {[type]} name [description]
* @param {Function} fn [description]
* @chainable
*/
off: function (name, fn) {
var current = this.__events[name],
i = 0;
//<validation>
if (name && !isString(name)) {
throw new TypeError('EventEmitter#off requires first argument to be a string, if present.');
}
if (fn && !isFunction(fn)) {
throw new TypeError('EventEmitter#off requires second argument to be a function, is present.');
}
if (name && !current) {
throw new ReferenceError('EventEmitter#off requires event to exist before trying to remove it');
}
//</validation>
// if no arguments are given, clear all events
if (!toArray(arguments).length) { return clearAll(this); }
// If no function is given, remove all listeners for the
// given name
if (!fn) { return clearName(name, this); }
// Go through all handlers for the current
// event, and call them with the given arguments
i = current.length - 1;
for (i; i >= 0; i -= 1) {
if (current[i].fn === fn) {
current.splice(i, 1);
}
}
return this;
},
/**
* emit
*
* @param {String} name event name
* @param {Mixed} [args]*
* @chainable
*/
emit: function (name, args) {
var current = this.__events[name],
i = 0,
len = 0;
//<validation>
if (!isString(name)) {
throw new TypeError('EventEmitter#emit requires first argument to be a string.');
}
//</validation>
// Get all arguments
args = [].slice.call(arguments, 1);
if (current) {
len = current.length;
for (i; i < len; i += 1) {
current[i].fn.apply(this, args);
// Check if this function was marked as a run once only
if (current[i].once) {
this.off(name, current[i].fn);
// Since we removed a handler
// we need to adapt our counter and length
i -= 1;
len = current.length;
}
}
}
return this;
}
};
return EventEmitter;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment