first commit
This commit is contained in:
77
xterminal/source/emitter/index.ts
Normal file
77
xterminal/source/emitter/index.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import Disposable from "../base/disposable";
|
||||
import type {
|
||||
XEventEmitter as IEventEmitter,
|
||||
IEventListener,
|
||||
IEventName
|
||||
} from "../types";
|
||||
import type { IEmitterState } from "./interface";
|
||||
|
||||
/**
|
||||
* EventEmitter class
|
||||
*
|
||||
* https://nodejs.dev/api/events.html
|
||||
*
|
||||
* https://nodejs.dev/en/learn/the-nodejs-event-emitter/
|
||||
*/
|
||||
export default class XEventEmitter extends Disposable implements IEventEmitter {
|
||||
// private store for states
|
||||
#state: IEmitterState;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.#state = {
|
||||
stack: [],
|
||||
store: new Map()
|
||||
};
|
||||
this.register({ dispose: () => this.#state.store.clear() });
|
||||
}
|
||||
|
||||
public on(eventName: IEventName, listener: IEventListener): void {
|
||||
const store = this.#state.store;
|
||||
if (store.has(eventName)) {
|
||||
store.get(eventName)?.add(listener);
|
||||
} else {
|
||||
store.set(eventName, new Set([listener]));
|
||||
}
|
||||
}
|
||||
|
||||
public once(eventName: IEventName, listener: IEventListener): void {
|
||||
const evlistener = (...args: unknown[]) => {
|
||||
listener.call(undefined, ...args);
|
||||
this.off(eventName, evlistener);
|
||||
};
|
||||
const store = this.#state.store;
|
||||
if (store.has(eventName)) {
|
||||
store.get(eventName)?.add(evlistener);
|
||||
} else {
|
||||
store.set(eventName, new Set([evlistener]));
|
||||
}
|
||||
}
|
||||
|
||||
public off(eventName: IEventName, listener: IEventListener): void {
|
||||
const all = this.#state.store.get(eventName);
|
||||
if (all) {
|
||||
for (const fn of all) {
|
||||
if (fn === listener) {
|
||||
all.delete(listener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public emit(eventName: IEventName, ...args: unknown[]): void {
|
||||
if (this.isDisposed) return;
|
||||
const stack = this.#state.stack;
|
||||
if (stack.includes(eventName)) return;
|
||||
const listeners = this.#state.store.get(eventName);
|
||||
if (listeners) {
|
||||
stack.push(eventName);
|
||||
for (const fn of listeners) {
|
||||
fn.call(undefined, ...args);
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
9
xterminal/source/emitter/interface.ts
Normal file
9
xterminal/source/emitter/interface.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { IEventName, IEventListener } from "../types";
|
||||
|
||||
/**
|
||||
* State of the Event Emitter
|
||||
*/
|
||||
export type IEmitterState = {
|
||||
store: Map<IEventName, Set<IEventListener>>;
|
||||
stack: IEventName[];
|
||||
};
|
||||
Reference in New Issue
Block a user