keet
Version:
Minimalist view layer for the web
97 lines (86 loc) • 3.21 kB
JavaScript
import replaceCommentBlock from './replaceCommentBlock'
import inspectAttributes from './inspectAttributes'
import replaceHandleBars from './replaceHandleBars'
import conditionalNodes from '../conditionalNodes'
import { getId } from '../../../utils'
import { addEvent, addEventModel } from './addEvent'
const conditionalNodesRawStart = /\{\{\?([^{}]+)\}\}/g
const reConditional = /([^{?])(.*?)(?=\}\})/g
const re = /{{([^{}]+)}}/g
const modelRaw = /\{\{model:([^{}]+)\}\}/g
const DOCUMENT_ELEMENT_TYPE = 1
const DOCUMENT_COMMENT_TYPE = 8
function testEventNode (node) {
let nodeAttributes = node.attributes
let i = 0
let a
let name
let value
let evtName
let handler
let evtStore = []
let obs
let args
while (i < nodeAttributes.length) {
a = nodeAttributes[i]
name = a.localName
value = a.nodeValue
if (/^k-/.test(name)) {
evtName = name.replace(/^k-/, '')
handler = value.match(/[a-zA-Z]+(?![^(]*\))/)[0]
args = value.match(/\(([^{}]+)\)/)
args = args ? args[1] : ''
obs = {}
obs[evtName] = handler
if (args) obs[args] = true
obs['isModel'] = false
evtStore.push(obs)
if (node.hasChildNodes() && node.firstChild.nodeType !== DOCUMENT_ELEMENT_TYPE && node.firstChild.nodeValue.match(modelRaw)) {
obs['isModel'] = true
}
}
i++
}
return evtStore
}
let events
let c
let currentNode
function recon (node, addState, model) {
while (node) {
currentNode = node
node = node.nextSibling
if (currentNode.nodeType === DOCUMENT_ELEMENT_TYPE) {
if (currentNode.hasAttributes()) {
inspectAttributes.call(this, currentNode, addState, model)
// to take advantage of caching always assigned id to the node
// we only assign eventListener on first mount to DOM or when the node is not available on DOM
if (!getId(currentNode.id)) {
events = testEventNode.call(this, currentNode)
if (events.length) {
events.map(e => {
!e.isModel ? addEvent.call(this, currentNode, e) : addEventModel.call(this, currentNode, e)
currentNode.removeAttribute(`k-${Object.keys(e)[0]}`)
})
}
}
}
recon.call(this, currentNode.firstChild, addState, model)
} else if (currentNode.nodeType === DOCUMENT_COMMENT_TYPE && currentNode.nodeValue.match(conditionalNodesRawStart)) {
c = currentNode.nodeValue.trim().match(reConditional)
c = c && c[0]
if (this[c]) {
conditionalNodes.call(this, currentNode, c, 'conditional-set', reconcile, addState)
}
} else if (currentNode.nodeType === DOCUMENT_COMMENT_TYPE && currentNode.nodeValue.match(re) && !currentNode.nodeValue.match(conditionalNodesRawStart)) {
replaceCommentBlock.call(this, currentNode.nodeValue, currentNode, reconcile, model, addState)
} else {
replaceHandleBars.call(this, currentNode.nodeValue, currentNode, addState, null, model)
}
}
}
// instance, addState, model
function reconcile () {
recon.apply(this, arguments)
}
export default reconcile