/* 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) {
var EventEmitter = require('./EventEmitter');
/**
* EventHandler extends EventEmitter to provide subscription methods.
* It also includes helper methods on the constructor for setting up Controllers and Views
* with input and output emitters.
*
* @example
*
* var eventHandlerA = new EventHandler();
* var eventHandlerB = new EventHandler();
*
* eventHandlerB.subscribe(eventHandlerA);
*
* eventHandlerB.on('name', function(payload){
* console.log(payload) // {data : 0}
* });
*
* eventHandlerA.emit('name', {data : 0});
*
* @class EventHandler
* @namespace Events
* @extends Events.EventEmitter
* @constructor
*/
function EventHandler() {
EventEmitter.apply(this, arguments);
this.upstream = []; // upstream event handlers
this.upstreamListeners = {}; // upstream listeners
}
EventHandler.prototype = Object.create(EventEmitter.prototype);
EventHandler.prototype.constructor = EventHandler;
/**
* Constructor helper method. Assign an event handler to receive an object's input events.
* Defines `trigger`, `subscribe` and `unsubscribe` methods on the class instance.
*
* @method setInputHandler
* @static
* @param object {Object} Class instance
* @param handler {EventHandler} EventHandler representing an input source
*/
EventHandler.setInputHandler = function setInputHandler(object, handler) {
object.trigger = handler.trigger.bind(handler);
object.subscribe = handler.subscribe.bind(handler);
object.unsubscribe = handler.unsubscribe.bind(handler);
};
/**
* Constructor helper method. Assign an event handler to emit an object's output events.
* Defines `emit`, `on` and `off` methods on the class instance.
*
* @method setOutputHandler
* @static
* @param object {Object} Object to provide on, off and emit methods
* @param handler {EventHandler} Handler assigned event handler
*/
EventHandler.setOutputHandler = function setOutputHandler(object, handler) {
handler.bindThis(object);
object.emit = handler.emit.bind(handler);
object.on = handler.on.bind(handler);
object.off = handler.off.bind(handler);
};
/**
* Constructor helper method. Given an events dictionary of {eventName : handler} pairs, attach them to
* a provided input handler for an object.
*
* @method setInputEvents
* @static
* @private
* @param object {Object} Object to provide on, off and emit methods
* @param handler {EventHandler} Handler assigned event handler
*/
EventHandler.setInputEvents = function setInputEvents(object, events, handlerIn){
for (var key in events) {
var handlerName = events[key];
var handler = (typeof handlerName === 'string')
? object[handlerName]
: handlerName;
if (handler) handlerIn.on(key, handler.bind(object));
}
};
/**
* Adds a handler to the `type` channel which will be executed on `emit`.
* Extends EventEmitter's `on` method.
*
* @method on
* @param type {String} Event channel name
* @param handler {Function} Handler
*/
EventHandler.prototype.on = function on(type, handler) {
EventEmitter.prototype.on.apply(this, arguments);
if (!(type in this.upstreamListeners)) {
var upstreamListener = this.trigger.bind(this, type);
this.upstreamListeners[type] = upstreamListener;
for (var i = 0; i < this.upstream.length; i++) {
this.upstream[i].on(type, upstreamListener);
}
}
};
/**
* Listen for events from an an upstream source.
*
* @method subscribe
* @param source {EventEmitter} Event source
*/
EventHandler.prototype.subscribe = function subscribe(source) {
var index = this.upstream.indexOf(source);
if (index < 0) {
this.upstream.push(source);
for (var type in this.upstreamListeners) {
source.on(type, this.upstreamListeners[type]);
}
}
return source;
};
/**
* Stop listening to events from an upstream source.
* Undoes work of `subscribe`.
*
* @method unsubscribe
* @param source {EventEmitter} Event source
*/
EventHandler.prototype.unsubscribe = function unsubscribe(source) {
var index = this.upstream.indexOf(source);
if (index >= 0) {
this.upstream.splice(index, 1);
for (var type in this.upstreamListeners) {
source.off(type, this.upstreamListeners[type]);
}
}
return source;
};
module.exports = EventHandler;
});