UNPKG

backbone-esnext-events

Version:

Separates 'events' support from Backbone in addition to adding TyphonJS extensions.

448 lines (371 loc) 14.6 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _keys = require('babel-runtime/core-js/object/keys'); var _keys2 = _interopRequireDefault(_keys); var _getIterator2 = require('babel-runtime/core-js/get-iterator'); var _getIterator3 = _interopRequireDefault(_getIterator2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _TyphonEvents = require('./TyphonEvents.js'); var _TyphonEvents2 = _interopRequireDefault(_TyphonEvents); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * EventProxy provides a protected proxy of another TyphonEvents / eventbus instance. * * The main use case of EventProxy is to allow indirect access to an eventbus. This is handy when it comes to managing * the event lifecycle for a plugin system. When a plugin is added it could receive a callback, perhaps named * `onPluginLoaded`, which contains an EventProxy instance rather than the direct eventbus. This EventProxy instance is * associated in the management system controlling plugin lifecycle. When a plugin is removed / unloaded the management * system can automatically unregister all events for the plugin without requiring the plugin author doing it correctly * if they had full control. IE This allows to plugin system to guarantee no dangling listeners. * * EventProxy provides the on / off, once, and trigger methods with the same signatures as found in * TyphonEvents / Events. However, the proxy tracks all added event bindings which is used to proxy between the target * eventbus which is passed in from the constructor. All registration methods (on / off / once) proxy. In addition * there is a `destroy` method which will unregister all of proxied events and remove references to the managed * eventbus. Any further usage of a destroyed EventProxy instance results in a ReferenceError thrown. */ var EventProxy = function () { /** * Creates the event proxy with an existing instance of TyphonEvents. * * @param {TyphonEvents} eventbus - The target eventbus instance. */ function EventProxy(eventbus) { (0, _classCallCheck3.default)(this, EventProxy); if (!(eventbus instanceof _TyphonEvents2.default)) { throw new TypeError('\'eventbus\' is not an instance of TyphonEvents.'); } /** * Stores the target eventbus. * @type {TyphonEvents} * @private */ this._eventbus = eventbus; /** * Stores all proxied event bindings. * @type {Array<{name: string, callback: function, context: *}>} * @private */ this._events = []; } /** * Creates a new EventProxy from the target eventbus of this proxy. * * @returns {EventProxy} */ (0, _createClass3.default)(EventProxy, [{ key: 'createEventProxy', value: function createEventProxy() { return new EventProxy(this._eventbus); } /** * Unregisters all proxied events from the target eventbus and removes any local references. All subsequent calls * after `destroy` has been called result in a ReferenceError thrown. */ }, { key: 'destroy', value: function destroy() { if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = (0, _getIterator3.default)(this._events), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var event = _step.value; this._eventbus.off(event.name, event.callback, event.context); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } this._events = []; this._eventbus = null; } /** * Returns the current proxied event count. * * @returns {Number} */ }, { key: 'getEventNames', /** * Returns the event names of proxied event listeners. * * @returns {string[]} */ value: function getEventNames() { if (!this._events) { return []; } var eventNames = {}; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = (0, _getIterator3.default)(this._events), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var event = _step2.value; eventNames[event.name] = true; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return (0, _keys2.default)(eventNames); } /** * Iterates over all proxied events invoking a callback with the event data stored. * * @param {function} callback - Callback invoked for each proxied event stored. */ }, { key: 'forEachEvent', value: function forEachEvent(callback) { if (typeof callback !== 'function') { throw new TypeError('\'callback\' is not a \'function\'.'); } var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = (0, _getIterator3.default)(this._events), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var event = _step3.value; callback(event.name, event.callback, event.context); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } /** * Returns the target eventbus name. * * @returns {string|*} */ }, { key: 'getEventbusName', value: function getEventbusName() { if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } return this._eventbus.getEventbusName(); } /** * Remove a previously-bound proxied event binding. * * Please see {@link Events#off}. * * @param {string} [name] - Event name(s) * * @param {function} [callback] - Event callback function * * @param {object} [context] - Event context * * @returns {EventProxy} */ }, { key: 'off', value: function off() { var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : void 0; var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : void 0; var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : void 0; if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } var hasName = typeof name !== 'undefined' && name !== null; var hasCallback = typeof callback !== 'undefined' && callback !== null; var hasContext = typeof context !== 'undefined' && context !== null; // Remove all events if `off()` is invoked. if (!hasName && !hasCallback && !hasContext) { var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = (0, _getIterator3.default)(this._events), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var event = _step4.value; this._eventbus.off(event.name, event.callback, event.context); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } this._events = []; } else { var values = {}; if (hasName) { values.name = name; } if (hasCallback) { values.callback = callback; } if (hasContext) { values.context = context; } for (var cntr = this._events.length; --cntr >= 0;) { var _event = this._events[cntr]; var foundMatch = true; for (var key in values) { if (_event[key] !== values[key]) { foundMatch = false;break; } } if (foundMatch) { this._eventbus.off(values.name, values.callback, values.context); this._events.splice(cntr, 1); } } } return this; } /** * Bind a callback function to an object. The callback will be invoked whenever the event is fired. If you have a * large number of different events on a page, the convention is to use colons to namespace them: "poll:start", or * "change:selection". * * This is proxied through `listenTo` of an internal Events instance instead of directly modifying the target * eventbus. * * Please see {@link Events#on}. * * @param {string} name - Event name(s) * @param {function} callback - Event callback function * @param {object} context - Event context * @returns {EventProxy} */ }, { key: 'on', value: function on(name, callback) { var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : void 0; if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } this._eventbus.on(name, callback, context); this._events.push({ name: name, callback: callback, context: context }); return this; } /** * Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be * passed along to the event callbacks. * * Please see {@link Events#trigger}. * * @returns {EventProxy} */ }, { key: 'trigger', value: function trigger() { var _eventbus; if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } (_eventbus = this._eventbus).trigger.apply(_eventbus, arguments); return this; } /** * Provides `trigger` functionality, but collects any returned Promises from invoked targets and returns a * single Promise generated by `Promise.resolve` for a single value or `Promise.all` for multiple results. This is * a very useful mechanism to invoke asynchronous operations over an eventbus. * * Please see {@link TyphonEvents#triggerAsync}. * * @returns {Promise} */ }, { key: 'triggerAsync', value: function triggerAsync() { var _eventbus2; if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } return (_eventbus2 = this._eventbus).triggerAsync.apply(_eventbus2, arguments); } /** * Defers invoking `trigger`. This is useful for triggering events in the next clock tick. * * Please see {@link TyphonEvents#triggerDefer}. * * @returns {EventProxy} */ }, { key: 'triggerDefer', value: function triggerDefer() { var _eventbus3; if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } (_eventbus3 = this._eventbus).triggerDefer.apply(_eventbus3, arguments); return this; } /** * Provides `trigger` functionality, but collects any returned result or results from invoked targets as a single * value or in an array and passes it back to the callee in a synchronous manner. * * Please see {@link TyphonEvents#triggerSync}. * * @returns {*|Array.<*>} */ }, { key: 'triggerSync', value: function triggerSync() { var _eventbus4; if (this._eventbus === null) { throw new ReferenceError('This EventProxy instance has been destroyed.'); } return (_eventbus4 = this._eventbus).triggerSync.apply(_eventbus4, arguments); } }, { key: 'eventCount', get: function get() { return this._events.length; } }]); return EventProxy; }(); exports.default = EventProxy; module.exports = exports['default'];