diff options
-rw-r--r-- | README.markdown | 2 | ||||
-rw-r--r-- | lib/handlebars/compiler.js | 2 | ||||
-rw-r--r-- | lib/handlebars/utils.js | 9 | ||||
-rw-r--r-- | spec/qunit_spec.js | 12 | ||||
-rw-r--r-- | spec/tokenizer_spec.rb | 11 | ||||
-rw-r--r-- | src/handlebars.l | 2 |
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 = { "<": "<", - ">": ">" + ">": ">", + '"': """, + "'": "'", + "`": "`" }; - var badChars = /&(?!\w+;)|[<>]/g; - var possible = /[&<>]/; + var badChars = /&(?!\w+;)|[<>"'`]/g; + var possible = /[&<>"'`]/; var escapeChar = function(chr) { return escape[chr] || "&" 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: "&\"\\<>"}, '&\"\\<>', - "by default expressions should be escaped"); - shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>', "expressions with {{& handlebars aren't escaped"); + shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&"'`\\<>', + "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'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'; } |