Created
August 7, 2020 08:45
-
-
Save Cloudo/a40311b630f31efc47306bd6ce2b73b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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