summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.markdown2
-rw-r--r--lib/handlebars/compiler.js2
-rw-r--r--lib/handlebars/utils.js9
-rw-r--r--spec/qunit_spec.js12
-rw-r--r--spec/tokenizer_spec.rb11
-rw-r--r--src/handlebars.l2
6 files changed, 25 insertions, 13 deletions
diff --git a/README.markdown b/README.markdown
index 35f8149..fa8c344 100644
--- a/README.markdown
+++ b/README.markdown
@@ -45,7 +45,7 @@ embedded in them, as well as the text for a link:
});
var context = { posts: [{url: "/hello-world", body: "Hello World!"}] };
- var source = "<ul>{{#posts}}<li>{{{link_to this}}}</li></ul>"
+ var source = "<ul>{{#posts}}<li>{{{link_to this}}}</li>{{/posts}}</ul>"
var template = Handlebars.compile(source);
template(context);
diff --git a/lib/handlebars/compiler.js b/lib/handlebars/compiler.js
index 4be85f4..f3ce602 100644
--- a/lib/handlebars/compiler.js
+++ b/lib/handlebars/compiler.js
@@ -288,7 +288,7 @@ Handlebars.JavaScriptCompiler = function() {};
// PUBLIC API: You can override these methods in a subclass to provide
// alternative compiled forms for name lookup and buffering semantics
nameLookup: function(parent, name, type) {
- if(JavaScriptCompiler.RESERVED_WORDS[name] || name.indexOf('-') !== -1) {
+ if(JavaScriptCompiler.RESERVED_WORDS[name] || name.indexOf('-') !== -1 || !isNaN(name)) {
return parent + "['" + name + "']";
} else if (/^[0-9]+$/.test(name)) {
return parent + "[" + name + "]";
diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js
index e7e5043..5fdfb0e 100644
--- a/lib/handlebars/utils.js
+++ b/lib/handlebars/utils.js
@@ -16,11 +16,14 @@ Handlebars.SafeString.prototype.toString = function() {
(function() {
var escape = {
"<": "&lt;",
- ">": "&gt;"
+ ">": "&gt;",
+ '"': "&quot;",
+ "'": "&#x27;",
+ "`": "&#x60;"
};
- var badChars = /&(?!\w+;)|[<>]/g;
- var possible = /[&<>]/;
+ var badChars = /&(?!\w+;)|[<>"'`]/g;
+ var possible = /[&<>"'`]/;
var escapeChar = function(chr) {
return escape[chr] || "&amp;"
diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js
index 9d8a573..c766b69 100644
--- a/spec/qunit_spec.js
+++ b/spec/qunit_spec.js
@@ -87,12 +87,12 @@ test("escaping expressions", function() {
shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>',
"expressions with 3 handlebars aren't escaped");
- shouldCompileTo("{{awesome}}", {awesome: "&\"\\<>"}, '&amp;\"\\&lt;&gt;',
- "by default expressions should be escaped");
-
shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>',
"expressions with {{& handlebars aren't escaped");
+ shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&amp;&quot;&#x27;&#x60;\\&lt;&gt;',
+ "by default expressions should be escaped");
+
});
test("functions returning safestrings shouldn't be escaped", function() {
@@ -370,7 +370,7 @@ test("block helper inverted sections", function() {
// so we should see the output of both
shouldCompileTo(string, hash, "<ul><li>Alan</li><li>Yehuda</li></ul>", "an inverse wrapper is passed in as a new context");
shouldCompileTo(string, empty, "<p><em>Nobody's here</em></p>", "an inverse wrapper can be optionally called");
- shouldCompileTo(messageString, rootMessage, "<p>Nobody's here</p>", "the context of an inverse is the parent of the block");
+ shouldCompileTo(messageString, rootMessage, "<p>Nobody&#x27;s here</p>", "the context of an inverse is the parent of the block");
});
module("fallback hash");
@@ -448,14 +448,14 @@ test("using a quote in the middle of a parameter raises an error", function() {
});
test("escaping a String is possible", function(){
- var string = 'Message: {{hello "\\"world\\""}}';
+ 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 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");
diff --git a/spec/tokenizer_spec.rb b/spec/tokenizer_spec.rb
index d12566d..286c244 100644
--- a/spec/tokenizer_spec.rb
+++ b/spec/tokenizer_spec.rb
@@ -77,12 +77,18 @@ describe "Tokenizer" do
result[3].should be_token("ID", "foo")
end
- it "tokenizes a simple mustahe with spaces as 'OPEN ID CLOSE'" do
+ it "tokenizes a simple mustache with spaces as 'OPEN ID CLOSE'" do
result = tokenize("{{ foo }}")
result.should match_tokens(%w(OPEN ID CLOSE))
result[1].should be_token("ID", "foo")
end
+ it "tokenizes a simple mustache with line breaks as 'OPEN ID ID CLOSE'" do
+ result = tokenize("{{ foo \n bar }}")
+ result.should match_tokens(%w(OPEN ID ID CLOSE))
+ result[1].should be_token("ID", "foo")
+ end
+
it "tokenizes raw content as 'CONTENT'" do
result = tokenize("foo {{ bar }} baz")
result.should match_tokens(%w(CONTENT OPEN ID CLOSE CONTENT))
@@ -172,6 +178,9 @@ describe "Tokenizer" do
result = tokenize("{{ foo bar baz=bat }}")
result.should match_tokens %w(OPEN ID ID ID EQUALS ID CLOSE)
+ result = tokenize("{{ foo bar\n baz=bat }}")
+ result.should match_tokens %w(OPEN ID ID ID EQUALS ID CLOSE)
+
result = tokenize("{{ foo bar baz=\"bat\" }}")
result.should match_tokens %w(OPEN ID ID ID EQUALS STRING CLOSE)
diff --git a/src/handlebars.l b/src/handlebars.l
index 62b8adf..83014c7 100644
--- a/src/handlebars.l
+++ b/src/handlebars.l
@@ -24,7 +24,7 @@
<mu>"}}}" { this.begin("INITIAL"); return 'CLOSE'; }
<mu>"}}" { this.begin("INITIAL"); return 'CLOSE'; }
<mu>'"'("\\"["]|[^"])*'"' { yytext = yytext.substr(1,yyleng-2).replace(/\\"/g,'"'); return 'STRING'; }
-<mu>[a-zA-Z0-9_-]+/[=} /.] { return 'ID'; }
+<mu>[a-zA-Z0-9_$-]+/[=}\s/.] { return 'ID'; }
<mu>. { return 'INVALID'; }
<INITIAL,mu><<EOF>> { return 'EOF'; }