// DOM primitives ported from static/mnw.js. /** * Escape all five HTML-special characters. Safe for both element-content and * attribute interpolation. Ported from mnw.js:19 (the Run 20 single escaper); * the one canonical escaper — feature code must not ship its own. */ export function escapeHtml(s: unknown): string { return String(s) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } /** Attribute-context alias — identical five-char escape (escapeHtml is already * attribute-safe); named separately so call sites read intentfully. */ export const escapeAttr = escapeHtml; /** Resolve `data-target` (space-separated element ids) to the elements that * currently exist. Ported from mnw.js:725. */ export function targets(el: Element): HTMLElement[] { const raw = el.getAttribute('data-target'); if (!raw) return []; return raw .split(/\s+/) .filter(Boolean) .map((id) => document.getElementById(id)) .filter((e): e is HTMLElement => e !== null); } /** `document.getElementById` guarded against null/empty ids. */ export function byId(id: string | null | undefined): HTMLElement | null { return id ? document.getElementById(id) : null; }