import EventContainer from "../event/EventContainer.js"; import EventRecord from "../event/EventRecord.js"; import TreeNode from "./TreeNode.js"; export default abstract class EventTreeNode< T extends EventTreeNode, E extends EventRecord, > extends TreeNode { private readonly events = new EventContainer void }>(); private subscriptions: Array<{ target: EventTreeNode; eventName: string; handler: (...args: any[]) => any; removeHandler: () => void; }> = []; public on void })>( eventName: K, handler: (E & { remove: () => void })[K], ): this { this.events.on(eventName, handler); return this; } public off void })>( eventName: K, handler?: (E & { remove: () => void })[K], ): this { this.events.off(eventName, handler); return this; } protected hasEvent(eventName: K): boolean { return this.events["hasEvent"](eventName); } protected emit void })>( eventName: K, ...args: Parameters<(E & { remove: () => void })[K]> ) { return this.events["emit"](eventName, ...args); } public subscribe< E2 extends (EventRecord & { remove: () => void }), K extends keyof E2, >( target: EventTreeNode, eventName: K, handler: E2[K], ): this { target.on(eventName, handler); const removeHandler = () => { const findIndex = this.subscriptions.findIndex( (s) => s.target === target && s.eventName === eventName && s.handler === handler, ); if (findIndex !== -1) this.subscriptions.splice(findIndex, 1); }; target.on("remove", removeHandler); this.subscriptions.push({ target, eventName: eventName as string, handler, removeHandler, }); return this; } public override remove(): void { if (this.removed) return; this.emit( "remove", ...([] as Parameters<(E & { remove: () => void })["remove"]>), ); this.events["clearEvents"](); for (const s of this.subscriptions) { s.target.off(s.eventName, s.handler); s.target.off("remove", s.removeHandler); } delete (this as any).subscriptions; super.remove(); } }