Add support for multiple params and String literals

This commit is contained in:
wycats
2010-11-17 16:12:24 -08:00
parent 75f2c8e3ce
commit 766497bb55
2 changed files with 105 additions and 21 deletions
+57 -21
View File
@@ -184,31 +184,37 @@ var Handlebars = {
},
handleBlock: function(lookup, context, arg, fn, notFn) {
var out = "";
var out = "", args;
originalArgs = arg.length ? arg : [null]
if (Handlebars.isFunction(lookup)) {
out = out + lookup.call(context, arg, fn);
args = originalArgs.concat(fn);
out = out + lookup.apply(context, args);
if (notFn != null && Handlebars.isFunction(lookup.not)) {
out = out + lookup.not.call(context, arg, notFn);
args = originalArgs.concat(notFn);
out = out + lookup.not.apply(context, args);
}
}
else {
if (!Handlebars.isEmpty(lookup)) {
out = out + Handlebars.helperMissing.call(arg, lookup, fn);
// TODO: which case is this, and what does it mean for multiple args
out = out + Handlebars.helperMissing.call(arg[0], lookup, fn);
}
if (notFn != null) {
out = out + Handlebars.helperMissing.not.call(arg, lookup, notFn);
out = out + Handlebars.helperMissing.not.call(arg[0], lookup, notFn);
}
}
return out;
},
handleExpression: function(lookup, context, arg, isEscaped) {
handleExpression: function(lookup, context, args, isEscaped) {
var out = "";
if (Handlebars.isFunction(lookup)) {
out = out + Handlebars.filterOutput(lookup.call(context, arg), isEscaped);
out = out + Handlebars.filterOutput(lookup.apply(context, args), isEscaped);
} else if(!Handlebars.isEmpty(lookup)) {
out = out + Handlebars.filterOutput(lookup, isEscaped);
}
@@ -333,11 +339,13 @@ Handlebars.Compiler.prototype = {
}
},
addExpression: function(mustache, param) {
param = param || null;
addExpression: function(mustache, params) {
if(!params[0]) params = ["null"]
params = params.join(", ")
var expr = this.lookupFor(mustache);
this.fn += "var proxy = Handlebars.buildContext(context, stack);"
this.fn += "out = out + Handlebars.handleExpression(" + expr + ", proxy, " + param + ", " + this.escaped + ");";
this.fn += "out = out + Handlebars.handleExpression(" + expr + ", proxy, [" + params + "], " + this.escaped + ");";
},
addInvertedSection: function(mustache) {
@@ -385,7 +393,7 @@ Handlebars.Compiler.prototype = {
return compiler;
},
addBlock: function(mustache, param, parts) {
addBlock: function(mustache, params) {
var compiler = this.compileToEndOfBlock(mustache);
var result = compiler.fn;
@@ -395,7 +403,7 @@ Handlebars.Compiler.prototype = {
this.fn += "var wrappedContext = Handlebars.buildContext(context, stack);";
this.fn += "var " + fnId + " = function(context) {" + result + "}; ";
this.fn += "lookup = " + this.lookupFor(mustache) + "; ";
this.fn += "arg = " + param + ";";
this.fn += "arg = [" + params.join(", ") + "] ;";
this.fn += "stack.push(context);";
if (compiler.continueInverted) {
@@ -441,13 +449,41 @@ Handlebars.Compiler.prototype = {
}
this.addText();
this.mustache = " ";
var params = [""], currentParam = 0, literals = [];
while(chr = this.getChar()) {
if(this.mustache && chr === "}" && this.peek() === "}") {
var parts = Handlebars.trim(this.mustache).split(/\s+/);
mustache = parts[0];
param = this.lookupFor(parts[1]);
if(this.stringLiteral) {
params[currentParam] += chr;
if(chr === "\\" && this.peek() === '"') {
params[currentParam] += '"';
this.getChar();
} else if(chr === '"') {
params[++currentParam] = ""
this.stringLiteral = false;
}
} else if(chr === '"') {
if(params[currentParam] !== "") {
throw new Handlebars.Exception("You are already in the middle of" +
"the " + params[currentParam] + " param. " +
"You cannot start a String param")
}
this.stringLiteral = true;
params[currentParam] = chr;
literals[currentParam] = true;
} else if(chr === " ") {
if(params[currentParam] !== "") params[++currentParam] = ""
} else if(chr === "}" && this.peek() === "}") {
mustache = params[0];
arguments = [];
if(!params[1]) params[1] = undefined;
for(var i=1,l=params.length; i<l; i++) {
var argument = params[i];
arguments.push( literals[i] ? argument : this.lookupFor(argument) );
}
this.mustache = false;
@@ -463,7 +499,7 @@ Handlebars.Compiler.prototype = {
this.comment = false;
return;
} else if (this.partial) {
this.addPartial(mustache, param)
this.addPartial(mustache, arguments[0])
this.partial = false;
return;
} else if (this.inverted) {
@@ -471,17 +507,17 @@ Handlebars.Compiler.prototype = {
this.inverted = false;
return;
} else if(this.openBlock) {
this.addBlock(mustache, param, parts)
this.addBlock(mustache, arguments)
return;
} else {
return this.addExpression(mustache, param);
return this.addExpression(mustache, arguments);
}
this.escaped = true;
} else if(this.comment) {
;
} else {
this.mustache = this.mustache + chr;
params[currentParam] += chr;
}
}
}
+48
View File
@@ -386,6 +386,54 @@ test("Partial containing complex expression", function() {
shouldCompileTo(template, [hash, {partials: {dude: dude}}], "Dudes: Mr. Yehuda Mr. Alan ");
});
module("String literal parameters");
test("simple literals work", function() {
var string = 'Message: {{hello "world"}}';
var hash = {}
var fallback = {hello: function(param) { return "Hello " + param; }}
shouldCompileTo(string, [hash, fallback], "Message: Hello world", "template with a simple String literal");
});
test("using a quote in the middle of a parameter raises an error", function() {
shouldThrow(function() {
var string = 'Message: {{hello wo"rld"}}';
Handlebars.compile(string);
}, Handlebars.Exception, "should throw exception");
});
test("escaping a String is possible", function(){
var string = 'Message: {{hello "\\"world\\""}}';
var hash = {}
var fallback = {hello: function(param) { return "Hello " + param; }}
shouldCompileTo(string, [hash, fallback], "Message: Hello \"world\"", "template with an escaped String literal");
});
test("it works with ' marks", function() {
var string = 'Message: {{hello "Alan\'s world"}}';
var hash = {}
var fallback = {hello: function(param) { return "Hello " + param; }}
shouldCompileTo(string, [hash, fallback], "Message: Hello Alan's world", "template with a ' mark");
});
module("multiple parameters");
test("simple multi-params work", function() {
var string = 'Message: {{goodbye cruel world}}';
var hash = {cruel: "cruel", world: "world"}
var fallback = {goodbye: function(cruel, world) { return "Goodbye " + cruel + " " + world; }}
shouldCompileTo(string, [hash, fallback], "Message: Goodbye cruel world", "regular helpers with multiple params");
});
test("block multi-params work", function() {
var string = 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}';
var hash = {cruel: "cruel", world: "world"}
var fallback = {goodbye: function(cruel, world, fn) {
return fn({greeting: "Goodbye", adj: "cruel", noun: "world"});
}}
shouldCompileTo(string, [hash, fallback], "Message: Goodbye cruel world", "block helpers with multiple params");
})
module("safestring");
test("constructing a safestring from a string and checking its type", function() {