UNPKG

@jokio/ts-events

Version:

Various EventEmitter event replacements with synchronous, a-synchronous, and queued events. Made in TypeScript so usable with JavaScript and TypeScript.

1,244 lines (1,242 loc) 138 kB
(function(f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.listComponent = f() } })(function() { var define, module, exports; require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var sync_event_1 = require("./sync-event"); /** * Simple synchronous event queue that needs to be drained manually. */ var EventQueue = (function () { function EventQueue() { /** * SyncEvent triggered after an event is added outside of a flush operation. * @param queue The event queue itself */ this.evtFilled = new sync_event_1.SyncEvent(); /** * SyncEvent triggered after the queue is flushed empty * @param queue The event queue itself */ this.evtDrained = new sync_event_1.SyncEvent(); /** * Queued elements */ this._queue = []; /** * True while flush() or flushOnce() is running */ this._flushing = false; } /** * The module-global event queue */ EventQueue.global = function () { if (!EventQueue._instance) { EventQueue.resetGlobal(); } return EventQueue._instance; }; /** * Testing purposes */ EventQueue.resetGlobal = function () { EventQueue._instance = new EventQueue(); }; /** * Returns true iff the queue is empty */ EventQueue.prototype.empty = function () { return this._queue.length === 0; }; /** * Add an element to the queue. The handler is called when one of the flush * methods is called. */ EventQueue.prototype.add = function (handler) { this._queue.push(handler); if (this._queue.length === 1 && !this._flushing) { this.evtFilled.post(this); } }; /** * Calls all handlers currently in the queue. Does not call any handlers added * as a result of the flush */ EventQueue.prototype.flushOnce = function () { var empty = (this._queue.length === 0); var flushing = this._flushing; this._flushing = true; try { var queue = this._queue; this._queue = []; for (var i = 0; i < queue.length; ++i) { queue[i](); } } finally { this._flushing = flushing; if (!empty && !flushing && this._queue.length === 0) { this.evtDrained.post(this); } } }; /** * Flushes the QueuedEvents, calling all events currently in the queue and those * put into the queue as a result of the flush. * @param maxRounds Optional, default 10. Number of iterations after which to throw an error because * the queue keeps filling up. Set to null to disable this. */ EventQueue.prototype.flush = function (maxRounds) { if (maxRounds === void 0) { maxRounds = 10; } var empty = (this._queue.length === 0); var flushing = this._flushing; this._flushing = true; try { var i = 0; while (this._queue.length > 0) { if (typeof maxRounds === 'number' && i >= maxRounds) { this._queue = []; throw new Error('unable to flush the queue due to recursively added event. Clearing queue now'); } this.flushOnce(); ++i; } } finally { this._flushing = flushing; if (!empty && !flushing && this._queue.length === 0) { this.evtDrained.post(this); } } }; return EventQueue; }()); exports.default = EventQueue; },{"./sync-event":7}],2:[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; return { next: verb(0), "throw": verb(1), "return": verb(2) }; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var objects_1 = require("./objects"); var sync_event_1 = require("./sync-event"); var async_event_1 = require("./async-event"); var queued_event_1 = require("./queued-event"); var EventType; (function (EventType) { EventType[EventType["Sync"] = 0] = "Sync"; EventType[EventType["Async"] = 1] = "Async"; EventType[EventType["Queued"] = 2] = "Queued"; })(EventType = exports.EventType || (exports.EventType = {})); /** * An event that behaves like a Sync/Async/Queued event depending on how * you subscribe. */ var AnyEvent = (function () { function AnyEvent(opts) { /** * Underlying event implementations; one for every attach type + opts combination */ this._events = []; if (opts && opts.monitorAttach) { this.evtFirstAttached = new VoidAnyEvent(); this.evtLastDetached = new VoidAnyEvent(); } } AnyEvent.prototype.attach = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var mode = EventType.Sync; if (args.length > 0 && typeof args[0] === 'number') { mode = args.shift(); } var boundTo = this; // add ourselves as default 'boundTo' argument var handler; var opts; var postable; if (typeof args[0] === 'function' || (args[0] && typeof args[0] === 'object' && typeof args[0].post === 'function')) { if (typeof args[0] === 'function') { handler = args[0]; } else { postable = args[0]; } opts = args[1]; } else { boundTo = args[0]; handler = args[1]; opts = args[2]; } this._attach(mode, boundTo, handler, postable, opts, false); }; AnyEvent.prototype.once = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var mode = EventType.Sync; if (args.length > 0 && typeof args[0] === 'number') { mode = args.shift(); } var boundTo = this; // add ourselves as default 'boundTo' argument var handler; var opts; var postable; if (typeof args[0] === 'function' || (args[0] && typeof args[0] === 'object' && typeof args[0].post === 'function')) { if (typeof args[0] === 'function') { handler = args[0]; } else { postable = args[0]; } opts = args[1]; } else { boundTo = args[0]; handler = args[1]; opts = args[2]; } this._attach(mode, boundTo, handler, postable, opts, true); }; AnyEvent.prototype._attach = function (mode, boundTo, handler, postable, opts, once) { var prevCount = (!!this.evtFirstAttached ? this.listenerCount() : 0); var event; switch (mode) { case EventType.Sync: { for (var _i = 0, _a = this._events; _i < _a.length; _i++) { var evt = _a[_i]; if (evt instanceof sync_event_1.SyncEvent) { event = evt; } } if (!event) { event = new sync_event_1.SyncEvent(); this._events.push(event); } } break; case EventType.Async: { for (var _b = 0, _c = this._events; _b < _c.length; _b++) { var evt = _c[_b]; if (evt instanceof async_event_1.AsyncEvent && objects_1.shallowEquals(evt.options, opts)) { event = evt; } } if (!event) { event = new async_event_1.AsyncEvent(opts); this._events.push(event); } } break; case EventType.Queued: { for (var _d = 0, _e = this._events; _d < _e.length; _d++) { var evt = _e[_d]; if (evt instanceof queued_event_1.QueuedEvent && objects_1.shallowEquals(evt.options, opts)) { event = evt; } } if (!event) { event = new queued_event_1.QueuedEvent(opts); this._events.push(event); } } break; default: throw new Error('unknown EventType'); } if (once) { if (postable) { event.once(postable); } else { event.once(boundTo, handler); } } else { if (postable) { event.attach(postable); } else { event.attach(boundTo, handler); } } if (this.evtFirstAttached && prevCount === 0) { this.evtFirstAttached.post(); } }; AnyEvent.prototype.attachSync = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } args.unshift(EventType.Sync); this.attach.apply(this, args); }; AnyEvent.prototype.onceSync = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } args.unshift(EventType.Sync); this.once.apply(this, args); }; AnyEvent.prototype.attachAsync = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } args.unshift(EventType.Async); this.attach.apply(this, args); }; AnyEvent.prototype.onceAsync = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } args.unshift(EventType.Async); this.once.apply(this, args); }; AnyEvent.prototype.attachQueued = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } args.unshift(EventType.Queued); this.attach.apply(this, args); }; AnyEvent.prototype.onceQueued = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } args.unshift(EventType.Queued); this.once.apply(this, args); }; /** * Detach event handlers regardless of type */ AnyEvent.prototype.detach = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var prevCount = (!!this.evtLastDetached ? this.listenerCount() : 0); for (var i = 0; i < this._events.length; ++i) { this._events[i].detach.apply(this._events[i], args); } if (!!this.evtLastDetached && prevCount > 0 && this.listenerCount() === 0) { this.evtLastDetached.post(); } }; /** * Post an event to all current listeners */ AnyEvent.prototype.post = function (data) { return __awaiter(this, void 0, void 0, function () { var events, i, i; return __generator(this, function (_a) { switch (_a.label) { case 0: events = []; for (i = 0; i < this._events.length; ++i) { events.push(this._events[i]); } i = 0; _a.label = 1; case 1: if (!(i < events.length)) return [3 /*break*/, 4]; return [4 /*yield*/, events[i].post(data)]; case 2: _a.sent(); _a.label = 3; case 3: ++i; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); }; /** * The number of attached listeners */ AnyEvent.prototype.listenerCount = function () { var result = 0; for (var i = 0; i < this._events.length; ++i) { result += this._events[i].listenerCount(); } return result; }; return AnyEvent; }()); exports.AnyEvent = AnyEvent; /** * Convenience class for AnyEvents without data */ var VoidAnyEvent = (function (_super) { __extends(VoidAnyEvent, _super); function VoidAnyEvent() { return _super !== null && _super.apply(this, arguments) || this; } /** * Send the AsyncEvent. */ VoidAnyEvent.prototype.post = function () { return _super.prototype.post.call(this, undefined); }; return VoidAnyEvent; }(AnyEvent)); exports.VoidAnyEvent = VoidAnyEvent; /** * Similar to 'error' event on EventEmitter: throws when a post() occurs while no handlers set. */ var ErrorAnyEvent = (function (_super) { __extends(ErrorAnyEvent, _super); function ErrorAnyEvent() { return _super !== null && _super.apply(this, arguments) || this; } ErrorAnyEvent.prototype.post = function (data) { if (this.listenerCount() === 0) { throw new Error("error event posted while no listeners attached. Error: " + data.message); } return _super.prototype.post.call(this, data); }; return ErrorAnyEvent; }(AnyEvent)); exports.ErrorAnyEvent = ErrorAnyEvent; },{"./async-event":3,"./objects":5,"./queued-event":6,"./sync-event":7}],3:[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; return { next: verb(0), "throw": verb(1), "return": verb(2) }; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var base_event_1 = require("./base-event"); /** * A-synchronous event. Handlers are called in the next Node.JS cycle. * - Optionally condenses multiple post() calls into one (the last post() gets through) * - Handlers are called only for events posted after they were attached. * - Handlers are not called anymore when they are detached, even if a post() is in progress */ var AsyncEvent = (function (_super) { __extends(AsyncEvent, _super); /** * Constructor * @param opts Optional. Various settings: * - condensed: a Boolean indicating whether to condense multiple post() calls within the same cycle. */ function AsyncEvent(opts) { var _this = _super.call(this) || this; _this._queued = false; _this.options = opts; var options = opts || {}; if (typeof options.condensed === 'boolean') { _this._condensed = options.condensed; } else { _this._condensed = false; } return _this; } /** * The default scheduler uses setImmediate() or setTimeout(..., 0) if setImmediate is not available. */ AsyncEvent.defaultScheduler = function (callback) { /* istanbul ignore else */ if (typeof window !== 'undefined') { // browsers don't always support setImmediate() setTimeout(callback, 0); } else { // node.js setImmediate(callback); } }; /** * By default, AsyncEvent uses setImmediate() to schedule event handler invocation. * You can change this for e.g. setTimeout(..., 0) by calling this static method once. * @param scheduler A function that takes a callback and executes it in the next Node.JS cycle. */ AsyncEvent.setScheduler = function (scheduler) { AsyncEvent._scheduler = scheduler; }; AsyncEvent.prototype.post = function () { var _this = this; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!this._listeners || this._listeners.length === 0) { return; } if (this._condensed) { this._queuedData = args; this._queuedListeners = this._listeners; if (this._queued) { return; } else { this._queued = true; AsyncEvent._scheduler(function () { // immediately mark non-queued to allow new AsyncEvent to happen as result // of calling handlers _this._queued = false; // cache listeners and data because they might change while calling event handlers var data = _this._queuedData; var listeners = _this._queuedListeners; for (var i = 0; i < listeners.length; ++i) { var listener = listeners[i]; _this._call(listener, data); } }); } } else { var listeners_1 = this._listeners; AsyncEvent._scheduler(function () { for (var i = 0; i < listeners_1.length; ++i) { var listener = listeners_1[i]; _this._call(listener, args); } }); } }; // inherited AsyncEvent.prototype._call = function (listener, args) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { // performance optimization: don't use consecutive nodejs cycles // for asyncevents attached to asyncevents if (listener.event && listener.event instanceof AsyncEvent) { listener.event._postDirect(args); } else { _super.prototype._call.call(this, listener, args); } return [2 /*return*/]; }); }); }; /** * Performance optimization: if this async signal is attached to another * async signal, we're already a the next cycle and we can call listeners * directly */ AsyncEvent.prototype._postDirect = function (args) { if (!this._listeners || this._listeners.length === 0) { return; } // copy a reference to the array because this._listeners might be replaced during // the handler calls var listeners = this._listeners; for (var i = 0; i < listeners.length; ++i) { var listener = listeners[i]; this._call(listener, args); } }; return AsyncEvent; }(base_event_1.BaseEvent)); /** * The current scheduler */ AsyncEvent._scheduler = AsyncEvent.defaultScheduler; exports.AsyncEvent = AsyncEvent; /** * Convenience class for AsyncEvents without data */ var VoidAsyncEvent = (function (_super) { __extends(VoidAsyncEvent, _super); function VoidAsyncEvent() { return _super !== null && _super.apply(this, arguments) || this; } /** * Send the AsyncEvent. */ VoidAsyncEvent.prototype.post = function () { return _super.prototype.post.call(this, undefined); }; return VoidAsyncEvent; }(AsyncEvent)); exports.VoidAsyncEvent = VoidAsyncEvent; /** * Similar to 'error' event on EventEmitter: throws when a post() occurs while no handlers set. */ var ErrorAsyncEvent = (function (_super) { __extends(ErrorAsyncEvent, _super); function ErrorAsyncEvent() { return _super !== null && _super.apply(this, arguments) || this; } ErrorAsyncEvent.prototype.post = function (data) { if (this.listenerCount() === 0) { throw new Error("error event posted while no listeners attached. Error: " + data.message); } return _super.prototype.post.call(this, data); }; return ErrorAsyncEvent; }(AsyncEvent)); exports.ErrorAsyncEvent = ErrorAsyncEvent; },{"./base-event":4}],4:[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; return { next: verb(0), "throw": verb(1), "return": verb(2) }; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); /** * Base class for events. * Handles attaching and detaching listeners */ var BaseEvent = (function () { function BaseEvent() { } /** * Attach implementation */ BaseEvent.prototype.attach = function (a, b) { this._attach(a, b, false); }; /** * Attach implementation */ BaseEvent.prototype.once = function (a, b) { this._attach(a, b, true); }; /** * Attach / once implementation * @param a * @param b * @param once */ BaseEvent.prototype._attach = function (a, b, once) { return __awaiter(this, void 0, void 0, function () { var boundTo, handler, event; return __generator(this, function (_a) { if (typeof a === 'function') { handler = a; } else if (!b && typeof a.post === 'function') { event = a; } else { if (typeof a !== 'object') { throw new Error('Expect a function or object as first argument'); } if (typeof b !== 'function') { throw new Error('Expect a function as second argument'); } boundTo = a; handler = b; } if (!this._listeners) { this._listeners = []; } else { // make a copy of the array so events that are underway have a stable local copy // of the listeners array at the time of post() this._listeners = this._listeners.slice(); } this._listeners.push({ deleted: false, boundTo: boundTo, handler: handler, event: event, once: once }); return [2 /*return*/]; }); }); }; /** * Detach implementation. See the overloads for description. */ BaseEvent.prototype.detach = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!this._listeners || this._listeners.length === 0) { return; } var boundTo; var handler; var event; if (args.length >= 1) { if (typeof (args[0]) === 'function') { handler = args[0]; } else if (args.length === 1 && typeof args[0].post === 'function') { event = args[0]; } else { boundTo = args[0]; } } if (args.length >= 2) { handler = args[1]; } // remove listeners AND mark them as deleted so subclasses don't send any more events to them this._listeners = this._listeners.filter(function (listener) { if ((typeof handler === 'undefined' || listener.handler === handler) && (typeof event === 'undefined' || listener.event === event) && (typeof boundTo === 'undefined' || listener.boundTo === boundTo)) { listener.deleted = true; return false; } return true; }); if (this._listeners.length === 0) { delete this._listeners; } }; /** * Abstract post() method to be able to connect any type of event to any other directly * @abstract */ BaseEvent.prototype.post = function (data) { throw new Error('abstract'); }; /** * The number of attached listeners */ BaseEvent.prototype.listenerCount = function () { return (this._listeners ? this._listeners.length : 0); }; /** * Call the given listener, if it is not marked as 'deleted' * @param listener The listener to call * @param args The arguments to the handler */ BaseEvent.prototype._call = function (listener, args) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!!listener.deleted) return [3 /*break*/, 4]; if (listener.once) { // remove listeners AND mark as deleted so subclasses don't send any more events to them listener.deleted = true; this._listeners = this._listeners.filter(function (l) { return l !== listener; }); if (this._listeners.length === 0) { delete this._listeners; } } if (!listener.event) return [3 /*break*/, 2]; return [4 /*yield*/, listener.event.post.apply(listener.event, args)]; case 1: _a.sent(); return [3 /*break*/, 4]; case 2: return [4 /*yield*/, listener.handler.apply((typeof listener.boundTo === 'object' ? listener.boundTo : this), args)]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/]; } }); }); }; return BaseEvent; }()); exports.BaseEvent = BaseEvent; },{}],5:[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); function shallowEquals(a, b) { if (a === b) { return true; } if (typeof a !== typeof b) { return false; } switch (typeof a) { case 'boolean': case 'number': case 'string': case 'function': case 'symbol': case 'undefined': // already did === compare return false; case 'object': if (a === null || b === null) { return false; // already compared === } if (Array.isArray(a) || Array.isArray(b)) { if (!Array.isArray(a) || !Array.isArray(b)) { return false; } if (a.length !== b.length) { return false; } for (var i = 0; i < a.length; ++i) { if (a[i] !== b[i]) { return false; } } return true; } var namesA = []; var namesB = []; for (var name_1 in a) { if (a.hasOwnProperty(name_1)) { namesA.push(name_1); } } for (var name_2 in b) { if (b.hasOwnProperty(name_2)) { namesB.push(name_2); } } namesA.sort(); namesB.sort(); if (namesA.join(',') !== namesB.join(',')) { return false; } for (var i = 0; i < namesA.length; ++i) { if (a[namesA[i]] !== b[namesA[i]]) { return false; } } return true; default: return false; } } exports.shallowEquals = shallowEquals; },{}],6:[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var base_event_1 = require("./base-event"); var EventQueue_1 = require("./EventQueue"); /** * Event that stays in a queue until you process the queue. Allows fine-grained * control over when events happen. * - Optionally condenses multiple post() calls into one. * - Handlers are called only for events posted after they were attached. * - Handlers are not called anymore when they are detached, even if a post() is in progress */ var QueuedEvent = (function (_super) { __extends(QueuedEvent, _super); /** * Constructor * @param opts Optional, an object with the following members: * - condensed: a Boolean indicating whether to condense multiple calls to post() into one (default false) * - queue: a specific event queue to use. The global EventQueue instance is used if not given. */ function QueuedEvent(opts) { var _this = _super.call(this) || this; _this._queued = false; _this.options = opts; var options = opts || {}; if (typeof options.condensed === 'boolean') { _this._condensed = options.condensed; } else { _this._condensed = false; } if (typeof options.queue === 'object' && options.queue !== null) { _this._queue = options.queue; } return _this; } QueuedEvent.prototype.post = function () { var _this = this; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!this._listeners || this._listeners.length === 0) { return; } var queue = (this._queue ? this._queue : EventQueue_1.default.global()); if (this._condensed) { this._queuedData = args; this._queuedListeners = this._listeners; if (this._queued) { return; } else { this._queued = true; queue.add(function () { // immediately mark non-queued to allow new AsyncEvent to happen as result // of calling handlers _this._queued = false; // cache listeners and data because they might change while calling event handlers var data = _this._queuedData; var listeners = _this._queuedListeners; for (var i = 0; i < listeners.length; ++i) { var listener = listeners[i]; _this._call(listener, data); } }); } } else { var listeners_1 = this._listeners; queue.add(function () { for (var i = 0; i < listeners_1.length; ++i) { var listener = listeners_1[i]; _this._call(listener, args); } }); } }; return QueuedEvent; }(base_event_1.BaseEvent)); exports.QueuedEvent = QueuedEvent; /** * Convenience class for events without data */ var VoidQueuedEvent = (function (_super) { __extends(VoidQueuedEvent, _super); function VoidQueuedEvent() { return _super !== null && _super.apply(this, arguments) || this; } /** * Send the event. */ VoidQueuedEvent.prototype.post = function () { return _super.prototype.post.call(this, undefined); }; return VoidQueuedEvent; }(QueuedEvent)); exports.VoidQueuedEvent = VoidQueuedEvent; /** * Similar to 'error' event on EventEmitter: throws when a post() occurs while no handlers set. */ var ErrorQueuedEvent = (function (_super) { __extends(ErrorQueuedEvent, _super); function ErrorQueuedEvent() { return _super !== null && _super.apply(this, arguments) || this; } ErrorQueuedEvent.prototype.post = function (data) { if (!this._listeners || this._listeners.length === 0) { throw new Error("error event posted while no listeners attached. Error: " + data.message); } return _super.prototype.post.call(this, data); }; return ErrorQueuedEvent; }(QueuedEvent)); exports.ErrorQueuedEvent = ErrorQueuedEvent; },{"./EventQueue":1,"./base-event":4}],7:[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function () { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; return { next: verb(0), "throw": verb(1), "return": verb(2) }; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var base_event_1 = require("./base-event"); /** * This is a true EventEmitter replacement: the handlers are called synchronously when * you post the event. * - Allows better error handling by aggregating any errors thrown by handlers. * - Prevents livelock by throwing an error when recursion depth is above a maximum. * - Handlers are called only for events posted after they were attached. * - Handlers are not called anymore when they are detached, even if a post() is in progress */ var SyncEvent = (function (_super) { __extends(SyncEvent, _super); function SyncEvent() { var _this = _super !== null && _super.apply(this, arguments) || this; /** * Recursive post() invocations */ _this._recursion = 0; return _this; } SyncEvent.prototype.post = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return __awaiter(this, void 0, void 0, function () { var listeners, i, listener; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this._listeners || this._listeners.length === 0) { return [2 /*return*/]; } this._recursion++; if (SyncEvent.MAX_RECURSION_DEPTH > 0 && this._recursion > SyncEvent.MAX_RECURSION_DEPTH) { throw new Error('event fired recursively'); } listeners = this._listeners; i = 0; _a.label = 1; case 1: if (!(i < listeners.length)) return [3 /*break*/, 4]; listener = listeners[i]; return [4 /*yield*/, this._call(listener, args)]; case 2: _a.sent(); _a.label = 3; case 3: ++i; return [3 /*break*/, 1]; case 4: this._recursion--; return [2 /*return*/]; } }); }); }; return SyncEvent; }(base_event_1.BaseEvent)); /** * Maximum number of times that an event handler may cause the same event * recursively. */ SyncEvent.MAX_RECURSION_DEPTH = 10; exports.SyncEvent = SyncEvent; /** * Convenience class for events without data */ var VoidSyncEvent = (function (_super) { __extends(VoidSyncEvent, _super); function VoidSyncEvent() { return _super !== null && _super.apply(this, arguments) || this; } /** * Send the event. */ VoidSyncEvent.prototype.post = function () { return _super.prototype.post.call(this, undefined); }; return VoidSyncEvent; }(SyncEvent)); exports.VoidSyncEvent = VoidSyncEvent; /** * Similar to 'error' event on EventEmitter: throws when a post() occurs while no handlers set. */ var ErrorSyncEvent = (function (_super) { __extends(ErrorSyncEvent, _super); function ErrorSyncEvent() { return _super !== null && _super.apply(this, arguments) || this; } ErrorSyncEvent.prototype.post = function (data) { if (this.listenerCount() === 0) { throw new Error("error event posted while no listeners attached. Error: " + data.message); } return _super.prototype.post.call(this, data); }; return ErrorSyncEvent; }(SyncEvent)); exports.ErrorSyncEvent = ErrorSyncEvent; },{"./base-event":4}],"ts-events":[function(require,module,exports){ // Copyright © 2015 Rogier Schouten<github@workingcode.ninja> // License: ISC 'use strict'; function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } Object.defineProperty(exports, "__esModule", { value: true }); __export(require("./base-event")); __export(require("./sync-event")); __export(require("./queued-event")); __export(require("./async-event")); __export(require("./any-even