summaryrefslogtreecommitdiff
authorJosh Kropf <josh@slashdev.ca>2010-06-06 22:36:10 (GMT)
committer Josh Kropf <josh@slashdev.ca>2010-06-06 22:36:10 (GMT)
commit8ac0b2c778d836f4d9ae1a065a665bcac961921a (patch) (side-by-side diff)
tree39c0890e9101252f001ebbc3f44ed185d54e8abb
parent6c3bfbf5dc6b1fe4b9e31b427d0917af696feebd (diff)
downloadjqtemplate-master.zip
jqtemplate-master.tar.gz
jqtemplate-master.tar.bz2
Fixed flaw in template compiling logic causing...HEADmaster
repeated evaluation of the last element in a loop when several elements in the template contained the same relative dom path.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--build.properties2
-rw-r--r--dist/jquery.jqtemplate-0.3.min.js1
-rw-r--r--dist/jquery.jqtemplate-0.4.min.js1
-rw-r--r--src/jquery.jqtemplate.js101
4 files changed, 48 insertions, 57 deletions
diff --git a/build.properties b/build.properties
index 5971fc4..1646df2 100644
--- a/build.properties
+++ b/build.properties
@@ -1 +1 @@
-version=0.3
+version=0.4
diff --git a/dist/jquery.jqtemplate-0.3.min.js b/dist/jquery.jqtemplate-0.3.min.js
deleted file mode 100644
index 02fd861..0000000
--- a/dist/jquery.jqtemplate-0.3.min.js
+++ b/dev/null
@@ -1 +0,0 @@
-(function(d){d.fn.jqtemplate=function(g,f){var i=d.extend({},d.fn.jqtemplate.defaults,f),h=this.selector+"/";if(this.data("compiled")!=true){c(this,this.selector);this.data("compiled",true)}if(i.inplace){return this.each(function(j,k){b(g,k,h+k.get(0).nodeName)})}else{var e=typeof(i.root)=="string"?d(i.root):i.root;return this.each(function(j,k){var l=d(k).clone();e.append(l);b(g,l,h+k.nodeName)})}};d.fn.jqtemplate.defaults={inplace:false,root:"body"};var a={};function c(g,k){k=k+"/"+g.get(0).nodeName;var j=["jqloop","jqbind","jqattr","jqtext"];for(var e in j){if(g.attr(j[e])){var h=new Function(["$this"],"return "+g.attr(j[e]));a[k+"/"+j[e]]=h}}g.children().each(function(f,l){c(d(l),k)})}function b(l,g,q){if(g.attr("jqloop")){var k=a[q+"/jqloop"](l),j=g,o=g;g.removeAttr("jqloop");for(var h in k.array){l[k.object]=k.array[h];var e=d(j.clone());o.after(e);o=e;b(l,e,q)}j.remove();return}if(g.attr("jqbind")){var f=d.makeArray(a[q+"/jqbind"](l));for(var h in f){g.bind(f[h].event,f[h],function(i){var r=i.data;r.fn.apply(this,d.makeArray(r.args))})}}if(g.attr("jqattr")){var n=a[q+"/jqattr"](l);for(var m in n){g.attr(m,n[m])}}if(g.attr("jqtext")){var p=a[q+"/jqtext"](l);g.text(p)}g.children().each(function(r,s){b(l,d(s),q+"/"+s.nodeName)})}})(jQuery); \ No newline at end of file
diff --git a/dist/jquery.jqtemplate-0.4.min.js b/dist/jquery.jqtemplate-0.4.min.js
new file mode 100644
index 0000000..2ceccc1
--- a/dev/null
+++ b/dist/jquery.jqtemplate-0.4.min.js
@@ -0,0 +1 @@
+(function(c){c.fn.jqtemplate=function(f,e){var h=c.extend({},c.fn.jqtemplate.defaults,e),g=this.selector+"/";if(this.data("compiled")!=true){b(this);this.data("compiled",true)}if(h.inplace){return this.each(function(j,k){a(f,c(k),c(k))})}else{var d=typeof(h.root)=="string"?c(h.root):h.root;return this.each(function(j,k){var l=c(k).clone();d.append(l);a(f,l,c(k))})}};c.fn.jqtemplate.defaults={inplace:false,root:"body"};function b(f){var g=["jqloop","jqbind","jqattr","jqtext"];for(var e in g){var d=g[e];if(f.attr(d)){f.data(d,new Function(["$this"],"return "+f.attr(d)))}}f.children().each(function(h,j){b(c(j))})}function a(m,f,e){if(f.attr("jqloop")){var k=e.data("jqloop")(m),h=f,l=f;f.removeAttr("jqloop");for(var g in k.array){m[k.object]=k.array[g];var j=c(f.clone());l.after(j);l=j;a(m,j,e)}h.remove();return}if(f.attr("jqbind")){var d=e.data("jqbind")(m);for(var g in d){f.bind(d[g].event,d[g],function(i){var p=i.data;p.fn.apply(this,c.makeArray(p.args))})}}if(f.attr("jqattr")){var o=e.data("jqattr")(m);for(var n in o){f.attr(n,o[n])}}if(f.attr("jqtext")){f.text(e.data("jqtext")(m))}(function(p,i){if(p.length!=0){a(m,p,i);arguments.callee(p.next(),i.next())}})(f.children().first(),e.children().first())}})(jQuery); \ No newline at end of file
diff --git a/src/jquery.jqtemplate.js b/src/jquery.jqtemplate.js
index 320101c..ae846ba 100644
--- a/src/jquery.jqtemplate.js
+++ b/src/jquery.jqtemplate.js
@@ -1,7 +1,7 @@
/*
* jQtemplate jQuery plugin
*
- * Copyright (c) 2009 Josh Kropf
+ * Copyright (c) 2009-2010 Josh Kropf
*
* Licensed under the GPL license:
* http://www.gnu.org/licenses/gpl.html
@@ -61,100 +61,89 @@
$.fn.jqtemplate = function(model, options) {
var opts = $.extend({}, $.fn.jqtemplate.defaults, options),
templatePath = this.selector + "/";
-
+
if (this.data("compiled") != true) {
- compileTemplate(this, this.selector);
+ compileTemplate(this);
this.data("compiled", true);
}
-
+
if (opts.inplace) {
return this.each(function(i, node) {
- evalNode(model, node, templatePath + node.get(0).nodeName);
+ evalNode(model, $(node), $(node));
});
} else {
// when root option is a string use it as a selector, otherwise
// assume it is already a jquery object for the root node
var root = typeof(opts.root) == "string"? $(opts.root) : opts.root;
-
+
return this.each(function(i, node) {
var copy = $(node).clone();
root.append(copy);
- evalNode(model, copy, templatePath + node.nodeName);
+ evalNode(model, copy, $(node));
});
}
};
-
+
$.fn.jqtemplate.defaults = {
inplace: false,
root: "body"
};
-
- /**
- * Map of attribute functions. Keys of the map are path representations
- * of the template node that contains jqtemplate attributes. The value for
- * a given key is the compiled function.
- */
- var attrCallback = {};
-
+
/**
* Recursively create function objects for jqtemplate attributes.
* @param node current template node
- * @param path path representation of template node
*/
- function compileTemplate(node, path) {
- path = path + "/" + node.get(0).nodeName;
-
+ function compileTemplate(node) {
var names = ["jqloop", "jqbind", "jqattr", "jqtext"];
for (var i in names) {
- if (node.attr(names[i])) {
- var f = new Function(["$this"], "return " + node.attr(names[i]));
- attrCallback[path + "/" + names[i]] = f;
+ var attr = names[i];
+ if (node.attr(attr)) {
+ node.data(attr, new Function(["$this"], "return " + node.attr(attr)));
}
}
-
+
node.children().each(function(i, node) {
- compileTemplate($(node), path);
+ compileTemplate($(node));
});
}
-
+
/**
* Recursively evaluate nodes of the template and their children.
* @param $this object model/context of template evaluation
- * @param node current template node
- * @param path path representation of template node
+ * @param node current node to be manipulated in the dom
+ * @param templateNode current template node
*/
- function evalNode($this, node, path) {
+ function evalNode($this, node, templateNode) {
if (node.attr("jqloop")) {
- var op = attrCallback[path + "/jqloop"]($this),
- first = node,
- last = node;
-
+ var op = templateNode.data("jqloop")($this),
+ first = node, current = node;
+
// remove jqloop attribute to avoid infinate recursion
node.removeAttr("jqloop");
-
+
// iterate over objects in the loop array and create/add
// new nodes in the dom
for (var i in op.array) {
// place the current array element in the template context
$this[op.object] = op.array[i];
-
- // clone the first node (the template node) and
- // add it after the last node
- var copy = $(first.clone());
- last.after(copy);
- last = copy;
-
+
+ // clone the current node and add it after the current
+ var next = $(node.clone());
+ current.after(next);
+ current = next;
+
// evaluate the cloned node
- evalNode($this, copy, path);
+ evalNode($this, next, templateNode);
}
-
+
+ // first node is used as a place holder and is not evaluated
first.remove();
return;
}
-
+
if (node.attr("jqbind")) {
- var bindings = $.makeArray(attrCallback[path + "/jqbind"]($this));
-
+ var bindings = templateNode.data("jqbind")($this);
+
for (var i in bindings) {
node.bind(bindings[i].event, bindings[i], function(event) {
// apply will call the function with a given 'this' object
@@ -166,22 +155,24 @@
});
}
}
-
+
if (node.attr("jqattr")) {
- var attrs = attrCallback[path + "/jqattr"]($this);
+ var attrs = templateNode.data("jqattr")($this);
for (var key in attrs) {
node.attr(key, attrs[key]);
}
}
-
+
if (node.attr("jqtext")) {
- var text = attrCallback[path + "/jqtext"]($this);
- node.text(text);
+ node.text(templateNode.data("jqtext")($this));
}
-
- node.children().each(function(i, node) {
- evalNode($this, $(node), path + "/" + node.nodeName);
- });
+
+ (function(nodeChild, templateChild) {
+ if (nodeChild.length != 0) {
+ evalNode($this, nodeChild, templateChild);
+ arguments.callee(nodeChild.next(), templateChild.next());
+ }
+ })(node.children().first(), templateNode.children().first());
}
})(jQuery);