Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function View(template, model, parentNode) {
- this.model = model
- this.parentNode = null
- this.bindings = {}
- this.node = document.importNode(template.content, true)
- this.childNodesSlice = Array.prototype.slice.apply(this.node.childNodes)
- this.discoverNodes(this.node.childNodes)
- this.setupObserve()
- if (parentNode) {
- this.mount(parentNode)
- }
- }
- View.prototype.discoverNodes = function(nodes) {
- for (var i = 0; i < nodes.length; i++) {
- this.discoverNode(nodes[i])
- }
- }
- View.prototype.discoverNode = function(node) {
- switch (node.nodeType) {
- case Node.ELEMENT_NODE:
- this.discoverElementNode(node)
- break
- case Node.ATTRIBUTE_NODE:
- this.discoverAttributeNode(node)
- break
- case Node.TEXT_NODE:
- this.discoverTextNode(node)
- break
- default:
- throw new Error("incompatible node came into View.discoverNode")
- }
- }
- View.prototype.discoverElementNode = function(node) {
- if (node.tagName === "TEMPLATE") {
- this.discoverTemplateNode(node)
- } else {
- this.discoverNodes(node.attributes)
- this.discoverNodes(node.childNodes)
- }
- }
- View.prototype.discoverAttributeNode = function(node) {
- var textFragments = node.value.split(/(\{\{.+?\}\})/g).filter(function(s){
- return s !== ""
- })
- var hasExpression = false
- var expression = textFragments.map(function(s){
- m = s.match(/^\{\{(.+)\}\}$/)
- if (m) {
- hasExpression = true
- return m[1]
- } else {
- return JSON.stringify(s)
- }
- }).join(" + ")
- if (hasExpression) {
- this.bindNode(node, expression)
- }
- }
- View.prototype.discoverTextNode = function(node) {
- var textFragments = node.data.split(/(\{\{.+?\}\})/g).filter(function(s){
- return s !== ""
- })
- if (textFragments.length > 1) {
- for (var i in textFragments) {
- var s = textFragments[i]
- var textNode = document.createTextNode(s)
- m = s.match(/^\{\{(.+)\}\}$/)
- if (m) this.bindNode(textNode, m[1])
- node.parentNode.insertBefore(textNode, node)
- }
- node.parentNode.removeChild(node)
- } else if (textFragments.length === 1) {
- var s = textFragments[0]
- m = s.match(/^\{\{(.+)\}\}$/)
- if (m) this.bindNode(node, m[1])
- }
- }
- View.prototype.discoverTemplateNode = function(node) {
- var mountPoint = document.createTextNode("")
- node.parentNode.insertBefore(mountPoint, node)
- node.remove()
- node.mountPoint = mountPoint
- this.discoverNodes(node.attributes)
- }
- View.prototype.applyNodeValue = function(node, value) {
- switch (node.nodeType) {
- case Node.ATTRIBUTE_NODE:
- if (node.ownerElement.tagName === "TEMPLATE") {
- var template = node.ownerElement
- switch (node.name) {
- case "if":
- if (!!value) {
- template.mountPoint.renderedView = new View(
- template, this.model, template.mountPoint)
- } else {
- if (template.mountPoint.renderedView) {
- template.mountPoint.renderedView.destroy()
- }
- }
- break;
- case "loop":
- if (!!value && value instanceof Array && value.length > 0) {
- template.mountPoint.renderedViews = value.map(function(v) {
- return new View(template, v, template.mountPoint)
- })
- } else {
- if (template.mountPoint.renderedViews) {
- template.mountPoint.renderedViews.forEach(function(view){
- view.destroy()
- })
- }
- }
- break
- default:
- throw new Error("don't know how to apply value on " + node.name + " attribute of template")
- }
- } else {
- node.value = value
- }
- break
- case Node.TEXT_NODE:
- node.data = value
- break
- default:
- throw new Error("incompatible node came into View.applyNodeValue")
- }
- }
- View.prototype.bindNode = function(node, expression) {
- if (!this.bindings[expression]) {
- this.bindings[expression] = []
- }
- this.bindings[expression].push(node)
- this.applyNodeValue(node, evalInContext(expression, this.model))
- }
- View.prototype.setupObserve = function() {
- if (!this.model) {
- return
- }
- var model = this.model
- var bindings = this.bindings
- var applyNodeValue = this.applyNodeValue.bind(this)
- // to be written
- Object.observe(model, function(changes){
- changes.forEach(function(change){
- if (change.name in bindings) {
- bindings[change.name].forEach(function(node){
- applyNodeValue(node, evalInContext(change.name, model))
- })
- }
- })
- })
- }
- View.prototype.unmount = function() {
- if (!this.parentNode) {
- return
- }
- for (var i = 0; i < this.childNodesSlice.length; i++) {
- this.childNodesSlice[i].remove()
- }
- }
- View.prototype.destroy = function() {
- this.unmount()
- // to be written
- }
- View.prototype.mount = function(parentNode) {
- if (parentNode.nodeType === Node.TEXT_NODE) {
- parentNode.parentNode.insertBefore(this.node, parentNode)
- this.parentNode = parentNode.parentNode
- } else {
- parentNode.appendChild(this.node)
- this.parentNode = parentNode
- }
- }
- View.queryTemplate = function(templateName, rootDocument) {
- rootDocument = rootDocument || document
- var template = rootDocument.querySelector("template[name='" + templateName + "']")
- if (template) {
- return template
- }
- imports = rootDocument.querySelectorAll('link[rel="import"]')
- for (var i = 0; i < imports.length; i++) {
- template = View.queryTemplate(templateName, imports[i].import)
- if (template) {
- return template
- }
- }
- throw new Error("cannot find template " + templateName)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement