UNPKG

keet

Version:

Minimalist view layer for the web

91 lines (84 loc) 3.05 kB
import genModelList from './genModelList' const conditionalNodesRawEnd = /\{\{\/([^{}]+)\}\}/g const modelRaw = /\{\{model:([^{}]+)\}\}/g const re = /([^{{model:])(.*?)(?=\}\})/g const DOCUMENT_ELEMENT_TYPE = 1 const DOCUMENT_COMMENT_TYPE = 8 let cache = {} // rebuild the node structure function catchNode (node, start) { let cNode while (node) { cNode = node node = node.nextSibling if (cNode && cNode.nodeType === DOCUMENT_ELEMENT_TYPE) { if (cNode.isEqualNode(start)) { cNode.remove() start = start.nextSibling } else { catchNode(cNode.firstChild, start) } } else if (cNode.isEqualNode(start)) { cNode.remove() start = start.nextSibling } } } function checkHasModel (conditional, node) { let cNode while (node) { cNode = node node = node.nextSibling if (cNode.nodeType === DOCUMENT_ELEMENT_TYPE) { checkHasModel.call(this, conditional, cNode.firstChild) } else if (cNode.nodeType === DOCUMENT_COMMENT_TYPE && cNode.nodeValue.match(modelRaw)) { let model = cNode.nodeValue.trim().match(re) if (model.length) { cache[conditional].models = cache[conditional].models || [] cache[conditional].models = cache[conditional].models.concat(model) // cache the model without propagating DOM changes genModelList.call(this, cNode, model, null) } } } } function resolveConditionalNodes (node, conditional, setup, runner, addState) { let currentNode let cNode let fetchFrag let frag = document.createDocumentFragment() if (setup === 'initial' && !cache.hasOwnProperty(conditional)) { cNode = node while (cNode) { currentNode = cNode cNode = cNode.nextSibling if (currentNode.nodeType !== DOCUMENT_ELEMENT_TYPE && currentNode.nodeValue.match(conditionalNodesRawEnd)) { cNode = null cache[conditional] = cache[conditional] || {} // clean up pristine node catchNode(this.__pristineFragment__.firstChild, frag.firstChild) // check if nodes has model(s) checkHasModel.call(this, conditional, frag.firstChild) cache[conditional].frag = frag } else if (currentNode.nodeType !== DOCUMENT_COMMENT_TYPE) { frag.appendChild(currentNode) } } } else if (setup === 'conditional-set') { if (!cache[conditional] || node.nextSibling.isEqualNode(cache[conditional].frag.firstChild)) return fetchFrag = cache[conditional].frag.cloneNode(true) // if cache has model(s), mark all as dirty, since all were removed from DOM // on last iteration if (cache[conditional].models && cache[conditional].models.length) { cache[conditional].models.map(model => { this[model].dirty = true }) } runner.call(this, fetchFrag.firstChild, addState) node.parentNode.insertBefore(fetchFrag, node.nextSibling) } } export { resolveConditionalNodes as default, cache }