Got escaping working, as well as avoiding escaping with {{{
This commit is contained in:
+48
-2
@@ -9,6 +9,33 @@ Handlebars = {
|
|||||||
return toString.call(fn) === "[object Function]";
|
return toString.call(fn) === "[object Function]";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
escape: function(string) {
|
||||||
|
if (string === null) {
|
||||||
|
string = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.replace(/&(?!\w+;)|["\\<>]/g, function(str) {
|
||||||
|
switch(str) {
|
||||||
|
case "&":
|
||||||
|
return "&";
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
return "\"";
|
||||||
|
case "\\":
|
||||||
|
return "\\\\";
|
||||||
|
break;
|
||||||
|
case "<":
|
||||||
|
return "<";
|
||||||
|
break;
|
||||||
|
case ">":
|
||||||
|
return ">";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
buildContext: function(context, stack) {
|
buildContext: function(context, stack) {
|
||||||
var contextWrapper = function(stack) {
|
var contextWrapper = function(stack) {
|
||||||
this.__stack__ = stack;
|
this.__stack__ = stack;
|
||||||
@@ -78,6 +105,7 @@ Handlebars.Compiler = function(string) {
|
|||||||
this.fn = "var out = ''; var lookup; ";
|
this.fn = "var out = ''; var lookup; ";
|
||||||
this.newlines = "";
|
this.newlines = "";
|
||||||
this.comment = false;
|
this.comment = false;
|
||||||
|
this.escaped = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Handlebars.ParseError = function(message) {
|
Handlebars.ParseError = function(message) {
|
||||||
@@ -146,8 +174,13 @@ Handlebars.Compiler.prototype = {
|
|||||||
|
|
||||||
addExpression: function(mustache) {
|
addExpression: function(mustache) {
|
||||||
var expr = this.lookupFor(mustache);
|
var expr = this.lookupFor(mustache);
|
||||||
this.fn += "if (Handlebars.isFunction(" + expr + ")) out = out + " + expr + ".call(Handlebars.buildContext(context, stack)); ";
|
var escapeCall = "(";
|
||||||
this.fn += "else if(typeof " + expr + "!== 'undefined') out = out + " + expr + "; ";
|
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) {
|
lookupFor: function(param) {
|
||||||
@@ -207,6 +240,9 @@ Handlebars.Compiler.prototype = {
|
|||||||
} else if(next === "#") {
|
} else if(next === "#") {
|
||||||
this.openBlock = true;
|
this.openBlock = true;
|
||||||
this.getChar();
|
this.getChar();
|
||||||
|
} else if(next === "{") {
|
||||||
|
this.escaped = false;
|
||||||
|
this.getChar();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addText();
|
this.addText();
|
||||||
@@ -219,7 +255,15 @@ Handlebars.Compiler.prototype = {
|
|||||||
param = this.lookupFor(parts[1]);
|
param = this.lookupFor(parts[1]);
|
||||||
|
|
||||||
this.mustache = false;
|
this.mustache = false;
|
||||||
|
|
||||||
|
// finish reading off the close of the handlebars
|
||||||
this.getChar();
|
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) {
|
if(this.comment) {
|
||||||
this.comment = false;
|
this.comment = false;
|
||||||
return;
|
return;
|
||||||
@@ -229,6 +273,8 @@ Handlebars.Compiler.prototype = {
|
|||||||
} else {
|
} else {
|
||||||
return this.addExpression(mustache);
|
return this.addExpression(mustache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.escaped = false;
|
||||||
} else if(this.comment) {
|
} else if(this.comment) {
|
||||||
;
|
;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+9
-1
@@ -26,6 +26,14 @@ test("boolean", function() {
|
|||||||
"booleans do not show the contents when false");
|
"booleans do not show the contents when false");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("escaping", function() {
|
||||||
|
shouldCompileTo("{{awesome}}", {awesome: "&\"\\<>"}, '&\"\\\\<>',
|
||||||
|
"by default expressions should be escaped");
|
||||||
|
|
||||||
|
shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
|
||||||
|
"expressions with 3 handlebars aren't escaped");
|
||||||
|
});
|
||||||
|
|
||||||
test("functions", function() {
|
test("functions", function() {
|
||||||
shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
|
shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome",
|
||||||
"functions are called and render their output");
|
"functions are called and render their output");
|
||||||
@@ -89,7 +97,7 @@ test("block with complex lookup", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("helper 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 hash = {prefix: "/root", goodbyes: [{text: "Goodbye", url: "goodbye"}]};
|
||||||
var fallback = {link: function() {
|
var fallback = {link: function() {
|
||||||
return "<a href='" + this.__get__("../prefix") + "/" + this.url + "'>" + this.text + "</a>"
|
return "<a href='" + this.__get__("../prefix") + "/" + this.url + "'>" + this.text + "</a>"
|
||||||
|
|||||||
Reference in New Issue
Block a user