irrelon-reactor-autonet
Version:
A module for automatically creating groups of self-networking services.
533 lines (449 loc) • 15.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _BaseClass2 = require('./BaseClass');
var _BaseClass3 = _interopRequireDefault(_BaseClass2);
var _Overload = require('./Overload');
var _Overload2 = _interopRequireDefault(_Overload);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var EventMethods = {
on: new _Overload2.default({
/**
* Attach an event listener to the passed event.
* @param {String} event The name of the event to listen for.
* @param {Function} listener The method to call when the event is fired.
*/
'string, function': function stringFunction(event, listener) {
this._listeners = this._listeners || {};
this._listeners[event] = this._listeners[event] || {};
this._listeners[event]['*'] = this._listeners[event]['*'] || [];
this._listeners[event]['*'].push(listener);
return this;
},
/**
* Attach an event listener to the passed event only if the passed
* id matches the document id for the event being fired.
* @param {String} event The name of the event to listen for.
* @param {*} id The document id to match against.
* @param {Function} listener The method to call when the event is fired.
*/
'string, *, function': function stringFunction(event, id, listener) {
this._listeners = this._listeners || {};
this._listeners[event] = this._listeners[event] || {};
this._listeners[event][id] = this._listeners[event][id] || [];
this._listeners[event][id].push(listener);
return this;
}
}),
once: new _Overload2.default({
/**
* Attach an event listener to the passed event which will only fire once.
* @param {String} event The name of the event to listen for.
* @param {Function} listener The method to call when the event is fired.
*/
'string, function': function stringFunction(event, listener) {
var self = this,
fired = false,
internalCallback = function internalCallback() {
if (!fired) {
fired = true;
self.off(event, internalCallback);
listener.apply(self, arguments);
}
};
return this.on(event, internalCallback);
},
/**
* Attach an event listener to the passed event only if the passed
* id matches the document id for the event being fired.
* @param {String} event The name of the event to listen for.
* @param {*} id The document id to match against.
* @param {Function} listener The method to call when the event is fired.
*/
'string, *, function': function stringFunction(event, id, listener) {
var self = this,
fired = false,
internalCallback = function internalCallback() {
if (!fired) {
fired = true;
self.off(event, id, internalCallback);
listener.apply(self, arguments);
}
};
return this.on(event, id, internalCallback);
}
}),
off: new _Overload2.default({
/**
* Cancels all event listeners for the passed event.
* @param {String} event The name of the event.
* @returns {*}
*/
'string': function string(event) {
var self = this;
if (this._emitting) {
this._eventRemovalQueue = this._eventRemovalQueue || [];
this._eventRemovalQueue.push(function () {
self.off(event);
});
} else {
if (this._listeners && this._listeners[event]) {
delete this._listeners[event];
}
}
return this;
},
/**
* Cancels the event listener for the passed event and listener function.
* @param {String} event The event to cancel listener for.
* @param {Function} listener The event listener function used in the on()
* or once() call to cancel.
* @returns {*}
*/
'string, function': function stringFunction(event, listener) {
var self = this,
arr,
index;
if (this._emitting) {
this._eventRemovalQueue = this._eventRemovalQueue || [];
this._eventRemovalQueue.push(function () {
self.off(event, listener);
});
} else {
if (typeof listener === 'string') {
if (this._listeners && this._listeners[event] && this._listeners[event][listener]) {
delete this._listeners[event][listener];
}
} else {
if (this._listeners && this._listeners[event]) {
arr = this._listeners[event]['*'];
index = arr.indexOf(listener);
if (index > -1) {
arr.splice(index, 1);
}
}
}
}
return this;
},
/**
* Cancels an event listener based on an event name, id and listener function.
* @param {String} event The event to cancel listener for.
* @param {String} id The ID of the event to cancel listening for.
* @param {Function} listener The event listener function used in the on()
* or once() call to cancel.
*/
'string, *, function': function stringFunction(event, id, listener) {
var self = this;
if (this._emitting) {
this._eventRemovalQueue = this._eventRemovalQueue || [];
this._eventRemovalQueue.push(function () {
self.off(event, id, listener);
});
} else {
if (this._listeners && this._listeners[event] && this._listeners[event][id]) {
var arr = this._listeners[event][id],
index = arr.indexOf(listener);
if (index > -1) {
arr.splice(index, 1);
}
}
}
},
/**
* Cancels all listeners for an event based on the passed event name and id.
* @param {String} event The event name to cancel listeners for.
* @param {*} id The ID to cancel all listeners for.
*/
'string, *': function string(event, id) {
var self = this;
if (this._emitting) {
this._eventRemovalQueue = this._eventRemovalQueue || [];
this._eventRemovalQueue.push(function () {
self.off(event, id);
});
} else {
if (this._listeners && this._listeners[event] && this._listeners[event][id]) {
// Kill all listeners for this event id
delete this._listeners[event][id];
}
}
}
}),
emit: new _Overload2.default({
/**
* Emit an event.
* @param {String} event The event to emit.
* @returns {*}
*/
'string': function string(event) {
// Fire global listeners
return this.$main(event);
},
/**
* Emit an event with data.
* @param {String} event The event to emit.
* @param {*} data Data to emit with the event.
* @returns {*}
*/
'string, ...': function string(event, data) {
// Fire global listeners first
this.$main.apply(this, arguments);
return this;
},
/**
* Handles emitting events, is an internal method not called directly.
* @param {String} event The name of the event to emit.
* @param {*} data The data to emit with the event.
* @returns {*}
* @private
*/
'$main': function $main(event, data) {
var id = '*';
this._listeners = this._listeners || {};
this._emitting = true;
if (this._listeners[event]) {
var arrIndex, arrCount, tmpFunc, arr;
// Handle global emit
if (this._listeners[event][id]) {
arr = this._listeners[event][id];
arrCount = arr.length;
for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
// Check we have a function to execute
tmpFunc = arr[arrIndex];
if (typeof tmpFunc === 'function') {
tmpFunc.apply(this, Array.prototype.slice.call(arguments, 1));
}
}
}
}
this._emitting = false;
this._processRemovalQueue();
return this;
}
}),
emitId: new _Overload2.default({
'string': function string(event) {
throw 'Missing id from emitId call!';
},
'string, *': function string(event, id) {
return this.$main(event, id);
},
'string, *, ...': function string(event, id) {
// Fire global listeners first
this.$main.apply(this, arguments);
return this;
},
'$main': function $main(event, id, data) {
this._listeners = this._listeners || {};
this._emitting = true;
if (this._listeners[event]) {
var arrIndex, arrCount, tmpFunc, arr;
// Handle global emit
if (this._listeners[event]['*']) {
arr = this._listeners[event]['*'];
arrCount = arr.length;
for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
// Check we have a function to execute
tmpFunc = arr[arrIndex];
if (typeof tmpFunc === 'function') {
tmpFunc.apply(this, Array.prototype.slice.call(arguments, 2));
}
}
}
// Handle id emit
if (this._listeners[event][id]) {
arr = this._listeners[event][id];
arrCount = arr.length;
for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
// Check we have a function to execute
tmpFunc = arr[arrIndex];
if (typeof tmpFunc === 'function') {
tmpFunc.apply(this, Array.prototype.slice.call(arguments, 2));
}
}
}
}
this._emitting = false;
this._processRemovalQueue();
return this;
}
}),
/**
* Checks if an event has any event listeners or not.
* @param {String} event The name of the event to check for.
* @returns {boolean} True if one or more event listeners are registered for
* the event. False if none are found.
*/
willEmit: function willEmit(event) {
var id = '*';
if (this._listeners && this._listeners[event]) {
var arrIndex, arrCount, tmpFunc, arr;
// Handle global emit
if (this._listeners[event][id]) {
arr = this._listeners[event][id];
arrCount = arr.length;
for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
// Check we have a function to execute
tmpFunc = arr[arrIndex];
if (typeof tmpFunc === 'function') {
return true;
}
}
}
}
return false;
},
/**
* Checks if an event has any event listeners or not based on the passed id.
* @param {String} event The name of the event to check for.
* @param {String} id The event ID to check for.
* @returns {boolean} True if one or more event listeners are registered for
* the event. False if none are found.
*/
willEmitId: function willEmitId(event, id) {
if (this._listeners && this._listeners[event]) {
var arrIndex, arrCount, tmpFunc, arr;
// Handle global emit
if (this._listeners[event]['*']) {
arr = this._listeners[event]['*'];
arrCount = arr.length;
for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
// Check we have a function to execute
tmpFunc = arr[arrIndex];
if (typeof tmpFunc === 'function') {
return true;
}
}
}
// Handle id emit
if (this._listeners[event][id]) {
arr = this._listeners[event][id];
arrCount = arr.length;
for (arrIndex = 0; arrIndex < arrCount; arrIndex++) {
// Check we have a function to execute
tmpFunc = arr[arrIndex];
if (typeof tmpFunc === 'function') {
return true;
}
}
}
}
return false;
},
/**
* If events are cleared with the off() method while the event emitter is
* actively processing any events then the off() calls get added to a
* queue to be executed after the event emitter is finished. This stops
* errors that might occur by potentially modifying the event queue while
* the emitter is running through them. This method is called after the
* event emitter is finished processing.
* @private
*/
_processRemovalQueue: function _processRemovalQueue() {
var i;
if (this._eventRemovalQueue && this._eventRemovalQueue.length) {
// Execute each removal call
for (i = 0; i < this._eventRemovalQueue.length; i++) {
this._eventRemovalQueue[i]();
}
// Clear the removal queue
this._eventRemovalQueue = [];
}
},
/**
* Queues an event to be fired. This has automatic de-bouncing so that any
* events of the same type that occur within 100 milliseconds of a previous
* one will all be wrapped into a single emit rather than emitting tons of
* events for lots of chained inserts etc. Only the data from the last
* de-bounced event will be emitted.
* @param {String} eventName The name of the event to emit.
* @param {*=} data Optional data to emit with the event.
*/
deferEmit: function deferEmit(eventName, data) {
var self = this,
args;
if (!this._noEmitDefer && (!this._db || this._db && !this._db._noEmitDefer)) {
args = arguments;
// Check for an existing timeout
this._deferTimeout = this._deferTimeout || {};
if (this._deferTimeout[eventName]) {
clearTimeout(this._deferTimeout[eventName]);
}
// Set a timeout
this._deferTimeout[eventName] = setTimeout(function () {
self.emit.apply(self, args);
}, 1);
} else {
this.emit.apply(this, arguments);
}
return this;
}
};
/**
* Provides event emitter functionality including the methods:
* on, off, once, emit, deferEmit.
*/
var EventEmitter = function (_BaseClass) {
_inherits(EventEmitter, _BaseClass);
function EventEmitter(name) {
_classCallCheck(this, EventEmitter);
// Define the object that will keep track of listeners
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(EventEmitter).call(this, name));
_this._listeners = {};
return _this;
}
_createClass(EventEmitter, [{
key: 'on',
get: function get() {
return EventMethods.on;
}
}, {
key: 'once',
get: function get() {
return EventMethods.once;
}
}, {
key: 'off',
get: function get() {
return EventMethods.off;
}
}, {
key: 'emit',
get: function get() {
return EventMethods.emit;
}
}, {
key: 'emitId',
get: function get() {
return EventMethods.emitId;
}
}, {
key: 'deferEmit',
get: function get() {
return EventMethods.deferEmit;
}
}, {
key: 'willEmit',
get: function get() {
return EventMethods.willEmit;
}
}, {
key: 'willEmitId',
get: function get() {
return EventMethods.willEmitId;
}
}, {
key: '_processRemovalQueue',
get: function get() {
return EventMethods._processRemovalQueue;
}
}]);
return EventEmitter;
}(_BaseClass3.default);
exports.default = EventEmitter;