From c3eac13aa7106d099e8f09c39518051ccf939060 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 19 Mar 2010 16:41:02 -0700 Subject: showing off problem to corry --- src/Compiler.js | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 src/Compiler.js (limited to 'src/Compiler.js') diff --git a/src/Compiler.js b/src/Compiler.js new file mode 100644 index 00000000..f4d901fb --- /dev/null +++ b/src/Compiler.js @@ -0,0 +1,188 @@ +/** + * Template provides directions an how to bind to a given element. + * It contains a list of init functions which need to be called to + * bind to a new instance of elements. It also provides a list + * of child paths which contain child templates + */ +function Template() { + this.paths = []; + this.children = []; + this.inits = []; +} + +Template.prototype = { + init: function(element, scope) { + foreach(this.inits, function(fn) { + scope.apply(fn, nodeLite(element)); + }); + + var i, + childNodes = element.childNodes, + children = this.children, + paths = this.paths, + length = paths.length; + for (i = 0; i < length; i++) { + children[i].init(childNodes[paths[i]], scope); + } + }, + + addInit:function(init) { + if (init) { + this.inits.push(init); + } + }, + + setExclusiveInit: function(init) { + this.inits = [init]; + this.addInit = noop; + }, + + + addChild: function(index, template) { + this.paths.push(index); + this.children.push(template); + } +}; + +/////////////////////////////////// +//NodeLite +////////////////////////////////// + +function NodeLite(element) { + this.element = element; +} + +function nodeLite(element) { + return element instanceof NodeLite ? element : new NodeLite(element); +} + +NodeLite.prototype = { + eachTextNode: function(fn){ + var i, chldNodes = this.element.childNodes || [], size = chldNodes.length, chld; + for (i = 0; i < size; i++) { + if((chld = new NodeLite(chldNodes[i])).isText()) { + fn(chld, i); + } + } + }, + + eachNode: function(fn){ + var i, chldNodes = this.element.childNodes || [], size = chldNodes.length, chld; + for (i = 0; i < size; i++) { + if(!(chld = new NodeLite(chldNodes[i])).isText()) { + fn(chld, i); + } + } + }, + + eachAttribute: function(fn){ + var i, attrs = this.element.attributes || [], size = attrs.length, chld, attr; + for (i = 0; i < size; i++) { + var attr = attrs[i]; + fn(attr.name, attr.value); + } + }, + + replaceWith: function(replaceNode) { + this.element.parentNode.replaceChild(nodeLite(replaceNode).element, this.element); + }, + + removeAttribute: function(name) { + this.element.removeAttribute(name); + }, + + after: function(element) { + this.element.parentNode.insertBefore(element, this.element.nextSibling); + }, + + attr: function(name, value){ + if (typeof value == 'undefined') { + return this.element.getAttribute(name); + } else { + this.element.setAttribute(name); + } + }, + + isText: function() { return this.element.nodeType == Node.TEXT_NODE; }, + text: function() { return this.element.nodeValue; }, + clone: function() { return nodeLite(this.element.cloneNode(true)); } +}; + +/////////////////////////////////// +//Compiler +////////////////////////////////// + +function Compiler(markup, directives, widgets){ + this.markup = markup; + this.directives = directives; + this.widgets = widgets; +} + +DIRECTIVE = /^ng-(.*)$/; + +Compiler.prototype = { + compile: function(element) { + var template = this.templetize(nodeLite(element)) || new Template(); + return function(element){ + var scope = new Scope(); + scope.element = element; + return { + scope: scope, + element:element, + init: bind(template, template.init, element, scope) + }; + }; + }, + + templetize: function(element){ + var self = this, + markup = self.markup, + markupSize = markup.length, + directives = self.directives, + widgets = self.widgets, + recurse = true, + exclusive = false, + template; + + // process markup for text nodes only + element.eachTextNode(function(textNode){ + for (var i = 0, text = textNode.text(); i < markupSize; i++) { + markup[i].call(self, text, textNode, element); + } + }); + + // Process attributes/directives + element.eachAttribute(function(name, value){ + var match = name.match(DIRECTIVE), + directive, init; + if (!exclusive && match) { + directive = directives[match[1]]; + if (directive) { + init = directive.call(self, value, element); + template = template || new Template(); + if (directive.exclusive) { + template.setExclusiveInit(init); + exclusive = true; + } else { + template.addInit(init); + } + recurse = recurse && init; + } else { + error("Directive '" + match[0] + "' is not recognized."); + } + } + }); + + // Process non text child nodes + if (recurse) { + element.eachNode(function(child, i){ + var childTemplate = self.templetize(child); + if(childTemplate) { + template = template || new Template(); + template.addChild(i, childTemplate); + } + }); + } + return template; + } +}; -- cgit v1.2.3