open-vault/website/assets/js/utils.js

71 lines
1.9 KiB
JavaScript

import { render } from 'preact'
import { hydrateInitialState } from 'reshape-preact-components/lib/browser'
// rehydrates and initializes top-level preact components
export function initializeComponents(obj) {
const res = {}
for (let k in obj) {
const name = getName(k)
res[name] = []
each(document.querySelectorAll(`.g-${name}`), el => {
// do not initialize nested components
const matches = Object.keys(obj)
.map(getName)
.reduce((m, name) => {
const parent = findParent(el, `.g-${name}`)
if (parent) m.push(parent)
return m
}, [])
if (matches.length > 1) return
// if there's no data-state, don't try
if (!el.dataset.state || !el.dataset.state.length) {
return
}
// otherwise, initialize away
const vdom = hydrateInitialState(el.dataset.state, {
[`hashi-${name}`]: obj[k]
})
res[name].push(render(vdom, el.parentElement, el))
})
}
return res
function getName(s) {
return s.replace(/([A-Z])/g, '-$1').toLowerCase()
}
}
// iterates through a NodeList
export function each(list, cb) {
for (let i = 0; i < list.length; i++) {
cb(list[i], i)
}
}
// polyfills object-fit in unsupported browsers
export function fixObjectFit() {
if (Modernizr.objectfit) {
import('object-fit-images').then(ofi => {
ofi.default()
})
}
}
// given an element and selector, finds the closest parent element. doesn't
// handle attribute selectors, just class, id, and element name
export function findParent(el, selector) {
const firstChar = selector[0]
if (firstChar === '.') {
if (el.classList.contains(selector.substr(1))) return el
} else if (firstChar === '#') {
if (el.id === selector.substr(1)) return el
} else {
if (el.tagName.toLowerCase() === selector) return el
}
if (!el.parentNode.tagName) return undefined
return findParent(el.parentNode, selector)
}