Handlebars helper - returning HTML not text - javascript

I wrote a simple helper for my template. Here's the code:
Handlebars.registerHelper('splitQuote', function (string) {
if (string.indexOf('|') !== -1) {
return string.replace('|', '<span>') + '</span>';
}
return string;
});
So I pass a string, and split the string by '|' character. I also want to put second part into span tags.
Problem is, the result that is being returned is pure text, so I get span tags like a text, not HTML.
Does anyone know what's the catch?
Tnx

You don´t need to use SafeString. Instead, use the "triple moustaches" from handlebar:
From Handlebars web site, HTML Escaping section:
Handlebars HTML-escapes values returned by a {{expression}}. If you don't want Handlebars to escape a value, use the "triple-stash", {{{.
So, a simple triple quote in your html will avoid escaping:
{{{splitQuote}}}

You have to mark the string as html in your helper if you want to Handlebars not to escape it. Use Handlebars.safeString to do this. The below should suit your needs
Handlebars.registerHelper('splitQuote', function(string) {
if (string.indexOf('|') !== -1) {
return new Handlebars.SafeString(string.replace('|', '<span>') + '</span>');
}
return string;
});
As mentioned in comments you should probably escape the passed string using Handlebars.Utils.escapeExpression(string) to encode the string before you do your custom formatting. I'd recommend writing like this:
Handlebars.registerHelper('splitQuote', function(string) {
string = Handlebars.Utils.escapeExpression(string);
if (string.indexOf('|') !== -1) {
string = string.replace('|', '<span>') + '</span>';
}
return new Handlebars.SafeString(string); // mark as already escaped
});

Related

How to escape html string having multiple double quotes

