Escaping curly brackets standing next to expression in handlebars - handlebars.js

Can't understand how to escape { or } symbols standing next to expression at handlebars java templating engine.
I'm using handlebars templates to generate plain text so I can't use HTML ASCII codes of braces as advised there.
I need expression like \{{{variable.name}}\} to be resolved to {variable.value}. Should I create helpers for that or there is a cleaner way?

Here are some examples of escaping. The last method escape with a helper (when the other methods are not possible).
$(document).ready(function () {
var context = {
"textexample1" : "hello",
"textexample2" : "<div><b>hello</b></div>",
"textexample3" : "{ 'json' : 'sample }"
};
Handlebars.registerHelper('surroundWithCurlyBraces', function(text) {
var result = '{' + text + '}';
return new Handlebars.SafeString(result);
});
var source = $("#sourceTemplate").html();
var template = Handlebars.compile(source);
var html = template(context);
$("#resultPlaceholder").html(html);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script id="sourceTemplate" type="text/x-handlebars-template">
Simple text : {{textexample1}}<br/>
Html text not escaped : {{textexample2}}<br/>
Html text escaped : {{{textexample2}}}<br/>
Json text : {{textexample3}}<br/>
Non JSON text with surrounding mustaches {} : { {{textexample1}} }<br/>
Non JSON text with surrounding mustaches (no space) : {{{textexample1}}}<br/>
Solution with helper : {{#surroundWithCurlyBraces textexample1}}{{/surroundWithCurlyBraces}}
</script>
<br/>
<div id="resultPlaceholder">
</div>

{{myvar}}{{append '' '}'}}
append helpers from here:
https://www.npmjs.com/package/handlebars-helpers#string

Had the same issue. Managed to make it work with a hack like this:
{{ curlyOpen }}{{ variable.name }}{{ curlyClose }}
Where you should define additional variables curlyOpen="{" and curlyClose="}" as part of your context.

I bumped into this.
In the end, adding a helper function was the easiest solution.
I enhanced the solution suggested by #Christophe since I also needed the camelCase version of the given parameter:
Handlebars.registerHelper('surroundWithCurlyBraces', function(text, camelCase) {
return new Handlebars.SafeString(surroundWithCurlyBraces(camelCase? _.camelCase(text): text));
});
Then you can call it as follows:
{{surroundWithCurlyBraces variable.name}}
or - if you need camelCase
{{surroundWithCurlyBraces variable.name true}}

Related

How to override Handlebars' `if` helper

I'm looking for a way to change how Handlebars' if helper works.
Mandrill has made a few modifications to the standard Handlebars. One of these handy changes is in the way they handle Handlebars' if block helper. They've added the ability to evaluate expressions inside the if helper like this:
{{#if `purchases > 3`}}
I need to be able to compile Mandrill templates locally, for testing and preview, and this feature is making it difficult. I know I can write my own custom helpers, but in this case I'm looking for a way to alter the way the built-in if helper works.
I guess I could build my own version of Handlebars.
Any other suggestions?
I don't think that there is a problem to redefine the standard helpers as long as yours are working fine. You'll find in the below snippet one example that override the if helper to put instead a text. So just register your own helper this will override the default one. If you want the {{else}} also working you'll have to handle it in your if helper code.
$(document).ready(function () {
var context = {
"textexample1" : "hello",
};
Handlebars.registerHelper('if', function(text) {
return new Handlebars.SafeString(text);
});
var source = $("#sourceTemplate").html();
var template = Handlebars.compile(source);
var html = template(context);
$("#resultPlaceholder").html(html);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script id="sourceTemplate" type="text/x-handlebars-template">
{{#if 'test override'}}
{{textexample1}}
{{/if}}
</script>
<br/>
<div id="resultPlaceholder">
</div>

What's the best/safest/most effective way of returning HTML from a Meteor helper?

I'm trying to return HTML from a helper function after certain logical conditions are met. However, using the Spacebars.SafeString() function doesn't seem to be working and I gather that using this method to return HTML is unsafe and is prone to code injection from external sources.
For example, returning this HTML:
<object data="/rating/what.svg" width="20" height="20" type="image/svg+xml"></object>
Set up like this:
Spacebars.SafeString("<object data=" + "/rating/what.svg" + "width='20' height='20' type=" + "image/svg+xml" + "></object>");
Can anyone guide me to the best way to return HTML from a helper and how to do such a task? Couldn't find a definitive answer anywhere else.
First of all, if your requirements allow it, don't return HTML at all, just use a template and populate it with a data context, for example:
in your template:
<template name="someHtml">
<object data="/rating/{{dynamicName}}.svg" width="20" height="20" type="image/svg+xml"></object>
</template>
in the corresponding helper:
Template.someHtml.helpers({
dynamicName: function() {
return 'what'; // obviously, you generate this with some code
}
})
But, if you truly must use html content to be printed, you can use one of the two most popular sanitization packages, either djedi:sanitize-html-client or vazco:universe-html-purifier
With the first:
cleanHtml = sanitizeHtml(dirtyHtml, {
allowedTags: [ 'b', 'i', 'em', 'strong', 'a' ],
allowedAttributes: {
'a': [ 'href' ]
}
});
and with the latter:
cleanHtml = UniHTML.purify(dirtyHtml, {
withoutTags: ['b', 'img'],
noFormatting: true
});
And then of course you include the return value of these in your template with either triple braces so that the HTML is not escaped.
You are correct in that Spacebars.SafeString() can return unsafe code. Your best bet is to strip out bad tags or injections that you do not want and either use Spacebars.SafeString() or triple brace syntax like below:
<div>
{{{htmlHelper}}}
</div>
htmlHelper: function() {
return "<img src=..."
}

Parse an Escaped HTML that comes from Meteor Collecction

My collection contains escape HTML entities such as &lt, &gt etc. when i retrieve and display it, it escapes and prints the respective characters but does not interpret the HTML.
Eg:
Template.Help.helpers({
faq_content: function () {
var x = Help.findOne({});
return x.faq;
}
})
assuming x takes the following value:
x =
{
faq: <div class=\"help_articles\">\\n
....some_content....\\n
</div>
tips: <div class=\"help_articles\">\\n
....some_content....\\n
</div>
articles: <div class=\"help_articles\">\\n
....some_content....\\n
</div>
}
Even when i place this helper using three curly braces i.e,
{{{faq_content}}} ,
The content that gets displayed on the Browser is
<div class="help_articles">....some_content....</div>.
This gets displayed as text but i want it to be interpreted into HTML.
Please suggest some solution
Looks like you need to _.unescape() the string once before presenting inside the {{{}}} braces:
Template.Help.helpers({
faq_content: function () {
var x = Help.findOne({});
return _.unescape(x.faq);
}
})
Be careful that the FAQ content is fully controlled by you and not submitted by your users without cleansing the content.

Setting the document title with Meteor

I'm just starting with Meteor. In an app which is to be localized, I want to set the document title.
I am following the advice given by Bernát
In my barebones version, I have just 2 documents:
head.html
<head>
<meta charset="utf-8">
<title>{{localizedTitle}}</title>
</head>
ui.js
UI.registerHelper("localizedTitle", function() {
var title = "Localized Title"
document.title = title;
});
When the app loads, the document title is "{{localizedTitle}}". If I call UI._globalHelpers.localizedTitle() from the console, the correct title is shown.
What do I have to do to get the localized title to show when the page is loaded?
EDIT: This works for me, but it seems to be a bit of a hack. The title template does nothing but get itself rendered, which actually adds nothing to the interface.
body.html
<body>
{{> title}}
</body>
<template name="title">
</template>
title.js
Template.title.onRendered(function () {
document.title = getLocalizedString()
function getLocalizedString() {
return "Title : in English"
}
})
Following Bernát's answer, your global helper should not be called in the head's <title> tag, but within the <template> tag of the template where you wish to have a given title. In Meteor, <head> does not count as a template, therefore you cannot use Spacebars notation in it: it will just be considered as simple text.
Also, keep in mind that your helper will not return (i.e. print) anything to the page. document.title = "something" directly assigns "something" to your ` tag. So no need to call your helper inside it!
So, say you want to have the "Localized Title" title for a page using the localized template :
<template name="localized">
<h1>This is the localized page</h1>
{{localizedTitle}}
</template>
Here, your trick should work.
I've found it convenient to set the title in onAfterAction in my iron-router routes:
onAfterAction: function(){
document.title = 'foo'; // ex: your site's name
var routeName = Router.current().route.getName();
if ( routeName ) document.title = document.title + ': ' + routeName;
}
I think a more elegant solution is to make the title reactive and set it via a Session variable (other reactive data sources are of course also OK). Like that:
Template.body.onRendered(function() {
this.autorun(function() {
document.title = Session.get('documentTitle');
});
});
Now every time you set the 'documentTitle' variable with
Session.set('documentTitle', 'Awesome title');
the page title will change. No need for hacks and you can do this anywhere in your client code.
Try this instead:
UI.registerHelper('title', function() {
return 'LocalizedTitle'
});
we can use title where ever you want
you can use like this {{title}}

Handlebars : register helper based on template with 'body content'

I'm trying to implement some kind of 'macro' mechanism in a nodejs application using Handlebars (similar to the #bodyContent system in velocity.)
In my main template, I want to be able to write something like this :
{{#foobar who = user }}
<p>My body content</p>
{{/foobar}}
In a "views/helpers/foobar.html", I would have a file with a template, and some way to reference the "body content"
<p>Hello {{ who }}<p>
{{ bodyContent }}
<p>Bye !</p>
Based on the convention that the templates in "views/helpers" corresponds to a helper called with a single hash parameter, I want to automatically register them ; so I have something like this :
var helpers = "./views/helpers/";
fs.readdirSync(helpers).forEach(function (file) {
var source = fs.readFileSync(helpers + file, "utf8"),
helperName = /(.+)\.html/.exec(file).pop();
var helperTemplate = Handlebars.compile(source);
// We assume all helpers in the folder
// would take a hash as their first param
// We'll provide them with all the required context
Handlebars.registerHelper(helperName, function (options) {
var hash = options.hash || {};
// I want to somehow 'pass' the body Content ;
// The closest I have is 'this', but the markup is
// encoded, so I get a string with '<p>My body content</p>'
hash.bodyContent = options.fn(this);
console.log("Body Content", hash.bodyContent);
// Render the source as an handlebar template
// in the context of a hash
return helperTemplate(hash);
});
});
This does not work, as the tags are escaped, and so bodyContent is a String containing the markup, instead of the markup.
Is there a way I can fix my helper registration, or a built in mechanism in Handlebars to deal with this ?
Thanks
You need to use the {{{triple stashes}}} to unescape the HTML injection. So your template should look like:
<p>Hello {{ who }}<p>
{{{ bodyContent }}}
<p>Bye !</p>
You can read more here

Resources