/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
/* Modified work copyright © 2015-2016 David Valdman */
define(function(require, exports, module) {
/**
* EventEmitter represents an asynchronous channel for broadcasting and receiving events.
*
* @example
*
* var eventEmitter = new EventEmitter();
*
* eventEmitter.on('send', function(payload){
* console.log(payload) // {data : 0}
* });
*
* // sometime later...
* eventEmitter.emit('send', {data : 0});
*
* @class EventEmitter
* @namespace Events
* @constructor
*/
function EventEmitter() {
this.listeners = {};
this._owner = this;
}
/**
* Broadcast an event on the `type` channel with an optional payload. This will call the handlers
* of all EventEmitters listening on the `type` channel with the (optional) data payload
* as its argument.
*
* @method emit
*
* @param type {String} Channel name
* @param data {Object} Payload
*/
EventEmitter.prototype.emit = function emit(type, data) {
if (data === false) return; // do not propagate
var handlers = this.listeners[type];
if (handlers) {
for (var i = 0; i < handlers.length; i++)
handlers[i].call(this._owner, data);
}
};
/**
* Alias for emit.
*
* @method trigger
*/
EventEmitter.prototype.trigger = EventEmitter.prototype.emit;
/**
* Adds a handler to the `type` channel which will be executed on `emit`.
*
* @method on
* @param type {String} Channel name
* @param handler {Function} Callback
*/
EventEmitter.prototype.on = function on(type, handler) {
if (!(type in this.listeners)) this.listeners[type] = [];
this.listeners[type].push(handler);
};
/**
* Behaves like `EventEmitter.prototype.on`, except the handler is only executed once.
*
* @method once
* @param type {String} Channel name (e.g., 'click')
* @param handler {Function} Callback
*/
EventEmitter.prototype.once = function once(type, handler){
var onceHandler = function(){
EventEmitter.prototype.off.call(this, type, onceHandler);
handler.apply(this, arguments);
}.bind(this);
this.on(type, onceHandler);
};
/**
* Removes the `handler` from the `type` channel. This undoes the work of `on`.
* If no type is provided, then all event listeners are removed.
* If a type is provided but no handler, then all listeners of that type are removed.
*
* @method off
* @param [type] {String} Channel name
* @param [handler] {Function} Callback
*/
EventEmitter.prototype.off = function off(type, handler) {
if (!type) {
this.listeners = {};
return;
}
var listener = this.listeners[type];
if (listener !== undefined) {
if (!handler) this.listeners[type] = []; // remove all listeners of given type
else {
var index = listener.indexOf(handler);
if (index >= 0) listener.splice(index, 1);
}
}
};
/**
* A convenience method to bind the provided object to all added handlers.
*
* @method bindThis
* @param owner {Object} Bound `this` context
*/
EventEmitter.prototype.bindThis = function bindThis(owner) {
this._owner = owner;
};
module.exports = EventEmitter;
});