From 0767acc36c2404640cf4b828d36580030b10d9b5 Mon Sep 17 00:00:00 2001 From: Alan Johnson Date: Mon, 6 Sep 2010 22:53:48 -0400 Subject: [PATCH] Added a readme file and made a few fixes that were discovered while writing it. --- README.markdown | 117 ++++++++++++++++++++++++++++++++++++++++++++++ lib/handlebars.js | 4 +- 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 README.markdown diff --git a/README.markdown b/README.markdown new file mode 100644 index 00000000..50efe1c9 --- /dev/null +++ b/README.markdown @@ -0,0 +1,117 @@ +Handlebars.js +============= + +Handlebars.js is an extension to the [Mustache templating language](http://mustache.github.com/) created by Chris Wanstrath. Handlebars.js and Mustache are both logicless templating languages that keep the view and the code separated like we all know they should be. + +Installing +---------- +Installing Handlebars is easy. Simply [download the package from GitHub](https://github.com/wycats/handlebars.js/zipball/master) and add lib/handlebars.js to your web pages. + +Usage +----- +In general, the syntax of Handlebars.js templates is identical to Mustache templates. For basic syntax, check out the [Mustache manpage](http://mustache.github.com/mustache.5.html). + +Once you have a template, use the Handlebars.compile method to compile the template into a function. The generated function takes two arguments, a hash of data to apply to the template and an option hash of functions to use as helpers. Here's an example: + + var source = "

Hello, my name is {{name}}. I am from {{hometown}}. I have " + + "{{kids/length}} kids:

" + + ""; + var template = Handlebars.compile(source); + + var data = { "name": "Alan", "hometown": "Somewhere, TX", + "kids": [{"name": "Jimmy", "age": "12"}, {"name": "Sally", "age": "4"}]}; + var result = template(data); + + // Would render: + //

Hello, my name is Alan. I am from Somewhere, TX. I have 2 kids:

+ // + +Differences Between Handlebars.js and Mustache +------------------------- +Handlebars.js adds a couple of additional features to make writing templates easier and also changes a tiny detail of how partials work. + +### Paths + +Handlebars.js supports an extended expression syntax that we call paths. Paths are made up of typical expressions and / characters. Expressions allow you to not only display data from the current context, but to display data from contexts that are descendents and ancestors of the current context. + +To display data from descendent contexts, use the `/` character. So, for example, if your data were structured like: + + var data = {"person": { "name": "Alan" }, company: {"name": "Rad, Inc." } }; + +you could display the person's name from the top-level context with the following expression: + + {{person/name}} + +Similarly, if already traversed into the person object you could still display the company's name with an expression like `{{../company/name}}`, so: + + {{#person}}{{name}} - {{../company/name}}{{/person}} + +would render: + + Alan - Rad, Inc. + +### Block Helpers + +Handlebars.js also adds the ability to define block helpers. Block helpers are functions that can be called from anywhere in the template. Here's an example: + + var source = ""; + var link = function(fn) { + return '' + fn(this) + ''; + }; + var template = Handlebars.compile(source); + + var data = { "people": [ + { "name": "Alan", "id": 1 }, + { "name": "Yehuda", "id": 2 } + ]}; + template(data, { "link": link }); + + // Should render: + // + +Whenever the block helper is called it is given a single parameter, the compiled contents of the block. Inside of the block helper the value of `this` is the current context. The context includes a method `__get__` that helps to translate paths into values for use within the helper. + +### Partials + +To specify the set of available partials when rendering a template, set them to the partials key of the blocks hash. Partials can be either the string value of the partial source or a precompiled partial function. Here's an example: + + var source = ""; + var partials = { "link": '{{name}}' }; + var template = Handlebars.compile(source); + + var data = { "people": [ + { "name": "Alan", "id": 1 }, + { "name": "Yehuda", "id": 2 } + ]}; + template(data, { "partials": partials }); + + // Should render: + // + +Precompiling Templates +---------------------- + +A node.js compatible command-line tool is included in the lib folder. compiler.js takes arguments of the form MethodName=source.hbs and generates a source file with source templates compiled into methods with the given names. + + node lib/compiler.js Template=templates/template.hbs Partial=templates/partial.hbs + +Performance +----------- +In a rough performance test, precompiled Handlebars.js templates rendered in about half the time of Mustache templates. It would be a shame if it were any other way, since they were precompiled, but the difference in architecture does have some big performance advantages. + +Known Issues +------------ +* Handlebars.js can be a bit cryptic when there's an error during compilation, and it can be even more cryptic when there's an error while rendering. + +Helping Out +----------- +If you notice any problems, please report them to the GitHub issue tracker at [http://github.com/wycats/handlebars.js/issues](http://github.com/wycats/handlebars.js/issues). Feel free to contact commondream or wycats through GitHub with any other questions or feature requests. diff --git a/lib/handlebars.js b/lib/handlebars.js index 59de3a0e..94edac0c 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -1,6 +1,7 @@ Handlebars = { compile: function(string) { var fnBody = Handlebars.compileFunctionBody(string); + console.log(fnBody); return new Function("context", "fallback", fnBody); }, @@ -22,6 +23,7 @@ Handlebars = { escapeText: function(string) { string = string.replace("'", "\\'"); + string = string.replace("\"", "\\\""); if (string.slice(-1) == "\\") { string = string + "\\"; } @@ -38,7 +40,7 @@ Handlebars = { string = ""; } - return string.replace(/&(?!\w+;)|["\\<>]/g, function(str) { + return string.toString().replace(/&(?!\w+;)|["\\<>]/g, function(str) { switch(str) { case "&": return "&";