define(function(require) {
'use strict';
var Module = require('modules/base/module');
/**
* EventEmitter implements basic event emitting logics. It also provides
* function that augments the ability to other objects.
*
* @example
* var eventEmitter = EventEmitter(['event1', 'event2']);
* var eventHandler = function(event) {
* console.log(event.detail);
* };
* var obj = {
* handleEvent: function(event) {
* console.log(event.detail);
* }
* };
*
* eventEmitter.addEventListener('event1', eventHandler);
* eventEmitter.addEventListener('event2', obj);
*
* eventEmitter._emitEvent('event1', 'value1'); // value1
* eventEmitter._emitEvent('event2', 'value2'); // value2
*
* Extending from EventEmitter:
* @example
* var NewModule = Module.create(function() {
* this.super(EventEmitter).call(this, ['event1', 'event2']);
* }).extend(EventEmitter);
*
* var module = NewModule();
*
* @class EventEmitter
* @returns {EventEmitter}
*/
var EventEmitter = Module.create(function EventEmitter(eventNames) {
if (eventNames && eventNames.length) {
this._eventListeners = eventNames.reduce((result, eventName) => {
result[eventName] = [];
return result;
}, {});
} else {
this.throw('no valid registered events');
}
});
/**
* Emit an event of a specific type and a given value.
*
* @access private
* @memberOf EventEmitter.prototype
* @param {String} eventName
* @param {Object} value
*/
EventEmitter.prototype._emitEvent = function(eventName, value) {
var listeners = this._eventListeners[eventName];
if (!listeners) {
this.throw('invalid event name: ' + eventName);
}
this.debug('_emitEvent:' + eventName + ' ' + value);
var eventObj = {
type: eventName,
detail: value
};
listeners.forEach((listener) => {
listener.call(this, eventObj);
});
};
/**
* Add an event listener on an event. If listener is an object,
* object.handleEvent is called when the event emits.
*
* @access public
* @memberOf EventEmitter.prototype
* @param {String} eventName
* @param {(Function|Object)} listener
*/
EventEmitter.prototype.addEventListener = function(eventName, listener) {
var listeners = this._eventListeners[eventName];
if (listener && listeners) {
switch (typeof listener) {
case 'function':
break;
case 'object':
if (typeof listener.handleEvent === 'function') {
listener = listener.handleEvent;
} else {
listener = null;
}
break;
default:
listener = null;
break;
}
if (listener && listeners.indexOf(listener) < 0) {
listeners.push(listener);
}
} else {
this.error('addEventListener: invalid listener for ' + eventName);
}
};
/**
* Remove the event listener from an event.
*
* @access public
* @memberOf EventEmitter.prototype
* @param {String} eventName
* @param {(Function|Object)} listener
*/
EventEmitter.prototype.removeEventListener = function(eventName, listener) {
var listeners = this._eventListeners[eventName];
if (listener && listeners) {
var index = -1;
var type = typeof listener;
switch (type) {
case 'function':
index = listeners.indexOf(listener);
break;
case 'object':
index = listeners.indexOf(listener.handleEvent);
break;
}
if (index >= 0) {
listeners.splice(index, 1);
}
} else {
this.error('removeEventListener: invalid listener for ' + eventName);
}
};
return EventEmitter;
});