UNPKG

irrelon-reactor-autonet

Version:

A module for automatically creating groups of self-networking services.

533 lines (449 loc) 15.4 kB
"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;