UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering

183 lines (166 loc) 4.33 kB
import { type AsyncBoolean, toAsyncBoolean } from '../function' import type { EventArgs, EventNames, Handler, NamesWithArrayArgs, OptionalNormalNames, OtherNames, RequiredNormalNames, UnknownNames, } from './types' import { call } from './util' export class Events<Args extends EventArgs = any> { private listeners: { [name: string]: any[] } = {} on<Name extends EventNames<Args>>( name: Name, handler: Handler<Args[Name]>, context?: any, ): this on<Name extends UnknownNames<Args>>( name: Name, handler: Handler<any>, context?: any, ): this on<Name extends EventNames<Args>>( name: Name, handler: Handler<Args[Name]>, context?: any, ) { if (handler == null) { return this } if (!this.listeners[name]) { this.listeners[name] = [] } const cache = this.listeners[name] cache.push(handler, context) return this } once<Name extends EventNames<Args>>( name: Name, handler: Handler<Args[Name]>, context?: any, ): this once<Name extends UnknownNames<Args>>( name: Name, handler: Handler<any>, context?: any, ): this once<Name extends EventNames<Args>>( name: Name, handler: Handler<Args[Name]>, context?: any, ) { const cb = (...args: any) => { this.off(name, cb as any) return call([handler, context], args) } return this.on(name, cb as any, this) } off(): this off(name: null, handler: Handler<any>): this off(name: null, handler: null, context: any): this off<Name extends EventNames<Args>>( name: Name, handler?: Handler<Args[Name]>, context?: any, ): this off<Name extends UnknownNames<Args>>( name: Name, handler?: Handler<any>, context?: any, ): this off(name?: string | null, handler?: Handler<any> | null, context?: any) { // remove all events. if (!(name || handler || context)) { this.listeners = {} return this } const listeners = this.listeners const names = name ? [name] : Object.keys(listeners) names.forEach((n) => { const cache = listeners[n] if (!cache) { return } // remove all events with specified name. if (!(handler || context)) { delete listeners[n] return } for (let i = cache.length - 2; i >= 0; i -= 2) { if ( !( (handler && cache[i] !== handler) || (context && cache[i + 1] !== context) ) ) { cache.splice(i, 2) } } }) return this } trigger<Name extends OptionalNormalNames<Args>>(name: Name): AsyncBoolean trigger<Name extends RequiredNormalNames<Args>>( name: Name, args: Args[Name], ): AsyncBoolean trigger<Name extends NamesWithArrayArgs<Args>>( name: Name, ...args: Args[Name] ): AsyncBoolean trigger<Name extends OtherNames<Args>>( name: Name, args?: Args[Name], ): AsyncBoolean trigger<Name extends OtherNames<Args>>( name: Name, ...args: Args[Name] ): AsyncBoolean trigger<Name extends UnknownNames<Args>>( name: Name, ...args: any[] ): AsyncBoolean trigger<Name extends EventNames<Args>>(name: Name, ...args: any[]) { let returned: AsyncBoolean = true if (name !== '*') { const list = this.listeners[name] if (list != null) { returned = call([...list], args) } } const list = this.listeners['*'] if (list != null) { return toAsyncBoolean([returned, call([...list], [name, ...args])]) } return returned } /** * Triggers event with specified event name. Unknown names * will cause a typescript type error. */ protected emit<Name extends OptionalNormalNames<Args>>( name: Name, ): AsyncBoolean protected emit<Name extends RequiredNormalNames<Args>>( name: Name, args: Args[Name], ): AsyncBoolean protected emit<Name extends NamesWithArrayArgs<Args>>( name: Name, ...args: Args[Name] ): AsyncBoolean protected emit<Name extends OtherNames<Args>>( name: Name, args?: Args[Name], ): AsyncBoolean protected emit<Name extends OtherNames<Args>>( name: Name, ...args: Args[Name] ): AsyncBoolean protected emit(name: any, ...args: any[]) { return this.trigger(name, ...args) } }