export function $(expr, con) { return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; } export function findNodeIndex(node) { var i = 0; while (node.previousSibling) { node = node.previousSibling; i++; } return i; } $.create = (tag, o) => { var element = document.createElement(tag); for (var i in o) { var val = o[i]; if (i === "inside") { $(val).appendChild(element); } else if (i === "around") { var ref = $(val); ref.parentNode.insertBefore(element, ref); element.appendChild(ref); } else if (i === "onClick" ) { element.addEventListener('click', val); } else if (i === "onInput" ) { element.addEventListener('input', function(e) { val(element.value); }); } else if (i === "onChange" ) { element.addEventListener('change', function(e) { val(element.value); }); } else if (i === "styles") { if(typeof val === "object") { Object.keys(val).map(prop => { element.style[prop] = val[prop]; }); } } else if (i in element ) { element[i] = val; } else { element.setAttribute(i, val); } } return element; }; export function getOffset(element) { let rect = element.getBoundingClientRect(); return { // https://stackoverflow.com/a/7436602/6495043 // rect.top varies with scroll, so we add whatever has been // scrolled to it to get absolute distance from actual page top top: rect.top + (document.documentElement.scrollTop || document.body.scrollTop), left: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft) }; } export function isElementInViewport(el) { // Although straightforward: https://stackoverflow.com/a/7557433/6495043 var rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */ rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ ); } export function getElementContentWidth(element) { var styles = window.getComputedStyle(element); var padding = parseFloat(styles.paddingLeft) + parseFloat(styles.paddingRight); return element.clientWidth - padding; } export function bind(element, o){ if (element) { for (var event in o) { var callback = o[event]; event.split(/\s+/).forEach(function (event) { element.addEventListener(event, callback); }); } } } export function unbind(element, o){ if (element) { for (var event in o) { var callback = o[event]; event.split(/\s+/).forEach(function(event) { element.removeEventListener(event, callback); }); } } } export function fire(target, type, properties) { var evt = document.createEvent("HTMLEvents"); evt.initEvent(type, true, true ); for (var j in properties) { evt[j] = properties[j]; } return target.dispatchEvent(evt); } // https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/ export function forEachNode(nodeList, callback, scope) { if(!nodeList) return; for (var i = 0; i < nodeList.length; i++) { callback.call(scope, nodeList[i], i); } } export function activate($parent, $child, commonSelector, activeClass='active', index = -1) { let $children = $parent.querySelectorAll(`${commonSelector}.${activeClass}`); if (typeof $child === 'string') { $child = $parent.querySelector($child); } this.forEachNode($children, (node, i) => { if(index >= 0 && i <= index) return; node.classList.remove(activeClass); }) $child.classList.add(activeClass); } export function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); }