Implement missing methods matching CustomElementRegistry

This commit is contained in:
Talia 2025-08-18 11:02:19 +02:00
parent a5c0502666
commit 74142e375f
Signed by: darkwiiplayer
GPG key ID: 7808674088232B3E

View file

@ -1,5 +1,7 @@
/** @typedef {Promise & {signal: AbortSignal}} PromiseWithSignal */
/** @typedef {(element: HTMLElement, detach: PromiseWithSignal) => void} Callback */
/** @typedef {(element: HTMLElement, detached: PromiseWithSignal) => void} Callback */
/** @typedef {new (element: HTMLElement, detached: PromiseWithSignal) => Object} ControllerClass */
/** @typedef {Callback|ControllerClass} Controller */
export class ControllerList {
/** @type {HTMLElement} */
@ -105,6 +107,11 @@ export class ControllerRegistry {
/** @type {Map<string,Callback>} */
#defined = new Map()
/** @type {Map<string,Controller>} */
#lookup = new Map()
/** @type {Map<Controller,string>} */
#nameLookup = new Map()
#attribute
/** @typedef {Document|DocumentFragment|HTMLElement} Root */
@ -141,20 +148,25 @@ export class ControllerRegistry {
/**
* @param {string} name
* @param {Callback} callback
* @param {Controller} callback
*/
define(name, callback) {
if (this.#nameLookup.has(callback)) console.warn(`Redefining controller ${this.#nameLookup.get(callback)} under new name ${name}:`, callback)
this.#lookup.set(name, callback)
this.#nameLookup.set(callback, name)
if (("function" == typeof callback) && callback.prototype) {
callback = async (element, disconnected) => {
const {proxy, revoke} = Proxy.revocable(element, {})
const controller = new callback(proxy, disconnected)
const controller = new /** @type {ControllerClass} */(callback)(proxy, disconnected)
await disconnected
revoke()
if ("detach" in controller) controller.detach(element)
}
}
this.#defined.set(name, callback)
this.#defined.set(name, /** @type {Callback} */(callback))
const waitingList = this.#waiting.get(name)
@ -162,13 +174,42 @@ export class ControllerRegistry {
this.#attach(element, name)
}
this.#waiting.delete(name)
if (this.#whenDefined.has(name)) {
this.#whenDefined.get(name)[1]?.()
}
}
/** Gets a controller associated with a given name
* @param {string} name
*/
get(name) {
return this.#defined.get(name)
return this.#lookup.get(name)
}
/** Gets the name a controller is registered with
* @param {Controller} controller
*/
getName(controller) {
return this.#nameLookup.get(controller)
}
/** @type {Map<string,[Promise, ()=>void]>} */
#whenDefined = new Map()
/**
* @param {string} name
*/
whenDefined(name) {
if (!this.#whenDefined.has(name)) {
if (this.#defined.has(name)) {
this.#whenDefined.set(name, [Promise.resolve(), undefined])
} else {
let resolve
const promise = new Promise(_resolve => {resolve = _resolve})
this.#whenDefined.set(name, [promise, resolve])
}
}
return this.#whenDefined.get(name)[0]
}
/** @type {WeakMap<HTMLElement,ControllerList>} */
@ -192,18 +233,10 @@ export class ControllerRegistry {
const attached = this.#attached.get(element)
if (attached)
return [...attached.entries().filter(pair => pair[1]).map(pair => pair[0])]
else
else
return []
}
getName(controller) {
// TODO: Return name of controller
}
whenDefined(name) {
// TODO: Return a promise
}
/** @param {HTMLElement} element */
#update(element) {
const names = this.#getControllerNames(element)
@ -238,7 +271,7 @@ export class ControllerRegistry {
if (!this.#attached.has(element)) this.#attached.set(element, new Map())
const attached = this.#attached.get(element)
const callback = this.get(name)
const callback = this.#defined.get(name)
if (callback) {
if (attached.has("name") && attached.get("name")) return console.warn(`Controller ${name} already fully attached`, element)