diff --git a/TODO.markdown b/TODO.markdown index 68e76436..acc297ff 100644 --- a/TODO.markdown +++ b/TODO.markdown @@ -6,3 +6,5 @@ * data-binding for iteration-style block helpers * README * Rationale (how it's different from mustache, and why) + +* Refactor blocks/inverted sections so shared code isn't copied and pasted diff --git a/lib/handlebars.js b/lib/handlebars.js index 80e1de0b..351673bb 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -107,6 +107,18 @@ Handlebars = { } return [depth, dig]; + }, + + isEmpty: function(value) { + if (typeof object === "undefined") { + return true; + } else if (!object) { + return true; + } else if(toString.call(object) === "[object Array]" && object.length == 0) { + return true; + } else { + return false; + } } } @@ -120,6 +132,7 @@ Handlebars.Compiler = function(string) { this.comment = false; this.escaped = true; this.partial = false; + this.inverted = false; }; Handlebars.Exception = function(message) { @@ -204,6 +217,23 @@ Handlebars.Compiler.prototype = { this.fn += "else if(typeof " + expr + "!== 'undefined') out = out + " + escapeCall + expr + ");"; }, + addInvertedSection: function(mustache) { + var result = this.compileToEndOfBlock(mustache); + + + // 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 proxy = Handlebars.buildContext(context, stack);"; + this.fn += "var " + fnId + " = function(context) {" + result + "}; "; + this.fn += "lookup = " + this.lookupFor(mustache) + "; "; + this.fn += "if(Handlebars.isFunction(lookup) && Handlebars.isEmpty(lookup())) out = out + " + fnId + "(proxy);"; + console.log(this.fn); + + this.openBlock = false; + this.inverted = false; + }, + lookupFor: function(param) { var parsed = Handlebars.parsePath(param); var depth = parsed[0]; @@ -221,9 +251,7 @@ Handlebars.Compiler.prototype = { } }, - addBlock: function(mustache, param, parts) { - // set up the stack before the new compiler starts - this.fn += "stack.push(context);"; + compileToEndOfBlock: function(mustache) { var compiler = new Handlebars.Compiler(this.string.slice(this.pointer + 1, -1)); // sub-compile with a custom EOF instruction @@ -237,6 +265,14 @@ Handlebars.Compiler.prototype = { // move the pointer forward the amount of characters handled by the sub-compiler this.pointer += compiler.pointer + 1; + return result; + }, + + addBlock: function(mustache, param, parts) { + // set up the stack before the new compiler starts + this.fn += "stack.push(context);"; + var result = this.compileToEndOfBlock(mustache); + // 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(); @@ -271,6 +307,10 @@ Handlebars.Compiler.prototype = { } else if (next === ">") { this.partial = true; this.getChar(); + } else if (next === "^") { + this.inverted = true; + this.openBlock = true; + this.getChar(); } else if(next === "{" || next === "&") { this.escaped = false; this.getChar(); @@ -301,6 +341,9 @@ Handlebars.Compiler.prototype = { } else if (this.partial) { this.addPartial(mustache, param) return; + } else if (this.inverted) { + this.addInvertedSection(mustache); + return; } else if(this.openBlock) { this.addBlock(mustache, param, parts) return;