Got escaping working, as well as avoiding escaping with {{{

This commit is contained in:
Alan Johnson
2010-08-08 00:14:03 -04:00
parent 5459b0ee3a
commit a74794ba8d
2 changed files with 57 additions and 3 deletions
+48 -2
View File
@@ -9,6 +9,33 @@ Handlebars = {
return toString.call(fn) === "[object Function]";
},
escape: function(string) {
if (string === null) {
string = "";
}
return string.replace(/&(?!\w+;)|["\\<>]/g, function(str) {
switch(str) {
case "&":
return "&amp;";
break;
case '"':
return "\"";
case "\\":
return "\\\\";
break;
case "<":
return "&lt;";
break;
case ">":
return "&gt;";
break;
default:
return str;
}
});
},
buildContext: function(context, stack) {
var contextWrapper = function(stack) {
this.__stack__ = stack;
@@ -78,6 +105,7 @@ Handlebars.Compiler = function(string) {
this.fn = "var out = ''; var lookup; ";
this.newlines = "";
this.comment = false;
this.escaped = true;
};
Handlebars.ParseError = function(message) {
@@ -146,8 +174,13 @@ Handlebars.Compiler.prototype = {
addExpression: function(mustache) {
var expr = this.lookupFor(mustache);
this.fn += "if (Handlebars.isFunction(" + expr + ")) out = out + " + expr + ".call(Handlebars.buildContext(context, stack)); ";
this.fn += "else if(typeof " + expr + "!== 'undefined') out = out + " + expr + "; ";
var escapeCall = "(";
if (this.escaped) {
escapeCall = "Handlebars.escape(";
}
this.fn += "if (Handlebars.isFunction(" + expr + ")) out = out + " + escapeCall + expr + ".call(Handlebars.buildContext(context, stack))); ";
this.fn += "else if(typeof " + expr + "!== 'undefined') out = out + " + escapeCall + expr + ");";
},
lookupFor: function(param) {
@@ -207,6 +240,9 @@ Handlebars.Compiler.prototype = {
} else if(next === "#") {
this.openBlock = true;
this.getChar();
} else if(next === "{") {
this.escaped = false;
this.getChar();
}
this.addText();
@@ -219,7 +255,15 @@ Handlebars.Compiler.prototype = {
param = this.lookupFor(parts[1]);
this.mustache = false;
// finish reading off the close of the handlebars
this.getChar();
// {{{expression}} is techically valid, but if we started with {{{ we'll try to read
// }}} off of the close of the handlebars
if (!this.escaped && this.peek() === "}") {
this.getChar();
}
if(this.comment) {
this.comment = false;
return;
@@ -229,6 +273,8 @@ Handlebars.Compiler.prototype = {
} else {
return this.addExpression(mustache);
}
this.escaped = false;
} else if(this.comment) {
;
} else {
+9 -1
View File
@@ -26,6 +26,14 @@ test("boolean", function() {
"booleans do not show the contents when false");
});
test("escaping", function() {
shouldCompileTo("{{awesome}}", {awesome: "&\"\\<>"}, '&amp;\"\\\\&lt;&gt;',
"by default expressions should be escaped");
shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
"expressions with 3 handlebars aren't escaped");
});
test("functions", function() {
shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
"functions are called and render their output");
@@ -89,7 +97,7 @@ test("block with complex lookup", function() {
});
test("helper with complex lookup", function() {
var string = "{{#goodbyes}}{{link}}{{/goodbyes}}"
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>"