First pass at getting booleans working
This commit is contained in:
+82
-17
@@ -1,7 +1,12 @@
|
||||
Handlebars = {
|
||||
compile: function(string) {
|
||||
var compiler = new Handlebars.Compiler(string);
|
||||
return compiler.compile();
|
||||
var result = compiler.compile();
|
||||
return new Function("context", result);
|
||||
},
|
||||
|
||||
isFunction: function(fn) {
|
||||
return toString.call(fn) === "[object Function]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +15,31 @@ Handlebars.Compiler = function(string) {
|
||||
this.pointer = -1;
|
||||
this.mustache = false;
|
||||
this.text = "";
|
||||
this.fn = "var out = ''; ";
|
||||
this.fn = "var out = ''; var lookup; ";
|
||||
this.newlines = "";
|
||||
this.comment = false;
|
||||
}
|
||||
|
||||
Handlebars.catchAll = function(object, fn) {
|
||||
var ret = "";
|
||||
|
||||
if(object === true) {
|
||||
return fn(this);
|
||||
} else if(object === false) {
|
||||
return "";
|
||||
} else if(toString.call(object) === "[object Array]") {
|
||||
for(var i=0, j=object.length; i<j; i++) {
|
||||
ret = ret + fn(object[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
Handlebars.Compiler.prototype = {
|
||||
getChar: function() {
|
||||
this.pointer++;
|
||||
return this.string[this.pointer];
|
||||
getChar: function(n) {
|
||||
var ret = this.peek(n);
|
||||
this.pointer = this.pointer + (n || 1);
|
||||
return ret;
|
||||
},
|
||||
|
||||
peek: function(n) {
|
||||
@@ -27,10 +48,9 @@ Handlebars.Compiler.prototype = {
|
||||
return this.string.slice(start, start + n);
|
||||
},
|
||||
|
||||
compile: function() {
|
||||
compile: function(endCondition) {
|
||||
var chr;
|
||||
while(chr = this.getChar()) {
|
||||
// entering mustache state
|
||||
if(chr === "{" && this.peek() === "{" && !this.mustache) {
|
||||
this.getChar();
|
||||
this.parseMustache();
|
||||
@@ -42,24 +62,41 @@ Handlebars.Compiler.prototype = {
|
||||
}
|
||||
this.text = this.text + chr;
|
||||
}
|
||||
|
||||
if(endCondition && endCondition(this)) { break };
|
||||
}
|
||||
|
||||
this.fn = this.fn + "\nreturn out;";
|
||||
return new Function("context", this.fn);
|
||||
this.addText();
|
||||
return this.fn + "return out;";
|
||||
},
|
||||
|
||||
addText: function() {
|
||||
if(this.text) {
|
||||
this.fn = this.fn + "out = out + '" + this.text + "'; ";
|
||||
this.fn = this.fn + this.newlines;
|
||||
this.newlines = ""
|
||||
this.text = ""
|
||||
}
|
||||
},
|
||||
|
||||
addExpression: function(mustache) {
|
||||
this.fn = this.fn + "out = out + context['" + mustache + "']; ";
|
||||
},
|
||||
|
||||
parseMustache: function() {
|
||||
var chr, mustache;
|
||||
|
||||
if(this.peek() === "!") {
|
||||
var next = this.peek();
|
||||
|
||||
if(next === "!") {
|
||||
this.comment = true;
|
||||
this.getChar();
|
||||
} else if(next === "#") {
|
||||
this.openBlock = true;
|
||||
this.getChar();
|
||||
}
|
||||
|
||||
this.fn = this.fn + "out = out + '" + this.text + "'; ";
|
||||
this.fn = this.fn + this.newlines;
|
||||
this.newlines = ""
|
||||
this.text = ""
|
||||
this.addText();
|
||||
this.mustache = " ";
|
||||
|
||||
while(chr = this.getChar()) {
|
||||
@@ -67,9 +104,36 @@ Handlebars.Compiler.prototype = {
|
||||
mustache = this.mustache.trim();
|
||||
this.mustache = false;
|
||||
this.getChar();
|
||||
if(this.comment) { this.comment = false; return; }
|
||||
this.fn = this.fn + "out = out + context['" + mustache + "']; ";
|
||||
return;
|
||||
if(this.comment) {
|
||||
this.comment = false;
|
||||
return;
|
||||
} else if(this.openBlock) {
|
||||
var compiler = new Handlebars.Compiler(this.string.slice(this.pointer + 1, -1));
|
||||
|
||||
// compile with a custom EOF instruction
|
||||
var result = compiler.compile(function(compiler) {
|
||||
if(compiler.peek(mustache.length + 5) === "{{/" + mustache + "}}") {
|
||||
compiler.getChar(mustache.length + 5);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
this.pointer += compiler.pointer + 1;
|
||||
|
||||
// each function made internally needs a unique IDs. These are locals, so they
|
||||
// don't need to be globally unique, just per compiler
|
||||
var fnId = "fn" + this.pointer.toString();
|
||||
|
||||
this.fn += "var " + fnId + " = function(context) {" + result + "}; ";
|
||||
this.fn += "lookup = context['" + mustache + "']; ";
|
||||
this.fn += "if(Handlebars.isFunction(lookup)) out = out + " + fnId + "(lookup); "
|
||||
this.fn += "else if(typeof lookup !== 'undefined') out = out + Handlebars.catchAll(lookup, " + fnId + "); "
|
||||
|
||||
this.openBlock = false;
|
||||
return;
|
||||
} else {
|
||||
this.addExpression(mustache);
|
||||
return;
|
||||
}
|
||||
} else if(this.comment) {
|
||||
;
|
||||
} else {
|
||||
@@ -78,3 +142,4 @@ Handlebars.Compiler.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-4
@@ -1,17 +1,28 @@
|
||||
module("basic context");
|
||||
|
||||
test("compiling with a basic context", function() {
|
||||
var string = "Goodbye\n{{cruel}}\n{{world}}";
|
||||
var string = "Goodbye\n{{cruel}}\n{{world}}!";
|
||||
var template = Handlebars.compile(string);
|
||||
|
||||
result = template({cruel: "cruel", world: "world"});
|
||||
equal("Goodbye\ncruel\nworld", result, "it works if all the required keys are provided");
|
||||
equal(result, "Goodbye\ncruel\nworld!", "it works if all the required keys are provided");
|
||||
});
|
||||
|
||||
test("comments", function() {
|
||||
var string = "{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}";
|
||||
var string = "{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!";
|
||||
var template = Handlebars.compile(string);
|
||||
|
||||
result = template({cruel: "cruel", world: "world"});
|
||||
equal("Goodbye\ncruel\nworld", result, "it works if all the required keys are provided");
|
||||
equal("Goodbye\ncruel\nworld!", result, "it works if all the required keys are provided");
|
||||
});
|
||||
|
||||
test("boolean", function() {
|
||||
var string = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!"
|
||||
var template = Handlebars.compile(string);
|
||||
|
||||
result = template({goodbye: true, world: "world"});
|
||||
equal("GOODBYE cruel world!", result, "booleans work when true");
|
||||
|
||||
result = template({goodbye: false, world: "world"});
|
||||
equal("cruel world!", result, "booleans work when true");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user