Merge remote-tracking branch 'upstream/master'
This commit is contained in:
+3
-1
@@ -205,7 +205,9 @@ Known Issues
|
||||
|
||||
Handlebars in the Wild
|
||||
-----------------
|
||||
* Don Park wrote an Express.js view engine adapter for Handlebars.js called [hbs](http://github.com/donpark/hbs)
|
||||
* [jblotus](http://github.com/jblotus) created [http://tryhandlebarsjs.com](http://tryhandlebarsjs.com) for anyone who would
|
||||
like to try out Handlebars.js in their browser.
|
||||
* Don Park wrote an Express.js view engine adapter for Handlebars.js called [hbs](http://github.com/donpark/hbs).
|
||||
* [sammy.js](http://github.com/quirkey/sammy) by Aaron Quint, a.k.a. quirkey, supports Handlebars.js as one of its template plugins.
|
||||
* [SproutCore](http://www.sproutcore.com) uses Handlebars.js as its main templating engine, extending it with automatic data binding support.
|
||||
|
||||
|
||||
@@ -314,12 +314,13 @@ 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 || !isNaN(name)) {
|
||||
return parent + "['" + name + "']";
|
||||
} else if (/^[0-9]+$/.test(name)) {
|
||||
if (/^[0-9]+$/.test(name)) {
|
||||
return parent + "[" + name + "]";
|
||||
} else {
|
||||
return parent + "." + name;
|
||||
} else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
|
||||
return parent + "." + name;
|
||||
}
|
||||
else {
|
||||
return parent + "['" + name + "']";
|
||||
}
|
||||
},
|
||||
|
||||
@@ -521,7 +522,8 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
+ " || "
|
||||
+ this.nameLookup('depth' + this.lastContext, name, 'context');
|
||||
}
|
||||
|
||||
|
||||
toPush += ';';
|
||||
this.source.push(toPush);
|
||||
} else {
|
||||
this.pushStack('depth' + this.lastContext);
|
||||
@@ -530,7 +532,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
|
||||
lookup: function(name) {
|
||||
var topStack = this.topStack();
|
||||
this.source.push(topStack + " = " + this.nameLookup(topStack, name, 'context') + ";");
|
||||
this.source.push(topStack + " = " + topStack + " ? " + this.nameLookup(topStack, name, 'context') + " : " + topStack + ";");
|
||||
},
|
||||
|
||||
pushStringParam: function(string) {
|
||||
@@ -733,6 +735,13 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
compilerWords[reservedWords[i]] = true;
|
||||
}
|
||||
|
||||
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
|
||||
if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
})(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
|
||||
|
||||
Handlebars.precompile = function(string, options) {
|
||||
|
||||
@@ -130,6 +130,16 @@ test("nested paths with empty string value", function() {
|
||||
"Goodbye world!", "Nested paths access nested objects with empty string");
|
||||
});
|
||||
|
||||
test("literal paths", function() {
|
||||
shouldCompileTo("Goodbye {{[@alan]/expression}} world!", {"@alan": {expression: "beautiful"}},
|
||||
"Goodbye beautiful world!", "Literal paths can be used");
|
||||
});
|
||||
|
||||
test("literal paths with square brackets in them", function() {
|
||||
shouldCompileTo("Goodbye {{[@alan]]/expression}} world!", {"@alan]": {expression: "beautiful"}},
|
||||
"Goodbye beautiful world!", "Literal paths with square brackets in them can be used");
|
||||
});
|
||||
|
||||
test("--- TODO --- bad idea nested paths", function() {
|
||||
return;
|
||||
var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"};
|
||||
@@ -449,6 +459,13 @@ test("GH-14: a partial preceding a selector", function() {
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude:dude}], true, "Dudes: Jeepers Creepers", "Regular selectors can follow a partial");
|
||||
});
|
||||
|
||||
test("Partials with literal paths", function() {
|
||||
var string = "Dudes: {{> [dude]}}";
|
||||
var dude = "{{name}}";
|
||||
var hash = {name:"Jeepers", another_dude:"Creepers"};
|
||||
shouldCompileToWithPartials(string, [hash, {}, {dude:dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
|
||||
});
|
||||
|
||||
module("String literal parameters");
|
||||
|
||||
test("simple literals work", function() {
|
||||
@@ -942,3 +959,11 @@ test("when inside a block in String mode, .. passes the appropriate context in t
|
||||
equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke wot", "Proper context variable output");
|
||||
});
|
||||
|
||||
module("Regressions")
|
||||
|
||||
test("GH-94: Cannot read property of undefined", function() {
|
||||
var data = {"books":[{"title":"The origin of species","author":{"name":"Charles Darwin"}},{"title":"Lazarillo de Tormes"}]};
|
||||
var string = "{{#books}}{{title}}{{author.name}}{{/books}}";
|
||||
shouldCompileTo(string, data, "The origin of speciesCharles DarwinLazarillo de Tormes",
|
||||
"Renders without an undefined property error");
|
||||
});
|
||||
@@ -28,6 +28,7 @@
|
||||
<mu>"false"/[}\s] { return 'BOOLEAN'; }
|
||||
<mu>[0-9]+/[}\s] { return 'INTEGER'; }
|
||||
<mu>[a-zA-Z0-9_$-]+/[=}\s/.] { return 'ID'; }
|
||||
<mu>\[.*\] { yytext = yytext.substr(1, yyleng-2); return 'ID'; }
|
||||
<mu>. { return 'INVALID'; }
|
||||
|
||||
<INITIAL,mu><<EOF>> { return 'EOF'; }
|
||||
|
||||
Reference in New Issue
Block a user