ts-events
Version:
Various EventEmitter event replacements with synchronous, a-synchronous, and queued events. Made in TypeScript so usable with JavaScript and TypeScript.
1,388 lines (1,367 loc) • 165 kB
JavaScript
(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(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({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 = /** @class */ (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 = function (d, b) {
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 extendStatics(d, b);
};
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 });
exports.ErrorAnyEvent = exports.VoidAnyEvent = exports.AnyEvent = exports.EventType = void 0;
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 = /** @class */ (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();
}
}
Object.defineProperty(AnyEvent.prototype, "evtListenersChanged", {
/**
* Sent when someone attaches or detaches
*/
get: function () {
if (!this._listenersChanged) {
// need to delay-load to avoid stack overflow in constructor
this._listenersChanged = new sync_event_1.VoidSyncEvent();
}
return this._listenersChanged;
},
enumerable: false,
configurable: true
});
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];
}
return 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];
}
return this._attach(mode, boundTo, handler, postable, opts, true);
};
AnyEvent.prototype._attach = function (mode, boundTo, handler, postable, opts, once) {
var _this = this;
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');
}
var detacher;
if (once) {
if (postable) {
detacher = event.once(postable);
}
else {
detacher = event.once(boundTo, handler);
}
}
else {
if (postable) {
detacher = event.attach(postable);
}
else {
detacher = event.attach(boundTo, handler);
}
}
if (this.evtFirstAttached && prevCount === 0) {
this.evtFirstAttached.post();
}
if (this.evtListenersChanged && prevCount !== this.listenerCount()) {
this.evtListenersChanged.post();
}
return function () {
var prevCount = (!!_this.evtLastDetached ? _this.listenerCount() : 0);
detacher();
if (!!_this.evtLastDetached && prevCount > 0 && _this.listenerCount() === 0) {
_this.evtLastDetached.post();
}
if (_this.evtListenersChanged && prevCount !== _this.listenerCount()) {
_this.evtListenersChanged.post();
}
};
};
AnyEvent.prototype.attachSync = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
args.unshift(EventType.Sync);
return 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);
return 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);
return 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);
return 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);
return 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);
return 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.listenerCount();
for (var i = 0; i < this._events.length; ++i) {
this._events[i].detach.apply(this._events[i], args);
}
if (this.evtListenersChanged && prevCount !== this.listenerCount()) {
this.evtListenersChanged.post();
}
if (!!this.evtLastDetached && prevCount > 0 && this.listenerCount() === 0) {
this.evtLastDetached.post();
}
};
/**
* Post an event to all current listeners
*/
AnyEvent.prototype.post = function (data) {
// make a copy of the array first to cover the case where event handlers
// are attached during the post
var events = [];
for (var i = 0; i < this._events.length; ++i) {
events.push(this._events[i]);
}
for (var i = 0; i < events.length; ++i) {
events[i].post(data);
}
};
/**
* 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 = /** @class */ (function (_super) {
__extends(VoidAnyEvent, _super);
function VoidAnyEvent() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Send the AsyncEvent.
*/
VoidAnyEvent.prototype.post = function () {
_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 = /** @class */ (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);
}
_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){
(function (setImmediate){
// Copyright © 2015 Rogier Schouten<github@workingcode.ninja>
// License: ISC
'use strict';
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
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 extendStatics(d, b);
};
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 });
exports.ErrorAsyncEvent = exports.VoidAsyncEvent = exports.AsyncEvent = void 0;
var base_event_1 = require("./base-event");
var sync_event_1 = require("./sync-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 = /** @class */ (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) {
if (opts === void 0) { opts = {}; }
var _this = _super.call(this) || this;
_this._queued = false;
_this.options = opts;
if (typeof opts.condensed === 'boolean') {
_this._condensed = opts.condensed;
}
else {
_this._condensed = false;
}
return _this;
}
Object.defineProperty(AsyncEvent.prototype, "evtListenersChanged", {
/**
* Sent when someone attaches or detaches
*/
get: function () {
if (!this._listenersChanged) {
// need to delay-load to avoid stack overflow in constructor
this._listenersChanged = new sync_event_1.VoidSyncEvent();
}
return this._listenersChanged;
},
enumerable: false,
configurable: true
});
/**
* 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 { // not condensed
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) {
// 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);
}
};
/**
* 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);
}
};
/** @inheritdoc */
AsyncEvent.prototype._attach = function (a, b, once) {
var _a, _b, _c, _d;
var count = (_b = (_a = this._listeners) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
var result = _super.prototype._attach.call(this, a, b, once);
if (this.evtListenersChanged && count !== ((_d = (_c = this._listeners) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)) {
this.evtListenersChanged.post();
}
return result;
};
/** @inheritdoc */
AsyncEvent.prototype._detach = function () {
var _a, _b, _c, _d;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var count = (_b = (_a = this._listeners) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
var result = _super.prototype._detach.apply(this, args);
if (this.evtListenersChanged && count !== ((_d = (_c = this._listeners) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)) {
this.evtListenersChanged.post();
}
return result;
};
/**
* The current scheduler
*/
AsyncEvent._scheduler = AsyncEvent.defaultScheduler;
return AsyncEvent;
}(base_event_1.BaseEvent));
exports.AsyncEvent = AsyncEvent;
/**
* Convenience class for AsyncEvents without data
*/
var VoidAsyncEvent = /** @class */ (function (_super) {
__extends(VoidAsyncEvent, _super);
function VoidAsyncEvent() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Send the AsyncEvent.
*/
VoidAsyncEvent.prototype.post = function () {
_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 = /** @class */ (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);
}
_super.prototype.post.call(this, data);
};
return ErrorAsyncEvent;
}(AsyncEvent));
exports.ErrorAsyncEvent = ErrorAsyncEvent;
}).call(this,require("timers").setImmediate)
},{"./base-event":4,"./sync-event":7,"timers":9}],4:[function(require,module,exports){
// Copyright © 2015 Rogier Schouten<github@workingcode.ninja>
// License: ISC
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseEvent = void 0;
/**
* Base class for events.
* Handles attaching and detaching listeners
*/
var BaseEvent = /** @class */ (function () {
function BaseEvent() {
}
/**
* Attach implementation
*/
BaseEvent.prototype.attach = function (a, b) {
return this._attach(a, b, false);
};
/**
* Once implementation
*/
BaseEvent.prototype.once = function (a, b) {
return this._attach(a, b, true);
};
/**
* Attach / once implementation
* @param a
* @param b
* @param once
* @returns function you can use for detaching from the event, instead of calling detach()
*/
BaseEvent.prototype._attach = function (a, b, once) {
var _this = this;
var boundTo;
var handler;
var event;
var result;
if (typeof a === 'function') {
handler = a;
result = function () { return _this.detach(handler); };
}
else if (!b && typeof a.post === 'function') {
event = a;
result = function () { return _this.detach(event); };
}
else {
if (typeof a !== 'object' || a === undefined) {
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;
result = function () { return _this.detach(boundTo, handler); };
}
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 result;
};
/**
* 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];
}
this._detach.apply(this, args);
};
/**
* Detach implementation
* @param args
*/
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) {
if (!this._listeners) {
return;
}
if (!listener.deleted) {
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) {
listener.event.post.apply(listener.event, args);
}
else if (listener.handler) {
listener.handler.apply((typeof listener.boundTo === 'object' ? listener.boundTo : this), args);
}
}
};
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 });
exports.shallowEquals = void 0;
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 = function (d, b) {
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 extendStatics(d, b);
};
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 });
exports.ErrorQueuedEvent = exports.VoidQueuedEvent = exports.QueuedEvent = void 0;
var base_event_1 = require("./base-event");
var EventQueue_1 = require("./EventQueue");
var sync_event_1 = require("./sync-event");
/**
* 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 = /** @class */ (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) {
if (opts === void 0) { opts = {}; }
var _this = _super.call(this) || this;
_this._queued = false;
_this.options = opts;
if (typeof opts.condensed === 'boolean') {
_this._condensed = opts.condensed;
}
else {
_this._condensed = false;
}
if (typeof opts.queue === 'object' && opts.queue !== null) {
_this._queue = opts.queue;
}
return _this;
}
Object.defineProperty(QueuedEvent.prototype, "evtListenersChanged", {
/**
* Sent when someone attaches or detaches
*/
get: function () {
if (!this._listenersChanged) {
// need to delay-load to avoid stack overflow in constructor
this._listenersChanged = new sync_event_1.VoidSyncEvent();
}
return this._listenersChanged;
},
enumerable: false,
configurable: true
});
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 { // not condensed
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);
}
});
}
};
/** @inheritdoc */
QueuedEvent.prototype._attach = function (a, b, once) {
var _a, _b, _c, _d;
var count = (_b = (_a = this._listeners) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
var result = _super.prototype._attach.call(this, a, b, once);
if (this.evtListenersChanged && count !== ((_d = (_c = this._listeners) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)) {
this.evtListenersChanged.post();
}
return result;
};
/** @inheritdoc */
QueuedEvent.prototype._detach = function () {
var _a, _b, _c, _d;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var count = (_b = (_a = this._listeners) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
var result = _super.prototype._detach.apply(this, args);
if (this.evtListenersChanged && count !== ((_d = (_c = this._listeners) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)) {
this.evtListenersChanged.post();
}
return result;
};
return QueuedEvent;
}(base_event_1.BaseEvent));
exports.QueuedEvent = QueuedEvent;
/**
* Convenience class for events without data
*/
var VoidQueuedEvent = /** @class */ (function (_super) {
__extends(VoidQueuedEvent, _super);
function VoidQueuedEvent() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Send the event.
*/
VoidQueuedEvent.prototype.post = function () {
_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 = /** @class */ (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);
}
_super.prototype.post.call(this, data);
};
return ErrorQueuedEvent;
}(QueuedEvent));
exports.ErrorQueuedEvent = ErrorQueuedEvent;
},{"./EventQueue":1,"./base-event":4,"./sync-event":7}],7:[function(require,module,exports){
// Copyright © 2015 Rogier Schouten<github@workingcode.ninja>
// License: ISC
'use strict';
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
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 extendStatics(d, b);
};
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 });
exports.ErrorSyncEvent = exports.VoidSyncEvent = exports.SyncEvent = void 0;
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 = /** @class */ (function (_super) {
__extends(SyncEvent, _super);
function SyncEvent() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* Recursive post() invocations
*/
_this._recursion = 0;
return _this;
}
Object.defineProperty(SyncEvent.prototype, "evtListenersChanged", {
/**
* Sent when someone attaches or detaches
*/
get: function () {
if (!this._listenersChanged) {
// need to delay-load to avoid stack overflow in constructor
this._listenersChanged = new VoidSyncEvent();
}
return this._listenersChanged;
},
enumerable: false,
configurable: true
});
SyncEvent.prototype.post = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (!this._listeners || this._listeners.length === 0) {
return;
}
this._recursion++;
if (typeof SyncEvent.MAX_RECURSION_DEPTH === 'number'
&& Number.isInteger(SyncEvent.MAX_RECURSION_DEPTH)
&& SyncEvent.MAX_RECURSION_DEPTH > 0
&& this._recursion > SyncEvent.MAX_RECURSION_DEPTH) {
throw new Error('event fired recursively');
}
// 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);
}
this._recursion--;
};
/** @inheritdoc */
SyncEvent.prototype._attach = function (a, b, once) {
var _a, _b, _c, _d;
var count = (_b = (_a = this._listeners) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
var result = _super.prototype._attach.call(this, a, b, once);
if (this.evtListenersChanged && count !== ((_d = (_c = this._listeners) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)) {
this.evtListenersChanged.post();
}
return result;
};
/** @inheritdoc */
SyncEvent.prototype._detach = function () {
var _a, _b, _c, _d;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var count = (_b = (_a = this._listeners) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
var result = _super.prototype._detach.apply(this, args);
if (this.evtListenersChanged && count !== ((_d = (_c = this._listeners) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)) {
this.evtListenersChanged.post();
}
return result;
};
/**
* Maximum number of times that an event handler may cause the same event
* recursively.
*/
SyncEvent.MAX_RECURSION_DEPTH = 10;
return SyncEvent;
}(base_event_1.BaseEvent));
exports.SyncEvent = SyncEvent;
/**
* Convenience class for events without data
*/
var VoidSyncEvent = /** @class */ (function (_super) {
__extends(VoidSyncEvent, _super);
function VoidSyncEvent() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* Send the event.
*/
VoidSyncEvent.prototype.post = function () {
_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 = /** @class */ (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);
}
_super.prototype.post.call(this, data);
};
return ErrorSyncEvent;
}(SyncEvent));
exports.ErrorSyncEvent = ErrorSyncEvent;
},{"./base-event":4}],8:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
functio