elexis/lib/$NodeManager.ts
defaultkavy 4c078c26b6
v0.3.0
- remove: class $EventMethod, $Event.
- change: $EventManager rewrite logic.
- change: most $Node base node element generic type have new EM(EventMap) parameter.
- new: $EventTarget.
- change: $Node extends $EventTarget.
- change: mix dom events and $EventManager events into $EventTarget.on().off().once().
- fix: $Container.insert() process synchronous when passing an not async function
- new: $Window element.
- fix: $(document.documentElement) throw error.
- new: $KeyboardManager, $FocusManager, $PointerManager.
- new: $ global methods:
  - $.events() return new $EventManager.
  - $.pointers() return new $PointerManager.
  - $.keys() return new $KeyboardManager.
  - $.focus() return new $FocusManager.
  - $.call()
- change: $Media extends $HTMLElement
- change: $Anchor.href() support $State parameter.
- new: $State.convert()
2024-10-17 11:54:28 +08:00

71 lines
2.4 KiB
TypeScript

import { $Container } from "./node/$Container";
import { $Node } from "./node/$Node";
export class $NodeManager {
readonly $container: $Container;
readonly childList = new Set<$Node>
constructor(container: $Container) {
this.$container = container;
}
add(element: $Node, position = -1) {
if (position === -1 || this.childList.size - 1 === position) {
this.childList.add(element);
} else {
const children = [...this.childList]
children.splice(position, 0, element);
this.childList.clear();
children.forEach(child => this.childList.add(child));
}
(element as Mutable<$Node>).parent = this.$container;
}
remove(element: $Node) {
if (!this.childList.has(element)) return this;
this.childList.delete(element);
(element as Mutable<$Node>).parent = undefined;
return this;
}
removeAll(render = true) {
this.childList.forEach(ele => this.remove(ele));
if (render) this.render();
}
replace(target: $Node, replace: $Node) {
const array = this.array
array.splice(array.indexOf(target), 1, replace);
target.remove();
this.childList.clear();
array.forEach(node => this.childList.add(node));
(replace as Mutable<$Node>).parent = this.$container;
return this;
}
render() {
const [domList, nodeList] = [this.array.map(node => node.dom), Array.from(this.dom.childNodes)];
const appendedNodeList: Node[] = []; // appended node list
// Rearrange
while (nodeList.length || domList.length) { // while nodeList or domList has item
const [node, dom] = [nodeList.at(0), domList.at(0)];
if (!dom) { if (node && !appendedNodeList.includes(node)) node.remove(); nodeList.shift()}
else if (!node) { if (!dom.$.hide()) this.dom.append(dom); domList.shift();}
else if (dom !== node) {
if (!dom.$.hide()) { this.dom.insertBefore(dom, node); appendedNodeList.push(dom) }
domList.shift();
}
else {
if (dom.$.hide()) this.dom.removeChild(dom);
domList.shift(); nodeList.shift();
}
}
}
indexOf(target: $Node) {
return this.array.indexOf(target);
}
get array() {return [...this.childList.values()]};
get dom() {return this.$container.dom}
}