Coder Social home page Coder Social logo

handlebars-lang / handlebars.js Goto Github PK

View Code? Open in Web Editor NEW
17.7K 451.0 2.0K 3.96 MB

Minimal templating on steroids.

Home Page: http://handlebarsjs.com

License: MIT License

JavaScript 94.66% HTML 2.19% Ruby 0.24% Shell 0.52% TypeScript 2.19% Handlebars 0.13% Mustache 0.06%
handlebars mustache templates

handlebars.js's People

Contributors

blakeembrey avatar blikblum avatar denniskuczynski avatar dmarcotte avatar ericbn avatar erisds avatar jasondavies avatar jaylinski avatar jjclark1982 avatar kabirbaidhya avatar kiall avatar kpdecker avatar lawnsea avatar leshill avatar liqiang372 avatar machty avatar marado avatar marcioj avatar mmun avatar nalanj avatar nknapp avatar paulfalgout avatar rgrove avatar ryanmurakami avatar slexaxton avatar travnels avatar tricknotes avatar wagenet avatar wycats avatar zaach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

handlebars.js's Issues

Blocks must be non-empty

when evaluating a block, handlebars fails if there is no content. eg

{{#my_list}}{{/my_list}}

or
{{^my_list}}{{/my_list}}

Not sure if this is a bug, but it would be nice to be able to do.

License

I'm looking at using Handlebars.js in a product at my day-job. Unfortunately, I've got to get permission from legal, and they won't bless its use without a license. Is there a particular license you're releasing Handlebars under? I couldn't find one in the repository.

Block Helpers not working.

Block helper functions aren't able to call get or fn as functions don't seem to survive the contextWrapper. Tested in FF, Chrome and Safari.

From the example function...
this.get is not a function
[Break on this error] return '<a href="/people/' + this.__...+ this.get("id") + '">' + '';

zero rendered as empty string

line: Handlebars.compile("num1: {{num1}}, num2: {{num2}}")({num1: 42, num2: 0});
output: 'num1: 42, num2:'

output should be: 'num1: 42, num2: 0'

Memoization of Paths Collision

Memoized paths can sometimes collide with methods on the array object. I updated it to use the following code instead, and it fixed the problem:

parsePath: function(path) {
if (path == null) {
return [0, []];
} else if (Handlebars.pathPatterns["hbr-" + path] != null) {
return Handlebars.pathPatterns["hbr-" + path];
}

var parts = path.split("/");
var readDepth = false;
var depth = 0;
var dig = [];
for (var i = 0, j = parts.length; i < j; i++) {
  switch(parts[i]) {
    case "..":
      if (readDepth) {
        throw new Handlebars.Exception("Cannot jump out of context after moving into a context."); 
      } else {
        depth += 1;
      }
      break;
    case ".":
      // do nothing - using .'s is pretty dumb, but it's also basically free for us to support
    case "this":
      // if we do nothing you'll end up sticking in the same context
      break;
    default:
      readDepth = true;
      dig.push(parts[i]);
  }
}

var ret = [depth, dig];
Handlebars.pathPatterns["hbr-" + path] = ret;
return ret;

},

Dependencies for build should be more explicit

I'm not a Ruby programmer, but I wanted to build handlebars on my (Ubuntu) machine. It would be nice to have better documentation on how to build. Your readme states:

just run 'rake release'

I did not find it that simple. I had to:

apt-get install ruby
apt-get install rubygems
gem install bundler
gem install diff-lcs
gem install rspec
gem install rspec-core

And now I'm stuck with the error message:

Could not find rspec-core-2.1.0 in any of the sources

Sorry if I'm being stupid - thanks for the help.

function require is not defined ??

I'm pretty New to Mustache and Handlebars and seem to be missing some critical piece.

I am getting an error on line 1 of handlebars.js -> var Handlebars = require("handlebars/base");
It seems to be using a require wrapper function but I get an undefined error so I'm assuming i am missing a dependency?

Can anybody point me in the right direction. Any help would be greatly appreciated. Thanks.

Context is wrong when using paths inside section blocks

When you use paths inside a section block ({{/some/thing}}), the context is wrong when handlebars calls thing().

See the following code:

    var templateSrc1 = "Testing the context blocks with paths: {{#nestedObject/bar}} Yes {{/nestedObject/bar}}";

    function SomeObject(nestedObject) {
        this.name = 'SomeObject';
        this.nestedObject = nestedObject;
    }

    function AnotherObject(_bar) {
        this.name = 'AnotherObject';
        this._bar = _bar;
        this.bar = function() {
            console.log('this inside AnotherObject.bar', this, this.name);
            return this.bar;
        }
    }

    var view = new SomeObject(new AnotherObject("the bar value")),
        template = Handlebars.compile(templateSrc1);

    console.log('Template output: ', template(view));

The output I'd expect:

This when inside AnotherObject.bar: Object {...} AnotherObject
Template output: Testing the context blocks with paths: Yes

But when you run it, you really get:

This when inside AnotherObject.bar: Object {...} SomeObject
Template output: Testing the context blocks with paths: undefined

Maybe I'm wrong, but I'd expect that bar() would be called with the context set to nestedObject.

ps: No offense intended, but I think that handlebars.js isn't quite ready for "serious" usage yet. You've done some great work and I can't wait until I can use it, but I think that I'm going to have to switch back to our own custom hacked mustache.js for now. (Maybe I can help and commit fixes later, but I unfortunately don't have the time to do it now).

edit: Looks like the same thing happens in expressions too ({{some/path}}).

Problems when using ids-with-dashes

The parser doesn't recognize hyphens as part of the key / ID. This is a problem with cross-site Ajax requests.

I tried to change line 24 in src/handlebars.l ( see rmetzler@56ec990#L1L24 ) but there was another problem I didn't found a simple solution yet.

current workaround: renaming the keys-with-dashes of the object into keys_with_underscores.

Helper error

Though the tests pass, when I re-create the test scenario on a web page, a simple helper does not work as expected.

var template = Handlebars.compile("{{#goodbyes}}{{{link}}}{{/goodbyes}}"),
data = {prefix: "/root", goodbyes: [{text: "Goodbye", url: "goodbye"}, {text: "Hello", url: "hello"}]},
helpers = {link: function() { 
  return "<a href='" + this.__get__("../prefix") + "/" + this.url + "'>" + this.text + "</a>";
}},
result = template(data, helpers);

console.log(result);

The code above results in an error-- data is undefined --and refers me to line 757 of handlebars.js from dist/:

result = data.apply(this.wrapContext(), params);

My suspicion is that my not having defined helperMissing has something to do with it.

Certain dot separated Expressions break

I have a template that uses expressions like {{de.tabtext}} and {{en.tabtext}} for a translation interface. While de.tabtext works, de.title and other variations throw a:

TypeError: 'undefined' is not an object (evaluating 'helpers.helperMissing.call')

The en.* expressions all seem to work. I assume that some parsing is going wrong but I couldn't figure out where to look. For now I changed it to german.* and english.* as this doesn't seem to have any issues. The context I'm feeding was:

de : {
    tabtext     : "foo",
    previewtext : "preview",
    title       : "title",
    text        : "text",
    caption     : "caption"
  },

en : {
    tabtext     : "foo",
    previewtext : "preview",
    title       : "title",
    text        : "text",
    caption     : "caption"
  }

Parse error when variable is in an html attribute

<div class="template redirect" data-path="{{data-path}}" data-template-id="{{data-template-id}}">
</div>

Error: Parse error on line 1:
...irect" data-path="{{data-path}}" data-te
--------------------^
Expecting 'ID'

I had to alter the the error message a bit to show exactly what the line with arrow (-----^) was pointing to in firebug.

Default helpers lost when passing in custom helpers to compiled template.

Given the following code:

var source = "{{#should_test}}{{test}}{{/should_test}}";
var helpers = {
  test: function() {
    return "test";
  }
};
var data = { "should_test": "true" };

var template = Handlebars.compile(source);

var result = template(data, helpers);

This will result in an exception such as:

TypeError: Cannot call method 'call' of undefined at Object.anonymous [as render] (eval at <anonymous> (/usr/local/lib/node/.npm/handlebars/0.9.0/package/lib/handlebars/vm.js:407:25))

I traced this to the fact when the 'helpers' are passed into the compiled template they replace the default helpers registered in base.js. Specifically the 'blockHelperMissing' helper is lost.

I'm not sure if it's the intention to replace these helpers, or if this is a bug.

Handlebars.js and Require.js

Require.js (http://requirejs.org/) adds the name require to the global namespace. If Require.js is included in the HTML template (simply a <script src>, without even being used), this causes Handlebars.js to throw an exception that exports is undefined at line 538.

537 if (typeof require !== 'undefined') {
538 exports.parser = handlebars;
539 exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); }

feature request: elsif

of course it can be done with the existing helpers (if, else, unless), but often elsif is just the natural choice people are used too.

License in its own File

Please add a copy of the MIT license in a file named LICENSE or ./MIT-LICENSE.

I understand that the README lists "Handlebars.js is released under the MIT license." But some people suffer a combination of maladies, of being finicky about licenses and of being ADHD, and this suggestion would make it take just that much less time to check the license.

A normal selector immediately following a partial fails for "undefined partial"

I am trying to integrate Handlebars.js into Sammy.js, and I can't get one of Sammy's tests passing. In the test, a partial is used and immediately followed by a normal {{something}}, but Handlebars.js raises an excaption stating that {{something}} is an undefined partial, even though it is just a regular selector. I have verified this behavior via a failing test which is here:

http://gist.github.com/597723

Thanks for a great library! I'm hoping to get a patch into Sammy.js for a Handlebars.js plugin, as I think your library is faster and far more flexible, but I'd like to get all the tests passing before I try.

Helpers boolean return values are rendered as text

Am I crazy?

This template:

{{#has_comments}}
<div class="comment_count">
    <i></i>{{comment_count}}
</div>
{{/has_comments}}

Is returned as:

false

With the following:

template({
    comments: []
},{
    has_comments: function(context, fn){
        if(context.comments.length > 0) return fn(context);

        return false;
    }
})

Shouldn't a block helper returning false cause the block to not be rendered? Mustache and Handlebars examples show that to be the case, but my Handlebars seems to not be doing so in the case above.

undefined?

If a particular replacement is undefined the app would crash. I think it should just replace with empty, as jquery tmpl does, without crashing the app.

How do I change this? Thanks.

TypeError: Object #<Object> has no method 'compile'

How do I fix this?

var handlebars = require("./handlebars.js")
var source = "hi {{dude}}";
var template = handlebars.compile(source);

I tried everything, I tried pre4+pre5, both precompiled and compiled myself.
I copied all the files from the 'dist' directory into my working directory. I also tried it with the older tag 0.9.0.pre.4.

Exception in IE7 using 0.9.0.pre-5

Using IE7 you will get:

SCRIPT1028: Expected identifier, string or number
handlebars-0.9.0.pre.5.js?1302572252, line 243 character 17

This can be fixed by removing the trailing comma at the end of line 242.

Explanation of how the code is compiled in the README

I fixed a bug with my copy of handlebars, forked the repo, searched for quite some time to find where my fix was in the source ... gave up.

I've never felt like an idiot trying to to contribute to a JavaScript project. I guess there's a first time for everything.

A quick "contributing" section would be nice that would explain what on earth is going on with the source code.

Firefox unable to render within <select>?

I have the following case:

  <select name="category">
     <option value="-1">Select One</option>
  {{#each categories}}
     {{#each subcategories}}
     <option value="{{id}}">{{description}}</option>
     {{/each}}
  {{/each}}
  </select>

In IE and Chrome, this renders fine; in Firefox only one blank option gets rendered. If I take the block outside of the <select></select> it renders fine.

Any ideas?

Error in Handlebars.Runtime.mustache on IE 8

When calling Handlebars.compile on IE 8, I get an "Object does not support this property or method" error. The culprit seems to be Handlebars.Runtime.mustache Line 117.

For some reason, the toString method isn't on the Handlebars.Runtime prototype. The same code works perfectly in Firefox and Chrome, but IE 8 chokes on it. I believe Firefox and Chrome are implicitly pulling in the Object prototype, but IE isn't.

Paths to Nowhere

There should be some sort of rescue or return undefined if a path {{foo/bar}} points to a foo.bar = null. Currently, it just throws an error that there is no bar. There is, it is just null.

Iterating over an array with different partials should result in different output

I've observed some wrong behavior of handlebars.js. The behaviour is reproduced by the test introduced in SHA: 89034d3 :

test("iterating over an array with different partials should result in different output", function() { 
  var aPartial = Handlebars.compile("A");
  var anotherPartial = Handlebars.compile("B");
  var template = Handlebars.compile("{{#each .}}{{> item }}{{/each}}");

  template(["A", "B"], null, { item: aPartial });
  var result = template(["A", "B"], null, { item: anotherPartial });
  equal("BB", result, "uses the second partial: " + result + " should be BB.");
});

I've investigated the issue and found out that it is related to the caching done in createFunction in JavascriptCompiler. It caches helpers and partials in a closure but doesn't check if the partials or the helpers changed since the last invocation. The simplest solution would be to simply remove the caching of the closures or to disable it if partials and helpers are involved. But i actually don't understand the impact of this changes.

node.js and npm support

How is handlebars.js expected to be used in node.js?

I see that object handlebars is being exported as exports.parser but the full Handlebars functionality as documented is only implemented only by Handlebars object.

Is there a reason why it's this way? Also, Is there a reason why handlebars.js is not a npm package?

Failed to find parse() function

I'm trying to call handlebars from a RingoJS web application, however the current code base seems to be throwing some errors. Basically, when I call the compile() function, it makes a call to Handlebars.parse(), however parse() is an undefined property on Handlebars.

I added some code to the compile() function to display the properties which are on the Handlebars object. No parse method discovered this way either.

js: warning: "handlebars/vm.js", line 591: Assignment to undeclared variable compilerWords
15378 [qtp448511246-20] INFO  actions  - Initializing actions.js
15403 [qtp448511246-20] INFO  actions  - Handling request
15412 [qtp448511246-20] INFO  handlebars.vm  -  Exception: 
15415 [qtp448511246-20] INFO  handlebars.vm  -  SafeString: 
15421 [qtp448511246-20] INFO  handlebars.vm  -  Utils: [object Object]
15422 [qtp448511246-20] INFO  handlebars.vm  -  AST: [object Object]
15438 [qtp448511246-20] INFO  handlebars.vm  -  Visitor: 
15439 [qtp448511246-20] INFO  handlebars.vm  -  PrintVisitor: 
15439 [qtp448511246-20] INFO  handlebars.vm  -  Context: 
15453 [qtp448511246-20] INFO  handlebars.vm  -  K: 
15454 [qtp448511246-20] INFO  handlebars.vm  -  proxy: 
15455 [qtp448511246-20] INFO  handlebars.vm  -  Runtime: 
15455 [qtp448511246-20] INFO  handlebars.vm  -  Compiler: 
15457 [qtp448511246-20] INFO  handlebars.vm  -  JavaScriptCompiler: 
15458 [qtp448511246-20] INFO  handlebars.vm  -  VM: [object Object]
15458 [qtp448511246-20] INFO  handlebars.vm  -  compile: 
15492 [qtp448511246-20] ERROR stick.middleware.error  - TypeError: Cannot find function parse in object [object Object]. (handlebars/vm.js#617)
Script stack:
    at handlebars/vm.js:617 (anonymous)
    at actions.js:37 (anonymous)
    at stick/middleware/route.js:174 (route)
    at stick/middleware/params.js:82 (anonymous)
    at stick/middleware/notfound.js:28 (notfound)
    at stick/middleware/error.js:42 (error)
    at stick/middleware/mount.js:108 (mount)
    at stick/middleware/responselog.js:39 (responselog)
    at stick/middleware/static.js:49 (static)
    at stick/middleware/etag.js:22 (etag)
    at stick/middleware/gzip.js:39 (gzip)
    at stick.js:36 (app)
    at ringo/jsgi.js:41 (handleRequest)

Compiled File Header Comment - Copyright & Version

Please add a header comment to the handlebars.js compiled output file.

Please include

  • the project URL
  • copyright information
  • the version number
  • the name of the license under which the project is released

If you have a minifying build step (e.g., Closure Compiler), please ensure that the header comment is preserved in the build output.

This helps when we have a copy of handlebars.js in a project, and want to remind ourselves quickly of what this file is, what version it is, and where exactly to go to check for an updated version.

Context is wrong inside inverted sections

Here is a test case: http://gist.github.com/639221

I've only had a little bit of time to look at the handlebars code, but it seems like a few things are out of place for inverted sections. Like, why is "fn70Not" referred to, but never defined? (see the compiled template output at the bottom of the gist)

I'll try to dig a little more.

Compile function craches in IE everytime.

I'm testing my project on IE but I'm finding that the "compile" function fails everytime: it even refuses to compile the examples in the readme or something as simple as this:

var t = Handlebars.compile("<li></li>");

I think it has a problem with each and every special character including slashes, quotes, dots and commas. Is this a known issue? Is there a workaround?

trailing comma in utils.js

In lib/handlebars/utils.js line 19 has a trailing comma:

var escape = {
  "<": "&lt;",
  ">": "&gt;",
};

Should be:

var escape = {
  "<": "&lt;",
  ">": "&gt;"
};

use registered helpers also when passing additional helpers to template function

Currently if template function is called with both data object and helpers object as parameters then you cannot use default helpers (that are registered with Handlebars.registerHelper) in your template. See https://github.com/wycats/handlebars.js/blob/master/lib/handlebars/base.js#L23

As I result I almost always need to call templates with

template(object, _.defaults({additionalHelper: ...}, Handlebars.helpers))

to ensure that I can use both additionalHelper as well as registered helpers in my template (_.defaults is utility function from underscore.js).

It would be better if Handlebars would always fallback to Handlebars.helpers when property is not found in data object as well as in provided helpers object. If helper with the same name as registered helper is provided in template function call then it would take precedence over registered helper.

dot separated path broken within loop

I'm using v0.9.0.pre.4

The data
{
names: [
{ first: "Peter", last: "Griffin" },
{ first: "Meg", last: "Griffin" }
]
}

the template


    {{#each names}}
  • {{this.first}} {{this.last}}


  • {{/each}}

now if I change the dot into slash (which is deprecated according to the docs), it works fine.

The first parameter of block helpers (documentation)

I'm currently struggling to see the purpose of the first parameter of block helper functions (context). Could you explain how it differs from this?

A brief look at the code suggests that what a block helper calls this is actually called context or wrappedContext internally, and what a block helper calls context is called proxy internally. (In the addBlock and handleBlock methods.) Beyond that I find it gets a bit involved. A few experiments suggest that they behave quite similarly, with subtle differences (e.g. issue #11 doesn't occur with this replaced by context).

Moreover, the README suggests that:

Whenever the block helper is called it is given a single parameter, the compiled contents of the block.

...which is not the case, unless I misunderstand the sentence. Should that be more something like:

Whenever the block helper is called it is given two parameters: a context (which differs from this as follows: ...) and the precompiled contents of the block.

Hope you could shed some light on the intentions behind this vs. context. Thanks!

Unexpected string in simple template

Hi Yehuda,

Thanks for another great open-source tool!

I'm looking to switch from Mustache to Handlebars for some of the cool path and helper additions but mostly for the speed increase thanks to use of compilation. I'm having a small problem though with creating templates that I have used previously with Mustache. Here's an example:

html = '<div title="Look at me" id="{{id}}">...</div>';
template = Handlebars.compile(html)

…produces a SyntaxError: Unexpected string.

A similar procedure in Mustache works:

html = '<div title="Look at me" id="{{id}}">...</div>';
Mustache.to_html(html, {id: 'unique'})

I can of course use a quoted string in my view like so…

html = '<div title={{quoted_title}} id={{quoted_id}}>...</div>';
template = Handlebars.compile(html)
template({quoted_title: '"Look at me"', quoted_id: '"unique"'})

…but this feels a bit messy when I only want to insert a double quoted string.

I believe the issue stems from double quotes not being escaped properly as things like Handlebars.compile(' " " ') also produce syntax errors. Interestingly, due to compilation three double quotes produce an illegal token error.

Kind regards,
James

Full Path

Make it possible to access the full path to the current context somehow, may with this.__fullPath or something similar.

Escaping backslashes by default

I can see the thinking behind this: backslashes are JavaScript-escaped so that data inserted into JavaScript code aren't messed up. However, for my particular use-case I don't actually want backslashes to be escaped as this results in a double-backslash being shown to the user.

I'm a big fan of escaping being on by default to prevent XSS, but conflating both HTML and JavaScript-escaping together seems inelegant. I can see two main options, and of course alternatively we can just suggest that people like me use triple-mustaches!

  1. Drop the backslash escape for {{ var }} and introduce a new syntax for JS-escaping. Not sure I like introducing too many syntaxes though.
  2. Drop the backslash escape for {{ var }} and advise people to specify a JSON.stringify-based (or similar) block helper for JS-escaping.

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.