// DOM Utils /** * Get the first matching element */ export function $(selector: string, context: Pick = document): E | null { return context.querySelector(selector); } /** * Get every matching element as an array */ export function $$(selector: string, context: Pick = document): E[] { const elements = context.querySelectorAll(selector); return [...elements]; } export function showEl(...elements: E[] | ConcatArray[]) { ([] as E[]).concat(...elements).forEach(el => el.classList.remove('hidden')); } export function hideEl(...elements: E[] | ConcatArray[]) { ([] as E[]).concat(...elements).forEach(el => el.classList.add('hidden')); } export function toggleEl(...elements: E[] | ConcatArray[]) { ([] as E[]).concat(...elements).forEach(el => el.classList.toggle('hidden')); } export function clearEl(...elements: E[] | ConcatArray[]) { ([] as E[]).concat(...elements).forEach(el => { while (el.firstChild) el.removeChild(el.firstChild); }); } export function removeEl(...elements: E[] | ConcatArray[]) { ([] as E[]).concat(...elements).forEach(el => el.parentNode?.removeChild(el)); } export function makeEl(tag: Tag, attr?: Partial): HTMLElementTagNameMap[Tag] { const el = document.createElement(tag); if (attr) { for (const prop in attr) { const newValue = attr[prop]; if (typeof newValue !== 'undefined') { el[prop] = newValue as Exclude; } } } return el; } export function insertBefore(existingElement: HTMLElement, newElement: HTMLElement) { existingElement.parentNode?.insertBefore(newElement, existingElement); } export function onLeftClick(callback: (e: MouseEvent) => boolean | void, context: Pick = document): VoidFunction { const handler: typeof callback = event => { if (event.button === 0) callback(event); }; context.addEventListener('click', handler); return () => context.removeEventListener('click', handler); } /** * Execute a function when the DOM is ready */ export function whenReady(callback: VoidFunction): void { if (document.readyState !== 'loading') { callback(); } else { document.addEventListener('DOMContentLoaded', callback); } } export function escapeHtml(html: string): string { return html.replace(/&/g, '&') .replace(/>/g, '>') .replace(/(of: Node): N { return Array.prototype.filter.call(of.childNodes, el => el.nodeType === Node.TEXT_NODE)[0]; }