Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Escape Mustache variable containing apostrophe for JavaScript

I have a variable ({{title}}) which contains an apostrophe. Mustache escapes this as '.

However, the following template results in a JavaScript error (Expected token ')'):

<a href="javascript:confirm('{{title}}?');">{{title}}</a>

After Mustache rendering, the syntax error is clear ('Joe's Lame?'):

<a href="javascript:confirm('Joe's Lame?');">Joe's Lame</a>

I am still learning Mustache and while this example is contrived, what is the proper way to escape variables in these situations.

The fiddle for reference.

like image 424
Jason McCreary Avatar asked May 14 '14 18:05

Jason McCreary


2 Answers

So if it doesn't have to be Mustache, you can use a superset of Mustache called Handlebars.

First register a Handlebars helper:

Handlebars.registerHelper('escapeJs', function(str) {
    return str.replace(/[\'\"\\\/]/gm, function (c) {
        return '\\' + c;
    });
});

And you call your helper like this {{escapeJs title}}:

var view = {
    title: "Joe's Lame\"\\/€"
};

var template = Handlebars.compile(
    "<a href=\"javascript:confirm('{{escapeJs title}}');\">{{title}}</a>");
var output = template(view);

View it live in this fiddle.

Mustache is really cool and it's available in almost any programming language. Handlebars is awesome and is used e.g. in Backbone Thorax and assemble, a powerful static web-site generator.

Edit: Alternative Solution

When using ECMAScript 5 (and with shim/shiv/polyfills that should be working with IE8 as well), one could prepare the view-object for Mustache in the following way. I admit, that this is not a very handy solution, but when producing JavaScript output is rare, it might be acceptable IMO.

function escapeJs (str) {
    return str.replace(/[\'\"\\\/]/gm, function (c) {
        return '\\' + c;
    });
}

var view = {
    title: "Joe's Lame"
};

Object.defineProperty(view, 'titleJsEnc', {
    enumerable: false,
    get: function () { return escapeJs(this.title); }
});

var output = Mustache.render(
    "<a href=\"javascript:confirm('{{titleJsEnc}}');\">{{title}}</a>", view);

Defining a new property (via Object.defineProperty) does the trick. One could write a generic object decorator which defines a getter for each real property returning the escaped string value.

Here is the fiddle

Edit: Alternative: Wait for a new version of Mustache

Once this pull-request is merged and a new version of Mustache is published, this problem should be solved in a "Mustache native way".

like image 140
hgoebl Avatar answered Nov 13 '22 07:11

hgoebl


P/S: I know this is an old post, just in case someone find it useful. Like myself, I found your post too before I realized about the triple brackets solution.

In Mustache, just use the triple brackets, no need to be so headache:

{{{title}}}

But for your case, I don't think by simply escaping the single quote is enough. You should also reverse your single and double quotes like this:

<a href='javascript:confirm("{{{title}}}?");'>{{{title}}}</a>
like image 45
Antonio Ooi Avatar answered Nov 13 '22 08:11

Antonio Ooi