I have received the following string from my ajax request:
As per json doc, "quotes must be escaped "
This is stored in data.description and is embedded in the template as:
''
data-title's value is used as a caption for lightbox plugin pop up. I tried the following function:
var HtmlEncode = function(s) {
var el = document.createElement("div");
el.innerText = el.textContent = s;
s = el.innerHTML;
return s;
}
as:
''
Now since the data.description contains multiple quotes javascript assumes them as multiple argument and throws error. I searched many other Stackoverflow posts which suggest to append the data in a div and retrieve its inner HTML but that is possible in my case.
Thanks
Change only the quotes that are the same as those will be surrounding the data-title. Like this:
var description = data.description.replace(/"/g, "'");
var template = '';
You can replace the double quotes in your string with single quotes or any other symbol in order for it to work inside double quotes.
you can do this with String.replace(/["]+/g,"'") this will replace the double quotes in the string with a single quote, the g in the reg-ex tells it to use all the string.
you can also fake it by using 2 single quotes like this String.replace(/["]+/g,"''"), and it will fake double quotes for you.
var HtmlEncode = function(s) {
return s.replace(/["]+/g,"''");
}
Solution 1
Escape it with replace and a regexp:
var HtmlEncode = function(s) {
return s.replace(/"/g, '\\"').replace(/'/g, "\\'");
}
''
Solution 2
Let jQuery doing this for you (only if you are using it).
var tpl = $('');
tpl.data('title', data.description);
Try to replace the quotes with HTML entity equivalents after which you can then safely use it on attributes.
var desc = data.description.replace(/'/g, "'").replace(/"/g, """);
''
Here's a Fiddle to demonstrate the solution.

Angular filter to replace all underscores to spaces

I need a filter to replace all the underscores to spaces in a string
string.replace not only accepts string as first argument but also it accepts regex as first argument. So put _ within regex delimiters / and aslo add g modifier along with that. g called global modifier which will do the replacement globally.
App.filter('underscoreless', function () {
return function (input) {
return input.replace(/_/g, ' ');
};
});
Here's a generic replace filter alternative
App.filter('strReplace', function () {
return function (input, from, to) {
input = input || '';
from = from || '';
to = to || '';
return input.replace(new RegExp(from, 'g'), to);
};
});
Use it as follows in your HTML:
{{ addText | strReplace:'_':' ' }}
Minor note: Any HTML tags in the to parameter will cause the expression to fail due to Angular content security rules.
In some case, you can use split() function.
.replace function is not compliant with regexp syntax (i.e. .replace(/,/g,'\n') syntax)
Full syntax:
{{myVar.toString().split(',').join('\n')}}
.toString() function is in case myVar is not typed as String in typescript.
There is a easyer method:
You could replace it inline without a defined filter. This is the way.
This example its for replace just in the view.
{{ value.replace(/_/g, ' ') }}
I hope its could help in a simple change, if you want to change in more places, use the filter.
This simple function can do it:
public getCleanedString(cadena) {
cadena = cadena.replace(/_/g, ' ');
return cadena;
}
this is i used in angularjs 1.4.7
<li ng-show="filter.degree.length">
<label>Search by Degree :- </label> {{
filter.degree.toString().split('|').join(', ')
}}
</li>

Can you strip out characters using a Handlebars helper?

I am using Handlebars to compile a template that returns JSON data. My issue is that I would like to create a tel link to the phone numbers which are displayed, but the format they are being returned in is: (XXX) XXX-XXXX
I know you can register a helper to take a string of numbers and then format them, but is there any way to do the reverse(strip out any non-numeric characters/spaces)?
This is the helper which does the inverse of what I am trying to do:
Handlebars.registerHelper("formatPhoneNumber", function(phoneNumber) {
phoneNumber = phoneNumber.toString();
return "(" + phoneNumber.substr(0,3) + ") " + phoneNumber.substr(3,3) + "-" + phoneNumber.substr(6,4);
});
Thanks!
Sure, you can just use a regular expression to strip out anything that's not a digit:
Handlebars.registerHelper("unformatPhoneNumber", function(phoneNumber) {
return phoneNumber.replace(/\D/g,'');
});
Nevermind, figured it out based on a non-handlebars answer.
Handlebars.registerHelper("formatPhoneNumber", function(phoneNumber) {
return phoneNumber.replace(/\D/g,'');
});

How to replace specific parts in string with javascript with values from object

I want to make custom replacer method for my HTML output. But I can't figure it out. I guess it should be done with String.match and replace somehow.
I have some "error codes" in my string that always start with _err_ and I have a JS object with values.
What I want to achieve:
Find all string parts (error codes) that starts with _err_
Get correct key for my object - error code without _err_
Find value from Lang object
Replace error code with correct Lang value.
Some error codes may appear multiple times.
var content = "Looks like you have _err_no_email or _err_no_code provided";
var Lang = {
'no_email' : "No email",
'no_code' : "No code"
};
I can do it other way around. So I cycle the Lang object and replace those in string.
It would be something like this if using underscore:
function replaceMe() {
_.each(Lang, function(value, key) {
content = content.replace(new RegExp('_err_' + key,'g'), value);
});
console.log(content);
};
But if it can be done faster with my first idea then I want to know how.
A simple regex should do the trick:
var content = content.replace(/\b_err_(.+?)\b/g, function(match, errorName) {
return Lang[errorName] || match;
});
This assumes that you do not want strings like "blah_err_blah" to be replaced, and defaults to not replacing the text if the error cannot be found in your Lang object.
var replace = function(str, object, regexp) { //if property not found string is not replaced
return String(str).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name) {
return (object[name] != null) ? object[name] : match;
});
}
This is a format function I've used in several projects thats quite efficient. Matches {prop} by default to {prop:'val'} but you can pass a regex for example maybe in your case /_err_+\S/g so it matches other tokens in your string.
So you can do:
var content ="Looks like you have {no_email} or {no_code} provided";
var Lang = {
'no_email' : "No email",
'no_code' : "No code"
}
var formatted = replace(content, lang);
Or for your original string stealing the other answers regex:
var formatted = replace(content, lang, /_err_([^\s]+)/g)
You can use a callback function, that look if a key matching the error code exists in your Lang object, and if so returns the value of that (and otherwise just the key itself, thereby doing no replacement, like so:
content.replace(/_err_([a-z_]+)/gi, function(fullmatch, key) {
return Lang[key] ? Lang[key] : fullmatch;
});
The first parameter passed to the function will be the full match, and the second parameter key will just be that part grouped by the bracktes.
And then, if Lang contains a (non-falsy) value for key, that’ll be returned, otherwise just the fullmatch value, so that that part of the string gets “replaced” with itself.
See it in action here: http://jsfiddle.net/VZVLt/1/
One more variation with split
content = content
.split('_err_')
.map(function(str, index){
if (index === 0)
return str;
var whitespace = str.indexOf(' '),
key = str.substring(0, whitespace)
return Lang[key] + str.substring(whitespace);
})
.join('')
;

How to tell if a string contains HTML entity (like &)?

I'm trying to write a function that checks a parameter against an array of special HTML entities (like the user entered '&amp' instead of '&'), and then add a span around those entered entities.
How would I search through the string parameter to find this? Would it be a regex?
This is my code thus far:
function ampersandKiller(input) {
var specialCharacters = ['&', ' ']
if($(specialCharacters).contains('&')) {
alert('hey')
} else {
alert('nay')
}
}
Obviously this doesn't work. Does anyone have any ideas?
So if a string like My name is & was passed, it would render My name is <span>&</span>. If a special character was listed twice -- like 'I really like &&& it would just render the span around each element. The user must also be able to use the plain &.
function htmlEntityChecker(input) {
var characterArray = ['&', ' '];
$.each(characterArray, function(idx, ent) {
if (input.indexOf(ent) != -1) {
var re = new RegExp(ent, "g");
input = input.replace(re, '<span>' + ent + '</span>');
}
});
return input;
}
FIDDLE
You could use this regular expression to find and wrap the entities:
input.replace(/&| /g, '<span>$&</span>')
For any kind of entity, you could use this too:
input.replace(/&(?:[a-z]+|#\d+);/g, '<span>$&</span>');
It matches the "word" entities as well as numeric entities. For example:
'test & & <'.replace(/&(?:[a-z]+|#x?\d+);/gi, '<span>$&</span>');
Output:
test & <span>&</span> <span><</span>
Another option would be to make the browser do a decode for you and check if the length is any different... check this question to see how to unescape the entities. You can then compare the length of the original string with the length of the decoded. Example below:
function htmlDecode(input){
var e = document.createElement('div');
e.innerHTML = input;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
function hasEntities(input) {
if (input.length != htmlDecode(input).length) {
return true;
}
return false;
}
alert(hasEntities('a'))
alert(hasEntities('&'))
The above will show two alerts. First false and then true.

Categories