import { type ButtonFeatures, ButtonType, type CheckboxFeatures, type ElementFeatures, type FormFeatures, HyperlinkDestination, type HyperlinkFeatures, type LabelFeatures, type TemplateBuilder } from '../common/template'; function tag(tagName: T, features: ElementFeatures, contents: Node[]): HTMLElementTagNameMap[T] { const element = document.createElement(tagName) if (typeof features.id !== "undefined") { element.id = features.id } if (typeof features.classes !== "undefined") { if (typeof features.classes === "string") { element.classList.add(features.classes) } else { for (const className of features.classes) { element.classList.add(className) } } } if (typeof features.data !== "undefined") { for (const [key, value] of features.data) { element.dataset[key] = value } } for (const node of contents) { element.appendChild(node) } return element } class DOMTemplateBuilderImpl implements TemplateBuilder { makeButton(features: ButtonFeatures, ...contents: Node[]): HTMLButtonElement { const element = tag('button', features, contents) element.classList.add("button") element.type = features.type ?? ButtonType.Button if (typeof features.name === "string") { element.name = features.name } if (typeof features.value === "string") { element.value = features.value } return element } makeCheckbox(features: CheckboxFeatures, ...contents: Node[]): HTMLInputElement { const element = tag('input', features, contents) element.type = "checkbox" element.name = features.name if (features.checked) { element.checked = true } if (typeof features.value === "string") { element.value = features.value } return element } makeDiv(features: ElementFeatures, ...contents: Node[]): HTMLDivElement { return tag('div', features, contents); } makeFooter(features: ElementFeatures, ...contents: Node[]): HTMLElement { return tag('footer', features, contents); } makeForm(features: FormFeatures, ...contents: Node[]): HTMLFormElement { const element = tag('form', features, contents) element.action = features.action element.method = features.method return element; } makeHeader(features: ElementFeatures, ...contents: Node[]): HTMLElement { return tag('header', features, contents) } makeHeading1(features: ElementFeatures, ...contents: Node[]): HTMLHeadingElement { return tag('h1', features, contents); } makeHeading2(features: ElementFeatures, ...contents: Node[]): HTMLHeadingElement { return tag('h2', features, contents); } makeHyperlink(features: HyperlinkFeatures, ...contents: Node[]): HTMLAnchorElement { const element = tag('a', features, contents) element.href = features.url if (features.destination === HyperlinkDestination.External) { element.rel = "external nofollow noreferrer" } if (features.asButton) { element.classList.add("button") element.draggable = false } return element; } makeLabel(features: LabelFeatures, ...contents: Node[]): HTMLLabelElement { const element = tag('label', features, contents) if (typeof features.forId === "string") { element.htmlFor = features.forId } return element; } makeListItem(features: ElementFeatures, ...contents: Node[]): HTMLLIElement { return tag('li', features, contents) } makeNav(features: ElementFeatures, ...contents: Node[]): HTMLElement { return tag('nav', features, contents) } makeNoscript(features: ElementFeatures, ...contents: Node[]): HTMLElement { return tag('noscript', features, contents); } makeParagraph(features: ElementFeatures, ...contents: Node[]): HTMLParagraphElement { return tag('p', features, contents); } makeSpan(features: ElementFeatures, ...contents: Node[]): HTMLSpanElement { return tag('span', features, contents); } makeText(text: string): Text { return document.createTextNode(text); } makeUnorderedList(features: ElementFeatures, ...contents: Node[]): HTMLUListElement { return tag('ul', features, contents); } } export const DOMTemplateBuilder = new DOMTemplateBuilderImpl()