Add fallback hash (useful for a helper Hash).
* available globally per top-level function regardless of iteration
This commit is contained in:
+20
-11
@@ -2,7 +2,7 @@ Handlebars = {
|
||||
compile: function(string) {
|
||||
var compiler = new Handlebars.Compiler(string);
|
||||
var result = compiler.compile();
|
||||
return new Function("context", result);
|
||||
return new Function("context", "fallback", "fallback = fallback || {}; " + result);
|
||||
},
|
||||
|
||||
isFunction: function(fn) {
|
||||
@@ -20,7 +20,7 @@ Handlebars.Compiler = function(string) {
|
||||
this.comment = false;
|
||||
}
|
||||
|
||||
Handlebars.catchAll = function(object, fn) {
|
||||
Handlebars.helperMissing = function(object, fn) {
|
||||
var ret = "";
|
||||
|
||||
if(object === true) {
|
||||
@@ -74,17 +74,21 @@ Handlebars.Compiler.prototype = {
|
||||
if(this.text) {
|
||||
this.fn = this.fn + "out = out + '" + this.text + "'; ";
|
||||
this.fn = this.fn + this.newlines;
|
||||
this.newlines = ""
|
||||
this.text = ""
|
||||
this.newlines = "";
|
||||
this.text = "";
|
||||
}
|
||||
},
|
||||
|
||||
addExpression: function(mustache) {
|
||||
this.fn = this.fn + "out = out + context['" + mustache + "']; ";
|
||||
this.fn += "out = out + " + this.lookupFor(mustache) + "; ";
|
||||
},
|
||||
|
||||
lookupFor: function(param) {
|
||||
return param ? "( context['" + param + "'] || fallback['" + param + "'] )" : "context";
|
||||
},
|
||||
|
||||
parseMustache: function() {
|
||||
var chr, mustache;
|
||||
var chr, part, mustache, param;
|
||||
|
||||
var next = this.peek();
|
||||
|
||||
@@ -101,7 +105,10 @@ Handlebars.Compiler.prototype = {
|
||||
|
||||
while(chr = this.getChar()) {
|
||||
if(this.mustache && chr === "}" && this.peek() === "}") {
|
||||
mustache = this.mustache.trim();
|
||||
var parts = this.mustache.trim().split(/\s+/);
|
||||
mustache = parts[0];
|
||||
param = this.lookupFor(parts[1]);
|
||||
|
||||
this.mustache = false;
|
||||
this.getChar();
|
||||
if(this.comment) {
|
||||
@@ -110,13 +117,15 @@ Handlebars.Compiler.prototype = {
|
||||
} else if(this.openBlock) {
|
||||
var compiler = new Handlebars.Compiler(this.string.slice(this.pointer + 1, -1));
|
||||
|
||||
// compile with a custom EOF instruction
|
||||
// sub-compile with a custom EOF instruction
|
||||
var result = compiler.compile(function(compiler) {
|
||||
if(compiler.peek(mustache.length + 5) === "{{/" + mustache + "}}") {
|
||||
compiler.getChar(mustache.length + 5);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// move the pointer forward the amount of characters handled by the sub-compiler
|
||||
this.pointer += compiler.pointer + 1;
|
||||
|
||||
// each function made internally needs a unique IDs. These are locals, so they
|
||||
@@ -124,9 +133,9 @@ Handlebars.Compiler.prototype = {
|
||||
var fnId = "fn" + this.pointer.toString();
|
||||
|
||||
this.fn += "var " + fnId + " = function(context) {" + result + "}; ";
|
||||
this.fn += "lookup = context['" + mustache + "']; ";
|
||||
this.fn += "if(Handlebars.isFunction(lookup)) out = out + " + fnId + "(lookup); "
|
||||
this.fn += "else if(typeof lookup !== 'undefined') out = out + Handlebars.catchAll(lookup, " + fnId + "); "
|
||||
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.openBlock = false;
|
||||
return;
|
||||
|
||||
+84
-15
@@ -1,28 +1,97 @@
|
||||
module("basic context");
|
||||
|
||||
test("compiling with a basic context", function() {
|
||||
var string = "Goodbye\n{{cruel}}\n{{world}}!";
|
||||
var shouldCompileTo = function(string, hash, result, message) {
|
||||
var template = Handlebars.compile(string);
|
||||
var params = toString.call(hash) === "[object Array]" ? hash : [hash, undefined];
|
||||
equal(template.apply(this, params), result, message);
|
||||
}
|
||||
|
||||
result = template({cruel: "cruel", world: "world"});
|
||||
equal(result, "Goodbye\ncruel\nworld!", "it works if all the required keys are provided");
|
||||
test("compiling with a basic context", function() {
|
||||
shouldCompileTo("Goodbye\n{{cruel}}\n{{world}}!", {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
|
||||
"It works if all the required keys are provided");
|
||||
});
|
||||
|
||||
test("comments", function() {
|
||||
var string = "{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!";
|
||||
var template = Handlebars.compile(string);
|
||||
|
||||
result = template({cruel: "cruel", world: "world"});
|
||||
equal("Goodbye\ncruel\nworld!", result, "it works if all the required keys are provided");
|
||||
shouldCompileTo("{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!",
|
||||
{cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!",
|
||||
"comments are ignored");
|
||||
});
|
||||
|
||||
test("boolean", function() {
|
||||
var string = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!"
|
||||
var string = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!";
|
||||
shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!",
|
||||
"booleans show the contents when true");
|
||||
|
||||
shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!",
|
||||
"booleans do not show the contents when false");
|
||||
});
|
||||
|
||||
module("blocks");
|
||||
|
||||
test("array", function() {
|
||||
var string = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!"
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!",
|
||||
"Arrays iterate over the contents when not empty");
|
||||
|
||||
shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!",
|
||||
"Arrays ignore the contents when empty");
|
||||
});
|
||||
|
||||
test("nested iteration", function() {
|
||||
|
||||
});
|
||||
|
||||
test("block helper", function() {
|
||||
var string = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!";
|
||||
var template = Handlebars.compile(string);
|
||||
|
||||
result = template({goodbye: true, world: "world"});
|
||||
equal("GOODBYE cruel world!", result, "booleans work when true");
|
||||
|
||||
result = template({goodbye: false, world: "world"});
|
||||
equal("cruel world!", result, "booleans work when true");
|
||||
result = template({goodbyes: function(fn) { return fn({text: "GOODBYE"}); }, world: "world"});
|
||||
equal(result, "GOODBYE! cruel world!");
|
||||
});
|
||||
|
||||
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"});
|
||||
equal(result, "<form><p>Yehuda</p></form>");
|
||||
});
|
||||
|
||||
test("block helper passing a new context", function() {
|
||||
var string = "{{#form yehuda}}<p>{{name}}</p>{{/form}}"
|
||||
var template = Handlebars.compile(string);
|
||||
|
||||
result = template({form: function(fn) { return "<form>" + fn(this) + "</form>" }, yehuda: {name: "Yehuda"}});
|
||||
equal(result, "<form><p>Yehuda</p></form>");
|
||||
});
|
||||
|
||||
test("nested block helpers", function() {
|
||||
var string = "{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}"
|
||||
var template = Handlebars.compile(string);
|
||||
|
||||
result = template({form: function(fn) { return "<form>" + fn(this) + "</form>" }, yehuda: {name: "Yehuda", link: function(fn) { return "<a href='" + this.name + "'>" + fn(this) + "</a>"; }}});
|
||||
equal(result, "<form><p>Yehuda</p><a href='Yehuda'>Hello</a></form>");
|
||||
});
|
||||
|
||||
module("fallback hash");
|
||||
|
||||
test("providing a fallback hash", function() {
|
||||
shouldCompileTo("Goodbye {{cruel}} {{world}}!", [{cruel: "cruel"}, {world: "world"}], "Goodbye cruel world!",
|
||||
"Fallback hash is available");
|
||||
|
||||
shouldCompileTo("Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!", [{iter: [{cruel: "cruel"}]}, {world: "world"}],
|
||||
"Goodbye cruel world!", "Fallback hash is available inside other blocks");
|
||||
});
|
||||
|
||||
test("in cases of conflict, the explicit hash wins", function() {
|
||||
|
||||
});
|
||||
|
||||
test("the fallback hash is available is nested contexts", function() {
|
||||
|
||||
});
|
||||
|
||||
module("partials");
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user