88 lines
2.5 KiB
JavaScript
88 lines
2.5 KiB
JavaScript
import renderTemplateString from "../state/renderTemplateString"
|
|
import appStore from "../state/store"
|
|
import hasBinding from "../state/hasBinding"
|
|
|
|
export const prepareRenderComponent = ({
|
|
ComponentConstructor,
|
|
htmlElement,
|
|
anchor,
|
|
props,
|
|
parentNode,
|
|
contextStoreKey,
|
|
}) => {
|
|
const thisNode = createTreeNode()
|
|
thisNode.parentNode = parentNode
|
|
thisNode.props = props
|
|
thisNode.contextStoreKey = contextStoreKey
|
|
|
|
// the treeNode is first created (above), and then this
|
|
// render method is add. The treeNode is returned, and
|
|
// render is called later (in attachChildren)
|
|
thisNode.render = initialProps => {
|
|
thisNode.component = new ComponentConstructor({
|
|
target: htmlElement,
|
|
props: initialProps,
|
|
hydrate: false,
|
|
anchor,
|
|
})
|
|
|
|
// finds the root element of the component, which was created by the contructor above
|
|
// we use this later to attach a className to. This is how styles
|
|
// are applied by the builder
|
|
thisNode.rootElement = htmlElement.children[htmlElement.children.length - 1]
|
|
|
|
let [componentName] = props._component.match(/[a-z]*$/)
|
|
if (props._id && thisNode.rootElement) {
|
|
thisNode.rootElement.classList.add(`${componentName}-${props._id}`)
|
|
}
|
|
|
|
// make this node listen to the store
|
|
if (thisNode.stateBound) {
|
|
const unsubscribe = appStore.subscribe(state => {
|
|
const storeBoundProps = Object.keys(initialProps._bb.props).filter(p =>
|
|
hasBinding(initialProps._bb.props[p])
|
|
)
|
|
if (storeBoundProps.length > 0) {
|
|
const toSet = {}
|
|
for (let prop of storeBoundProps) {
|
|
const propValue = initialProps._bb.props[prop]
|
|
toSet[prop] = renderTemplateString(propValue, state)
|
|
}
|
|
thisNode.component.$set(toSet)
|
|
}
|
|
}, thisNode.contextStoreKey)
|
|
thisNode.unsubscribe = unsubscribe
|
|
}
|
|
}
|
|
|
|
return thisNode
|
|
}
|
|
|
|
export const createTreeNode = () => ({
|
|
context: {},
|
|
props: {},
|
|
rootElement: null,
|
|
parentNode: null,
|
|
children: [],
|
|
bindings: [],
|
|
component: null,
|
|
unsubscribe: () => {},
|
|
render: () => {},
|
|
get destroy() {
|
|
const node = this
|
|
return () => {
|
|
if (node.children) {
|
|
// destroy children first - from leaf nodes up
|
|
for (let child of node.children) {
|
|
child.destroy()
|
|
}
|
|
}
|
|
if (node.unsubscribe) node.unsubscribe()
|
|
if (node.component && node.component.$destroy) node.component.$destroy()
|
|
for (let onDestroyItem of node.onDestroy) {
|
|
onDestroyItem()
|
|
}
|
|
}
|
|
},
|
|
onDestroy: [],
|
|
})
|