let _LCounter = 0; const NodeMap = new WeakMap(); /** Core wrapper for {@link HTMLElement DOM elements}. */ export class Node { wraps: HTMLElement; children: Node[] = []; id: string = "L" + _LCounter++; /** * Creates a node, wrapping an HTML element. * @example new Node(document.createElement("h1")); */ constructor(wraps: HTMLElement) { this.wraps = wraps; this.wraps.id = this.id; } /** Adds a child node. Should not be overridden. */ add(node: NodeEquivalent) { if (node != undefined) { let xnode: Node; if (typeof node === "string") { xnode = new Label(node); } else { xnode = node; } this.children.push(xnode); this.wraps.appendChild(xnode.wraps); } else { throw new Error("node undefined"); } return this; } /** Works similarly to {@link add}, but takes multiple nodes and is the one you would want to override. */ with(...nodes: NodeEquivalent[]) { nodes.forEach(x=>{this.add(x)}); return this; } /** Removes a child node in the same way {@link add} does. */ delete(node: Node) { let idx = this.children.indexOf(node); if (idx < 0) { throw new Error(`Node ${node.id} not found.`); } this.children.splice(idx, 1); this.wraps.removeChild(node.wraps); } /** Removes one or more child nodes, like {@link with} does adding them. */ remove(...nodes: Node[]) { nodes.forEach(x=>{this.delete(x)}); return this; } /** Conveniently chain-able callback thing for styling your nodes. * @example new Label("This is a label!").style((s)=>{s.color="maroon";}) */ style(fn: (style: CSSStyleDeclaration) => void) { fn(this.wraps.style); return this; } /** Adds a CSS class to your node. * @example new Container().class("my-class") */ class(cls: string) { this.wraps.classList.add(cls); return this; } /** Hopefully, this points at the parent element. */ get parent(): Node | undefined{ if (this.wraps.parentElement == null) return undefined; return NodeMap.get(this.wraps.parentElement); } } type NodeEquivalent = (Node | string); enum LinkTarget { THIS_TAB = "_this", NEW_TAB = "_blank", OUT_FRAME = "_parent", NOT_FRAME = "_top" } /** Wrapper for {@link HTMLAnchorElement ``} */ export class Link extends Node { constructor(around: NodeEquivalent | null) { let a = document.createElement("a"); a.classList.add("LLink"); super(a); if (around != null) { this.add(around); } } set destination(x: string) { (this.wraps as HTMLAnchorElement).href = x; } // noinspection JSUnusedGlobalSymbols get destination(): string { return (this.wraps as HTMLAnchorElement).href; } set target(x: string) { (this.wraps as HTMLAnchorElement).target = x; } get target(): string { return (this.wraps as HTMLAnchorElement).target; } to(dst: string, tgt: LinkTarget = LinkTarget.NEW_TAB) { this.destination = dst; this.target = tgt; return this; } } /** Wrapper for {@link HTMLDivElement `
`} */ export class Container extends Node { constructor() { let div = document.createElement("div"); div.classList.add("LContainer"); super(div); } } /** Vertical Flexbox container */ export class Column extends Container { constructor() { super(); this.wraps.classList.add("LColumn"); } } /** Horizontal Flexbox container */ export class Row extends Container { constructor() { super(); this.wraps.classList.add("LRow"); } } /** Wrapper for {@link HTMLTableElement ``} */ export class Table extends Node { constructor() { let table = document.createElement("table"); table.classList.add("LTable"); super(table); } } /** Wrapper for {@link HTMLTableRowElement ``} */ export class TableRow extends Node { constructor() { let tr = document.createElement("tr"); tr.classList.add("LTableRow"); super(tr); } } /** Wrapper for {@link HTMLTableCellElement `
`} */ export class TableCell extends Node { constructor() { let td = document.createElement("td"); td.classList.add("LTableCell"); super(td); } } /** An "abstract" class of sorts for {@link HTMLElement}s that have a textContent member. */ export class Text extends Node { private _text: string = ""; get text() { return this._text; } set text(x) { this._text = x; this.wraps.textContent = x; } } /** Wrapper for {@link HTMLSpanElement ``} */ export class Label extends Text { constructor(text: string = "") { let el = document.createElement("span"); el.classList.add("LLabel"); super(el); this.text = text; } } /** Wrapper for {@link HTMLButtonElement `