const $boot = (cb) => { document.addEventListener("DOMContentLoaded", cb); } const $sanitize = (badHTML) => { // this Option hack courtesy of stackoverflow return new Option(badHTML).innerHTML; } const validate_sanitized = (sanitized) => { const check = JSON.stringify(sanitized); console.assert(!check.includes("<"), "YOU BEEN HACKED! Send Zed this:", sanitized); } const $sanitize_data = (data) => { const sanitized = $sanitize(JSON.stringify(data)); validate_sanitized(sanitized); return JSON.parse(sanitized); } const $render = (template, data) => { const sanitized = $sanitize_data(data); const args = Object.keys(sanitized); const values = Object.values(sanitized) const render_func = new Function(...args, `return \`${template.innerHTML}\``) const text = render_func(...values); return $html(text); } const $render_data = (template_id, target_id, data) => { const target = $id(target_id); const template = $id(template_id); let new_data = []; if(Array.isArray(data)) { new_data = data.map((item, i) => { return $render(template, {i, item}); }); } else if(data instanceof Object) { console.log("object rendering", data); new_data.push($render(template, data)); } else { console.error("$render only works with {} or [] data", data); new_data.push($html("ERROR LOOK IN CONSOLE")); } $replace_with(target, new_data); } const $get = (name, inChildren) => { if(inChildren) { return inChildren.querySelector(name); } else { return document.querySelector(name); } } const $all = (name, inChildren) => { if(inChildren) { return inChildren.querySelectorAll(name); } else { return document.querySelectorAll(name); } } const $id = (name, inChildren) => { if(inChildren) { return inChildren.children.namedItem(name); } else { return document.getElementById(name); } } const $class = (name) => { return document.getElementsByClassName(name); } const $name = (name) => { return document.getElementsByTagName(name); } const $filter = (nodes, fn) => { return Array.prototype.filter.call(nodes, fn); } const $next = (node) => { return node.nextElementSibling; } const $previous = (node) => { return node.previousElementSibling; } const $siblings = (node) => { return $filter(node.parentNode.children, child => { return child !== node; }); } const $style_toggle = (node, className) => { node.classList.toggle(className); } const $style_add = (node, className) => { node.classList.add(className); } const $style_del = (node, className) => { node.classList.remove(className); } const $style_of = (node, ruleName) => { return getComputedStyle(node)[ruleName] } const $new = (tag, id, html) => { let new_tag = document.createElement(tag); new_tag.id = id; new_tag.innerHTML = html; return new_tag.cloneNode(true); } const $append = (parent, child) => { parent.appendChild(child); } const $prepend = (parent, node) => { parent.insertBefore(node, parent.firstChild); } const $remove = (parent, child) => { parent.removeChild(child); } const $clone = (node) => { return node.cloneNode(true); } const $contains = (node, child) => { return node !== child && node.contains(child); } const $has = (node, selector) => { return node.querySelector(selector) !== null; } const $empty = (node) => { return node.innerHTML == ''; } const $attribute_of = (node, name) => { return node.getAttribute(name); } const $attribute = (node, name, value) => { return node.setAttribute(name, value); } const $contents_of = (node) => { return node.innerHTML; } const $contents = (node, newhtml) => { node.innerHTML = newhtml; } const $has_class = (node, className) => { return node.classList.contains(className); } const $outer_html = (node) => { return node.outerHTML; } const $replace_with = (node, newNodes) => { node.replaceChildren(...newNodes); } const $matches = (node, selector) => { return node.matches(selector); } const $parent = (node) => { return node.parentNode; } const $text_of = (node) => { return node.textContent; } const $text = (node, newtext) => { node.textContent = newtext; } const $off = (node, eventName, eventHandler) => { node.removeEventListener(eventName, eventHandler); } const $on = (node, eventName, eventHandler) => { node.addEventListener(eventName, eventHandler); } const $now = () => { return Date.now(); } const $html = (htmlString) => { const temp = document.createElement('template'); temp.innerHTML = htmlString; return temp.content; } const $observe = (node_id, cb) => { const options = { root: document, rootMargin: "0px", scrollMargin: "0px", threshold: 1.0, delay: 200, }; const callback = (entries, observer) => { cb(); } const observer = new IntersectionObserver(callback, options); observer.observe($id(node_id)); }