diff options
Diffstat (limited to 'src/Compiler.js')
| -rw-r--r-- | src/Compiler.js | 208 |
1 files changed, 93 insertions, 115 deletions
diff --git a/src/Compiler.js b/src/Compiler.js index f4d901fb..ba598a43 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -12,12 +12,13 @@ function Template() { Template.prototype = { init: function(element, scope) { + element = jqLite(element); foreach(this.inits, function(fn) { - scope.apply(fn, nodeLite(element)); + scope.apply(fn, element); }); var i, - childNodes = element.childNodes, + childNodes = element[0].childNodes, children = this.children, paths = this.paths, length = paths.length; @@ -26,106 +27,74 @@ Template.prototype = { } }, + 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); + if (template) { + this.paths.push(index); + this.children.push(template); + } + }, + + empty: function() { + return this.inits.length == 0 && this.paths.length == 0; } }; /////////////////////////////////// -//NodeLite +//Compiler ////////////////////////////////// - -function NodeLite(element) { - this.element = element; -} - -function nodeLite(element) { - return element instanceof NodeLite ? element : new NodeLite(element); +function isTextNode(node) { + return node.nodeType == Node.TEXT_NODE; } -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); - } +function eachTextNode(element, fn){ + var i, chldNodes = element[0].childNodes || [], size = chldNodes.length, chld; + for (i = 0; i < size; i++) { + if(isTextNode(chld = chldNodes[i])) { + fn(jqLite(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); +function eachNode(element, fn){ + var i, chldNodes = element[0].childNodes || [], size = chldNodes.length, chld; + for (i = 0; i < size; i++) { + if(!isTextNode(chld = chldNodes[i])) { + fn(jqLite(chld), i); } - }, - - 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 eachAttribute(element, fn){ + var i, attrs = element[0].attributes || [], size = attrs.length, chld, attr; + for (i = 0; i < size; i++) { + var attr = attrs[i]; + fn(attr.name, attr.value); + } +} -function Compiler(markup, directives, widgets){ - this.markup = markup; +function Compiler(textMarkup, attrMarkup, directives, widgets){ + this.textMarkup = textMarkup; + this.attrMarkup = attrMarkup; 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(); + compile: function(rawElement) { + rawElement = jqLite(rawElement); + var template = this.templatize(rawElement) || new Template(); + return function(element, parentScope){ + var scope = new Scope(parentScope); scope.element = element; + // todo return should be a scope with everything already set on it as element return { scope: scope, element:element, @@ -134,55 +103,64 @@ Compiler.prototype = { }; }, - templetize: function(element){ + templatize: function(element){ var self = this, - markup = self.markup, - markupSize = markup.length, - directives = self.directives, + elementName = element[0].nodeName, widgets = self.widgets, - recurse = true, + widget = widgets[elementName], + directives = self.directives, + descend = 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); - } - }); + directiveQueue = [], + template = new Template(), + selfApi = { + compile: bind(self, self.compile), + comment:function(text) {return jqLite(document.createComment(text));}, + element:function(type) {return jqLite(document.createElement(type));}, + text:function(text) {return jqLite(document.createTextNode(text));}, + descend: function(value){ if(isDefined(value)) descend = value; return descend;} + }; + + if (widget) { + template.addInit(widget.call(selfApi, element)); + } else { + // process markup for text nodes only + eachTextNode(element, function(textNode){ + var text = textNode.text(); + foreach(self.textMarkup, function(markup){ + markup.call(selfApi, 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(); + // Process attributes/directives + eachAttribute(element, function(name, value){ + foreach(self.attrMarkup, function(markup){ + markup.call(selfApi, value, name, element); + }); + }); + eachAttribute(element, function(name, value){ + var directive = directives[name]; + if (!exclusive && directive) { if (directive.exclusive) { - template.setExclusiveInit(init); exclusive = true; - } else { - template.addInit(init); + directiveQueue = []; } - recurse = recurse && init; - } else { - error("Directive '" + match[0] + "' is not recognized."); + directiveQueue.push(bindTry(selfApi, directive, value, element, errorHandlerFor(element))); } - } - }); + }); - // 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); - } + // Execute directives + foreach(directiveQueue, function(directive){ + template.addInit(directive()); }); + + // Process non text child nodes + if (descend) { + eachNode(element, function(child, i){ + template.addChild(i, self.templatize(child)); + }); + } } - return template; + return template.empty() ? null : template; } }; |
