Using this.__get__ inside of functions called as expressions now works.

This commit is contained in:
Alan Johnson
2010-08-06 00:34:03 -04:00
parent 28d699233a
commit 13ceb010ba
2 changed files with 49 additions and 10 deletions
+31 -9
View File
@@ -2,7 +2,6 @@ Handlebars = {
compile: function(string) {
var compiler = new Handlebars.Compiler(string);
var result = compiler.compile();
console.log(result);
return new Function("context", "fallback", "fallback = fallback || {}; var stack = [];" + result);
},
@@ -19,11 +18,34 @@ Handlebars.Compiler = function(string) {
this.fn = "var out = ''; var lookup; ";
this.newlines = "";
this.comment = false;
}
};
Handlebars.ParseError = function(message) {
this.message = message;
}
};
Handlebars.Context = function(stack) {
this.__stack__ = stack;
this.__get__ = function(path) {
var context = this;
var parsedPath = Handlebars.parsePath(path);
var depth = parsedPath[0];
var parts = parsedPath[1];
if (depth > 0) {
context = this.__stack__[stack.length - depth];
}
for (var i = 0; i < parts.length; i++) {
context = context[parts[i]];
}
return context;
};
};
Handlebars.buildContext = function(context, stack) {
Handlebars.Context.prototype = context;
return new Handlebars.Context(stack);
};
// Returns a two element array containing the numbers of contexts to back up the stack and
// the properties to dig into on the current context
@@ -57,7 +79,7 @@ Handlebars.parsePath = function(path) {
}
return [depth, dig];
}
};
Handlebars.helperMissing = function(object, fn) {
var ret = "";
@@ -120,7 +142,8 @@ Handlebars.Compiler.prototype = {
addExpression: function(mustache) {
var expr = this.lookupFor(mustache);
this.fn += "out = out + (Handlebars.isFunction(" + expr + ") ? " + expr + "() : " + expr + "); ";
this.fn += "if (Handlebars.isFunction(" + expr + ")) out = out + " + expr + ".call(Handlebars.buildContext(context, stack)); ";
this.fn += "else if(typeof " + expr + "!== 'undefined') out = out + " + expr + "; ";
},
lookupFor: function(param) {
@@ -186,11 +209,11 @@ Handlebars.Compiler.prototype = {
// each function made internally needs a unique IDs. These are locals, so they
// don't need to be globally unique, just per compiler
var fnId = "fn" + this.pointer.toString();
this.fn += "var proxy = Handlebars.buildContext(" + param + ", stack);";
this.fn += "var " + fnId + " = function(context) {" + result + "}; ";
this.fn += "lookup = " + this.lookupFor(mustache) + "; ";
this.fn += "if(Handlebars.isFunction(lookup)) out = out + lookup.call(" + param + ", " + fnId + "); ";
this.fn += "else if(typeof lookup !== 'undefined') out = out + Handlebars.helperMissing.call(" + param + ", lookup, " + fnId + "); ";
this.fn += "if(Handlebars.isFunction(lookup)) out = out + lookup.call(proxy, " + fnId + "); ";
this.fn += "else if(typeof lookup !== 'undefined') out = out + Handlebars.helperMissing.call(proxy, lookup, " + fnId + "); ";
this.fn += "stack.pop();";
this.openBlock = false;
@@ -207,4 +230,3 @@ Handlebars.Compiler.prototype = {
}
}
}
+18 -1
View File
@@ -88,6 +88,15 @@ test("block with complex lookup", function() {
"Templates can access variables in contexts up the stack with relative path syntax");
});
test("helper with complex lookup", function() {
var string = "{{#goodbyes}}{{link}}{{/goodbyes}}"
var hash = {prefix: "/root", goodbyes: [{text: "Goodbye", url: "goodbye"}]};
var fallback = {link: function() {
return "<a href='" + this.__get__("../prefix") + "/" + this.url + "'>" + this.text + "</a>"
}};
shouldCompileTo(string, [hash, fallback], "<a href='/root/goodbye'>Goodbye</a>")
});
test("block with deep nested complex lookup", function() {
var string = "{{#outer}}Goodbye {{#inner}}cruel {{../../omg}}{{/inner}}{{/outer}}";
var hash = {omg: "OMG!", outer: [{ inner: [{ text: "goodbye" }] }] };
@@ -107,7 +116,7 @@ test("block helper staying in the same context", function() {
var string = "{{#form}}<p>{{name}}</p>{{/form}}"
var template = Handlebars.compile(string);
result = template({form: function(fn) { return "<form>" + fn(this) + "</form>" }, name: "Yehuda"});
result = template({form: function(fn) { console.log(fn); return "<form>" + fn(this) + "</form>" }, name: "Yehuda"});
equal(result, "<form><p>Yehuda</p></form>");
});
@@ -119,6 +128,14 @@ test("block helper passing a new context", function() {
equal(result, "<form><p>Yehuda</p></form>");
});
test("block helper passing a complex path context", function() {
var string = "{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}"
var template = Handlebars.compile(string);
result = template({form: function(fn) { return "<form>" + fn(this) + "</form>" }, yehuda: {name: "Yehuda", cat: {name: "Harold"}}});
equal(result, "<form><p>Harold</p></form>");
});
test("nested block helpers", function() {
var string = "{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}"
var template = Handlebars.compile(string);