/// import { templateNoop, HTML_ESCAPES, xss } from "./string.ts" export { HTML_ESCAPES } /** * Parses HTML, kinda smart. * * As a function, it just parses the string as HTML. When used as a tagged template, expressions are XSS escaped using {@link xss}, except Nodes, which are added to the tree. * * ```js * html("

Hello world!

") * // DocumentFragment * // └─ p * // └─ "Hello world!" * html` * ${html`Look ma, nested HTML!`} * ${``} * ` * * // DocumentFragment * // └─ strong * // ├─ em * // │ └─ "Look ma, nested HTML!" * // └─ "" * ``` * @author MindfulMinun * @since 2020-06-23 */ export function html(content: string): DocumentFragment export function html(strings: TemplateStringsArray, ...exprs: unknown[]): DocumentFragment export function html(strings: TemplateStringsArray | string, ...exprs: unknown[]): DocumentFragment { const temp = document.createElement("template") let out = "" if (typeof strings === "string") { temp.innerHTML = strings return temp.content.cloneNode(true) as DocumentFragment } // Join the strings together for (let i = 0; i < strings.length; i++) { // If it's another Node, put a template in its place so we can replace it later if (exprs[i] instanceof Node) { out += strings[i] + `` continue } // Otherwise, just join the expressions together, escaping dynamic content out += strings[i] + (typeof exprs[i] != 'undefined' ? xss("" + exprs[i]) : "") } temp.innerHTML = out const clone = temp.content.cloneNode(true) as DocumentFragment // Replace all templates with the real nodes clone.querySelectorAll("template[data-replaceindex]").forEach(node => { if (!(node instanceof HTMLElement)) return if (!node.parentNode) return const index = parseInt(node.getAttribute("data-replaceindex") || "", 10) node.parentNode.replaceChild(exprs[index] as Node, node); }) return clone } /** * Creates a text node for use in the DOM. The text content is NOT escaped. * @author MindfulMinun * @since 2022-06-04 */ export function textNode(templ: string): Text export function textNode(templ: TemplateStringsArray, ...values: unknown[]): Text export function textNode(templ: string | TemplateStringsArray, ...values: unknown[]): Text { const string = templateNoop(templ, ...values) return document.createTextNode(string) } /** * Walks the DOM recursively, calling the callback for each node. * @deprecated * @param root - The root of the DOM walk * @param callback - If this callback returns true, stop tree traversal. * @param filters - A bitmask of what nodes to show. Defaults to `NodeFilter.SHOW_ELEMENT`. * @author MindfulMinun * @since 2020-06-29 */ export function domWalker( root: Node, callback: (node: Node, root: Node, walker: TreeWalker) => boolean, filters: number = NodeFilter.SHOW_ELEMENT ) { const walker = document.createTreeWalker(root, filters); let guard = false; let current: Node | null = walker.currentNode while (true) { if (!current) break if (guard) break guard = callback.call(null, current, root, walker); current = walker.nextNode() } }