Skip to content

Instantly share code, notes, and snippets.

@Cloudo
Created August 7, 2020 08:45
Show Gist options
  • Save Cloudo/a40311b630f31efc47306bd6ce2b73b1 to your computer and use it in GitHub Desktop.
Save Cloudo/a40311b630f31efc47306bd6ce2b73b1 to your computer and use it in GitHub Desktop.
import _ from 'lodash'
const logger = false
const consoleLog = (...args) => {
if (logger) {
console.log(...args)
}
}
export const testProp = (prop, _v) => {
if (_v === null || _v === undefined) return {}
let v = typeof _v === 'object' ? JSON.stringify(_v) : _v
return {
[`data-attr-${prop}`]: v,
}
}
const walkDom = (start, fn) => {
const walk = element => {
do {
let clean
if (element.nodeType === 1) {
clean = fn(element)
}
if (element.hasChildNodes()) walk(element.firstChild)
clean && clean()
} while ((element = element.nextSibling))
}
if (start.hasChildNodes()) {
walk(start.firstChild)
} else {
walk(start)
}
}
const fromDefault = () => document.body
const domSnap = (options = {}) => {
let from = options.from || fromDefault
let snap = { name: 'app' }
let path = []
if (typeof from === 'string') {
from = document.querySelector(from)
} else if (typeof from === 'function') {
from = from()
}
walkDom(from, el => {
const dataCmp = el.attributes['data-cmp']
let prevPath
if (dataCmp && dataCmp.nodeValue) {
prevPath = [...path]
let children
if (path.length) {
path.push('children')
children = _.get(snap, path) || []
} else {
path = ['children']
children = snap.children || []
}
consoleLog(`[${dataCmp.nodeValue}] start`, path)
const nextChildren = [...children, { name: dataCmp.nodeValue }]
_.set(snap, path, nextChildren)
path.push(nextChildren.length - 1)
}
Array.prototype.slice.call(el.attributes).forEach(attr => {
if (attr.name.startsWith('data-attr')) {
const [, , dataAttrValueKey] = attr.name.split('-')
let dataAttrValue = attr.value || el.textContent
if (dataAttrValue === 'textContent') {
dataAttrValue = el.textContent
}
const attrPath = [...path, dataAttrValueKey]
let prevValue = _.get(snap, attrPath)
let nextValue = dataAttrValue
if (prevValue) {
if (!Array.isArray(prevValue)) {
prevValue = [prevValue]
}
nextValue = [...prevValue, dataAttrValue]
}
if (nextValue === '') return
if (nextValue === 'true') {
nextValue = true
} else if (nextValue === 'false') {
nextValue = false
} else if (typeof nextValue === 'string' && nextValue.startsWith('{')) {
try {
nextValue = JSON.parse(nextValue)
} catch (e) {
console.error('failed to parse json from value >', nextValue)
}
}
_.set(snap, attrPath, nextValue)
}
})
return () => {
if (dataCmp) {
consoleLog(`[${dataCmp.nodeValue}] clean`, path, prevPath)
path = [...prevPath]
}
}
})
if (typeof options.process === 'function') {
const nextSnap = options.process(snap)
if (nextSnap) {
snap = nextSnap
}
}
return snap
}
if (typeof window !== 'undefined') {
window.domSnap = domSnap
}
export default domSnap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment