From 5097c1891230b72b41d0095f92be9a01404735e7 Mon Sep 17 00:00:00 2001 From: wycats Date: Sat, 11 Dec 2010 18:10:56 -0800 Subject: [PATCH] Make it possible to register helpers and partials and then skip passing in the helpers or partials later --- lib/handlebars.js | 25 +++++++++++++++++++++++-- lib/handlebars/runtime.js | 34 +++++++++++++++++----------------- spec/qunit_spec.js | 10 +++++----- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/lib/handlebars.js b/lib/handlebars.js index f0d4e943..a96df4cf 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -25,12 +25,33 @@ Handlebars.print = function(ast) { Handlebars.compile = function(string) { var ast = Handlebars.parse(string); - return function(context, fallback) { - var runtime = new Handlebars.Runtime(context, fallback); + return function(context, helpers, partials) { + var helpers, partials; + + if(!helpers) { + helpers = this.helpers; + } + + if(!partials) { + partials = this.partials; + } + + var runtime = new Handlebars.Runtime(context, helpers, partials); runtime.accept(ast); return runtime.buffer; }; }; + +Handlebars.helpers = {}; +Handlebars.partials = {}; + +Handlebars.registerHelper = function(name, fn) { + this.helpers[name] = fn; +}; + +Handlebars.registerPartial = function(name, str) { + this.partials[name] = str; +}; // END(BROWSER) exports.Handlebars = Handlebars; diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 75b9d9ab..b58ba241 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -19,9 +19,10 @@ Handlebars.Exception = require("handlebars/utils").Exception; // new Context given a path. For instance, if the data // is { person: { name: "Alan" } }, a Context wrapping // "Alan" can be extracted by searching for "person/name" -Handlebars.Context = function(data, fallback) { +Handlebars.Context = function(data, helpers, partials) { this.data = data; - this.fallback = fallback; + this.helpers = helpers || {}; + this.partials = partials || {}; }; Handlebars.Context.prototype = { @@ -29,7 +30,7 @@ Handlebars.Context.prototype = { // Make a shallow copy of the Context clone: function() { - return new Handlebars.Context(this.data, this.fallback); + return new Handlebars.Context(this.data, this.helpers, this.partials); }, // Search for an object inside the Context's data. The @@ -54,7 +55,7 @@ Handlebars.Context.prototype = { } if(parts.length === 1 && context.data === undefined) { - context.data = context.fallback[parts[0]]; + context.data = context.helpers[parts[0]]; } return context; @@ -69,18 +70,14 @@ Handlebars.proxy = function(obj) { return new Proxy(); }; -Handlebars.Runtime = function(context, fallback, stack) { +Handlebars.Runtime = function(context, helpers, partials, stack) { this.stack = stack || []; this.buffer = ""; - var newContext = this.context = new Handlebars.Context(); - if(context && context.isContext) { - newContext.data = context.data; - newContext.fallback = context.fallback; + this.context = context.clone(); } else { - newContext.data = context; - newContext.fallback = fallback || {}; + this.context = new Handlebars.Context(context, helpers, partials) } }; @@ -139,7 +136,7 @@ Handlebars.Runtime.prototype = { if(toString.call(data) !== "[object Function]") { params = [data]; - data = this.context.fallback.helperMissing; + data = this.context.helpers.helperMissing; } else { params = this.evaluateParams(mustache.params); } @@ -157,7 +154,7 @@ Handlebars.Runtime.prototype = { }, partial: function(partial) { - var partials = this.context.fallback.partials || {}; + var partials = this.context.partials || {}; var id = partial.id.original; var partialBody = partials[partial.id.original]; @@ -179,7 +176,7 @@ Handlebars.Runtime.prototype = { } else { context = this.context; } - var runtime = new Handlebars.Runtime(context, this.context.fallback, this.stack.slice(0)); + var runtime = new Handlebars.Runtime(context, null, null, this.stack.slice(0)); this.buffer = this.buffer + runtime.program(program); }, @@ -252,13 +249,16 @@ Handlebars.Runtime.prototype = { }, wrapProgram: function(program) { - var runtime = this, stack = this.stack.slice(0); + var runtime = this, + stack = this.stack.slice(0), + helpers = this.context.helpers, + partials = this.context.partials; + stack.push(this.context); - var fallback = this.context.fallback; return function(context) { if(context && context.isWrappedContext) { context = context.__data__; } - var runtime = new Handlebars.Runtime(context, fallback, stack); + var runtime = new Handlebars.Runtime(context, helpers, partials, stack); runtime.program(program); return runtime.buffer; }; diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js index d1c74a97..4b652a9f 100644 --- a/spec/qunit_spec.js +++ b/spec/qunit_spec.js @@ -378,7 +378,7 @@ test("basic partials", function() { var string = "Dudes: {{#dudes}}{{> dude}}{{/dudes}}"; var partial = "{{name}} ({{url}}) "; var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileTo(string, [hash, {partials: {dude: partial}}], "Dudes: Yehuda (http://yehuda) Alan (http://alan) ", + shouldCompileTo(string, [hash, {}, {dude: partial}], "Dudes: Yehuda (http://yehuda) Alan (http://alan) ", "Basic partials output based on current context."); }); @@ -386,7 +386,7 @@ test("partials with context", function() { var string = "Dudes: {{>dude dudes}}"; var partial = "{{#this}}{{name}} ({{url}}) {{/this}}"; var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileTo(string, [hash, {partials: {dude: partial}}], "Dudes: Yehuda (http://yehuda) Alan (http://alan) ", + shouldCompileTo(string, [hash, {}, {dude: partial}], "Dudes: Yehuda (http://yehuda) Alan (http://alan) ", "Partials can be passed a context"); }); @@ -395,7 +395,7 @@ test("partial in a partial", function() { var dude = "{{name}} {{> url}} "; var url = "{{url}}"; var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileTo(string, [hash, {partials: {dude: dude, url: url}}], "Dudes: Yehuda http://yehuda Alan http://alan ", "Partials are rendered inside of other partials"); + shouldCompileTo(string, [hash, {}, {dude: dude, url: url}], "Dudes: Yehuda http://yehuda Alan http://alan ", "Partials are rendered inside of other partials"); }); test("rendering undefined partial throws an exception", function() { @@ -409,14 +409,14 @@ test("GH-14: a partial preceding a selector", function() { var string = "Dudes: {{>dude}} {{another_dude}}"; var dude = "{{name}}"; var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileTo(string, [hash, {partials: {dude:dude}}], "Dudes: Jeepers Creepers", "Regular selectors can follow a partial"); + shouldCompileTo(string, [hash, {}, {dude:dude}], "Dudes: Jeepers Creepers", "Regular selectors can follow a partial"); }); test("Partial containing complex expression", function() { var template = "Dudes: {{#dudes}}{{> dude}} {{/dudes}}"; var dude = "{{../salutation}} {{name}}"; var hash = {salutation: "Mr.", dudes: [{name: "Yehuda"}, {name: "Alan"}]}; - shouldCompileTo(template, [hash, {partials: {dude: dude}}], "Dudes: Mr. Yehuda Mr. Alan "); + shouldCompileTo(template, [hash, {}, {dude: dude}], "Dudes: Mr. Yehuda Mr. Alan "); }); module("String literal parameters");