aboutsummaryrefslogtreecommitdiffstats
path: root/src/Compiler.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/Compiler.js')
-rw-r--r--src/Compiler.js208
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;
}
};