rittenhop-dev/versions/5.94.2/node_modules/lib0/observable.js
2024-09-23 19:40:12 -04:00

162 lines
3.6 KiB
JavaScript

/**
* Observable class prototype.
*
* @module observable
*/
import * as map from './map.js'
import * as set from './set.js'
import * as array from './array.js'
/**
* Handles named events.
* @experimental
*
* This is basically a (better typed) duplicate of Observable, which will replace Observable in the
* next release.
*
* @template {{[key in keyof EVENTS]: function(...any):void}} EVENTS
*/
export class ObservableV2 {
constructor () {
/**
* Some desc.
* @type {Map<string, Set<any>>}
*/
this._observers = map.create()
}
/**
* @template {keyof EVENTS & string} NAME
* @param {NAME} name
* @param {EVENTS[NAME]} f
*/
on (name, f) {
map.setIfUndefined(this._observers, /** @type {string} */ (name), set.create).add(f)
return f
}
/**
* @template {keyof EVENTS & string} NAME
* @param {NAME} name
* @param {EVENTS[NAME]} f
*/
once (name, f) {
/**
* @param {...any} args
*/
const _f = (...args) => {
this.off(name, /** @type {any} */ (_f))
f(...args)
}
this.on(name, /** @type {any} */ (_f))
}
/**
* @template {keyof EVENTS & string} NAME
* @param {NAME} name
* @param {EVENTS[NAME]} f
*/
off (name, f) {
const observers = this._observers.get(name)
if (observers !== undefined) {
observers.delete(f)
if (observers.size === 0) {
this._observers.delete(name)
}
}
}
/**
* Emit a named event. All registered event listeners that listen to the
* specified name will receive the event.
*
* @todo This should catch exceptions
*
* @template {keyof EVENTS & string} NAME
* @param {NAME} name The event name.
* @param {Parameters<EVENTS[NAME]>} args The arguments that are applied to the event listener.
*/
emit (name, args) {
// copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.
return array.from((this._observers.get(name) || map.create()).values()).forEach(f => f(...args))
}
destroy () {
this._observers = map.create()
}
}
/* c8 ignore start */
/**
* Handles named events.
*
* @deprecated
* @template N
*/
export class Observable {
constructor () {
/**
* Some desc.
* @type {Map<N, any>}
*/
this._observers = map.create()
}
/**
* @param {N} name
* @param {function} f
*/
on (name, f) {
map.setIfUndefined(this._observers, name, set.create).add(f)
}
/**
* @param {N} name
* @param {function} f
*/
once (name, f) {
/**
* @param {...any} args
*/
const _f = (...args) => {
this.off(name, _f)
f(...args)
}
this.on(name, _f)
}
/**
* @param {N} name
* @param {function} f
*/
off (name, f) {
const observers = this._observers.get(name)
if (observers !== undefined) {
observers.delete(f)
if (observers.size === 0) {
this._observers.delete(name)
}
}
}
/**
* Emit a named event. All registered event listeners that listen to the
* specified name will receive the event.
*
* @todo This should catch exceptions
*
* @param {N} name The event name.
* @param {Array<any>} args The arguments that are applied to the event listener.
*/
emit (name, args) {
// copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.
return array.from((this._observers.get(name) || map.create()).values()).forEach(f => f(...args))
}
destroy () {
this._observers = map.create()
}
}
/* c8 ignore end */