awv3
Version:
⚡ AWV3 embedded CAD
157 lines (140 loc) • 5.5 kB
JavaScript
export default class Events {
constructor() {
this._callbacks = undefined;
this._inspectors = undefined;
}
once(type, callback) {
this.on(type, callback, true);
}
onFirst(type, callback) {
this.on(type, callback, false, 1);
}
onLast(type, callback) {
this.on(type, callback, false, -1);
}
on(arg1 = {}, arg2 = undefined, remove = false, priority = undefined) {
if (!this._callbacks) this._callbacks = {};
if (Array.isArray(arg1) || typeof arg1 === 'string' && typeof arg2 === 'function') {
// Types & Callback
let types = Array.isArray(arg1) ? arg1 : [arg1];
for (let type of types) {
let listeners = this._callbacks[type];
if (!listeners) listeners = this._callbacks[type] = [];
if (listeners.indexOf(arg2) < 0) {
arg2.remove = remove;
if (priority) arg2.priority = priority;
listeners.push(arg2);
listeners.sort((a, b) => b.priority || 0 - a.priority || 0);
if (this._inspectors) {
for (let inspector of this._inspectors)
inspector({ action: 'Add', type, callback: arg2 });
}
}
}
} else if (typeof arg1 === 'object' && arg2 === undefined) {
// Array of 'Type: Callback' pairs
for (let key in arg1) {
let callback = arg1[key];
typeof callback === 'function' && this.on(key, callback, remove, priority);
}
}
return this;
}
inspect(callback) {
if (!this._inspectors) this._inspectors = [];
this._inspectors.push(callback);
}
removeListener(types, callback) {
if (!Array.isArray(types) && typeof types === 'object' && callback === undefined) {
// Object of 'Type: Callback'
for (let [type, callback] of Object.entries(types))
this.removeListener(type, callback);
return this;
}
if (!this._callbacks) this._callbacks = {};
types = Array.isArray(types) ? types : [types];
for (let type of types) {
let listeners = this._callbacks[type];
if (!listeners) continue;
if (!callback) {
delete this._callbacks[type];
if (this._inspectors) {
for (let inspector of this._inspectors)
inspector({ action: 'Remove', type, callback: undefined });
}
} else {
let index = listeners.indexOf(callback);
index > -1 && listeners.splice(index, 1);
if (this._inspectors) {
for (let inspector of this._inspectors)
inspector({ action: 'Remove', type, callback });
}
}
}
return this;
}
removeListeners() {
this._callbacks = undefined;
}
removeInspectors() {
this._inspectors = undefined;
}
emit(type, ...args) {
let sequence = Promise.resolve();
if (!this._callbacks) this._callbacks = {};
let listeners = this._callbacks[type];
if (!!listeners) {
for (let listener of listeners) {
sequence = sequence.then(_ => {
listener.remove && this.removeListener(type, listener);
return listener.call(this, ...args);
});
}
}
return sequence;
}
bubble(type, ...args) {
let sequence = Promise.resolve();
if (!this._callbacks) this._callbacks = {};
let listeners = this._callbacks[type];
if (!!listeners) {
for (let listener of listeners)
sequence = sequence.then(_ => listener.call(this, ...args));
} else if (!!this.parent) {
// No listener found, just bubble up ...
this.parent.bubble(type, ...args);
}
return sequence;
}
findListener(type) {
if (!this._callbacks) this._callbacks = {};
let listeners = this._callbacks[type];
if (!!listeners) {
return this;
} else if (!!this.parent) {
// No listener found, just bubble up ...
return this.parent.find(type);
}
return undefined;
}
hasListener(type, callback = undefined) {
if (!this._callbacks) this._callbacks = {};
let listener = this._callbacks[type];
return !!listener && (!callback || callback === listener);
}
static mixin(object, handlers = null) {
object.hasListener = Events.prototype.hasListener;
object.on = Events.prototype.on;
object.once = Events.prototype.once;
object.onFirst = Events.prototype.onFirst;
object.onLast = Events.prototype.onLast;
object.inspect = Events.prototype.inspect;
object.removeListener = Events.prototype.removeListener;
object.removeListeners = Events.prototype.removeListeners;
object.removeInspectors = Events.prototype.removeInspectors;
object.emit = Events.prototype.emit;
object.bubble = Events.prototype.bubble;
object.findListener = Events.prototype.findListener;
if (handlers) object.on.bind(object)(handlers);
}
}