flecks/packages/core/build/event-emitter.js
2024-01-19 03:38:16 -06:00

127 lines
3.0 KiB
JavaScript

const createListener = (fn, that, type, once) => ({
fn,
that,
type,
once,
bound: that ? fn.bind(that) : fn,
});
module.exports = function EventEmitterDecorator(Superclass) {
return class EventEmitter extends Superclass {
constructor(...args) {
super(...args);
this.$$events = Object.create(null);
}
addListener(typesOrType, fn, that) {
return this.on(typesOrType, fn, that);
}
// Notify ALL the listeners!
emit(type, ...args) {
const typeListeners = this.$$events[type];
if (typeListeners && typeListeners.length > 0) {
this.emitToListeners(typeListeners, args);
}
}
emitToListeners(listeners, args) {
for (let i = 0; i < listeners.length; ++i) {
const {
once,
type,
fn,
bound,
that,
} = listeners[i];
// Remove if only once.
if (once) {
this.offSingleEvent(type, fn);
}
// Fast path...
if (0 === args.length) {
bound();
}
else if (1 === args.length) {
bound(args[0]);
}
else if (2 === args.length) {
bound(args[0], args[1]);
}
else if (3 === args.length) {
bound(args[0], args[1], args[2]);
}
else if (4 === args.length) {
bound(args[0], args[1], args[2], args[3]);
}
else if (5 === args.length) {
bound(args[0], args[1], args[2], args[3], args[4]);
}
// Slow path...
else {
fn.apply(that, args);
}
}
}
off(typesOrType, fn) {
const types = Array.isArray(typesOrType) ? typesOrType : [typesOrType];
for (let i = 0; i < types.length; i++) {
this.offSingleEvent(types[i], fn);
}
return this;
}
offSingleEvent(type, fn) {
if ('function' !== typeof fn) {
// Only type.
if (type in this.$$events) {
this.$$events[type] = [];
}
return;
}
// Function.
if (!(type in this.$$events)) {
return;
}
this.$$events[type] = this.$$events[type].filter((listener) => listener.fn !== fn);
}
on(typesOrType, fn, that = undefined) {
this.$$on(typesOrType, fn, that, false);
return this;
}
$$on(typesOrType, fn, that, once) {
const types = Array.isArray(typesOrType) ? typesOrType : [typesOrType];
for (let i = 0; i < types.length; i++) {
this.onSingleEvent(types[i], fn, that, once);
}
}
once(types, fn, that = undefined) {
this.$$on(types, fn, that, true);
return this;
}
onSingleEvent(type, fn, that, once) {
if ('function' !== typeof fn) {
throw new TypeError('EventEmitter::onSingleEvent() requires function listener');
}
const listener = createListener(fn, that, type, once);
if (!(type in this.$$events)) {
this.$$events[type] = [];
}
this.$$events[type].push(listener);
}
removeListener(...args) {
return this.off(...args);
}
};
};