Style text with innerText while still escaping HTML - javascript

I want to dynamically set the text of a p element with styling, but I do not know how to do this.
Here is my HTML element: <p id="delete-speaker-info-message"> </p>
Here is my current code to set the text:
document.getElementById("delete-speaker-info-message").innerHTML = `Are you sure you want to delete <b>${speakerName}</b> from <b>${eventName}</b>? This cannot be undone.`
Although the code above works, the speakerName, and eventName values are user inputted and need to be escaped. I know innerText can do this but it also escapes the bold tags. I am sure there is a way to do this but I just could not find it online. Thanks for the help!

Your best bet is to use a templating library. If you try to roll your own, you're probably going to mess it up and end up with XSS vulnerabilities. There's always a hacker out there who will think of something you haven't. Using a library also lets you do nice things like have an html template and pass in variables to be safely interpolated into it.
It sounds like you're not using any of the larger frameworks like React or Angular, so I'd say Lodash's template function is your best bet. Here's an example from their docs:
// Use the HTML "escape" delimiter to escape data property values.
var compiled = _.template('<b><%- value %></b>');
compiled({ 'value': '<script>' });
// => '<b><script></b>'

You should use something like my special function:
//<![CDATA[
/* external.js */
var doc, bod, I, special, unspecial; // for use on other loads
addEventListener('load', function(){
doc = document; bod = doc.body;
I = function(id){
return doc.getElementById(id);
}
special = function(str){
return str.replace(/&/g, '&').replace(/'/g, '&apos;').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
}
unspecial = function(str){
return str.replace(/&/g, '&').replace(/&apos;/g, "'").replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
}
var speakerName = '<i>Cool Joe</i>', eventName = '<div>Keeping it Real</div>';
var deleteSpeakerInfoMsg = I('delete-speaker-info-message');
deleteSpeakerInfoMsg.innerHTML = 'Are you sure you want to delete <b>'+special(speakerName)+'</b> from <b>'+special(eventName)+'</b>? This cannot be undone.';
console.log(deleteSpeakerInfoMsg.innerHTML);
}); // end load
//]]>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1' />
<title>Test Template</title>
<link type='text/css' rel='stylesheet' href='external.css' />
<script type='text/javascript' src='external.js'></script>
</head>
<body>
<div id='delete-speaker-info-message'></div>
</body>
</html>

Related

Having trouble parsing json file in my javascript..but I am getting "responseObject.weather[i].weatherresponseObject.weather[i].description"

Trying to parse data from a php file which is in json format to an html file using javascript to do so
I am getting responseObject.weather[i].weatherresponseObject.weather[i].description but I have a hunch its how the php file is formatted and perhaps the object I am using is not correct
I am trying to just pull the temperature and the description onto my html page.
Can someone give me a idea of where it is going wrong?
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="style.css" rel="stylesheet" type="text/css">
<script src="run.js"></script>
<title>Ajax Demo</title>
</head>
<body>
<h1 class="title">Todays Weather Forecast</h1>
<p class="sub">Click the button the check the local weather.</p>
<button class="demo-centered" type="button" onclick="loadPhp()">Check Weather</button><br><br>
<div id="content"></p>
</body>
</html>
function loadPhp() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.status === 200) {
responseObject = JSON.parse(xhr.responseText);
var newContent = '';
for (var i = 0; i < responseObject.weather.length; i++){
newContent += 'responseObject.weather[i].weather';
newContent += 'responseObject.weather[i].description';
}
document.getElementById('content').innerHTML = newContent;
}
};
xhr.open('GET', 'demo.php', true);
xhr.send(null);
}
{"coord":{"lon":-116.8,"lat":33.03},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":293.73,"feels_like":289.89,"temp_min":289.26,"temp_max":295.93,"pressure":1016,"humidity":52},"visibility":16093,"wind":{"speed":5.7,"deg":260},"clouds":{"all":40},"dt":1589408840,"sys":{"type":1,"id":5686,"country":"US","sunrise":1589374130,"sunset":1589423903},"timezone":-25200,"id":5391832,"name":"San Diego County","cod":200}
You don't want the quotes in this code:
newContent += 'responseObject.weather[i].weather';
newContent += 'responseObject.weather[i].description';
With the quotes, you're making those literal strings. Instead:
newContent += responseObject.weather[i].weather;
newContent += responseObject.weather[i].description;
...though you probably want some markup around those, as they'll just be stuck together.
Three other things worth noting:
You never do anything with newContent. You need to do something to put it on the page (append elements with it, append it to existing elements, etc.).
Your code is falling prey to what I call The Horror of Implicit Globals — you need to declare responseObject.
It's fine to use XMLHttpRequest, but you might also look at the newer fetch instead. If you do, though, beware the fetch footgun.

How to replace text in a html document using Javascript

I have written this code which I thought was correct, but although it runs without error, nothing is replaced.
Also I am not sure what event I should use to execute the code.
The test a simple template for a landing page. The tokens passed in on the url will be used to replace tags or tokens in the template.
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
// gets passed variables frm the url
function getQueryVar(str) {
return 'Newtext'; // JUST SCAFFOLD FOR TESTING
}
function searchReplace() {
/**/
var t = 0;
var tags = Array('keyword', 'locale', 'advert_ID');
if (document.readyState === 'complete') {
var str = document.body.innerText;
for (t = 0; t < tags.length; t++) {
//replace in str every instance of the tag with the correct value
if (tags[t].length > 0) {
var sToken = '{ltoken=' + tags[t] + '}';
var sReplace = getQueryVar(tags[t]);
str.replace(sToken, sReplace);
} else {
var sToken = '{ltoken=' + tags[t] + '}'
var sReplace = '';
str.replace(sToken, sReplace);
//str.replace(/sToken/g,sReplace); //all instances
}
}
document.body.innerText = str;
}
}
</script>
</head>
<body>
<H1> THE HEADING ONE {ltoken=keyword}</H1>
<H2> THE HEADING TWO</H2>
<H3> THE HEADING THREE</H3>
<P>I AM A PARAGRAPH {ltoken=keyword}</P>
<div>TODO write content</div>
<input type="button" onclick="searchReplace('keyword')">
</body>
</html>
So when the documment has finished loading I want to execute this code and it will replace {ltoken=keyword} withe value for keyword returned by getQueryVar.
Currently it replaces nothing, but raises no errors
Your problem is the fact you don't reassign the replacement of the string back to it's parent.
str.replace(sToken,sReplace);
should be
str = str.replace(sToken,sReplace);
The .replace method returns the modified string, it does not perform action on the variable itself.
Use innerHTML instead innerText and instead your for-loop try
tags.forEach(t=> str=str.replace(new RegExp('{ltoken='+ t+'}','g'), getQueryVar(t)))
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
// gets passed variables frm the url
function getQueryVar(str)
{
return'Newtext';// JUST SCAFFOLD FOR TESTING
}
function searchReplace() {
/**/
var t=0;
var tags =Array('keyword','locale','advert_ID');
if (document.readyState==='complete'){
var str = document.body.innerHTML;
tags.forEach(t=> str=str.replace(new RegExp('{ltoken='+ t+'}','g'), getQueryVar(t)));
//tags.forEach(t=> str=str.replace(new RegExp('{ltoken='+ tags[t]+'}', 'g'), getQueryVar(tags[t])));
document.body.innerHTML=str;
}
}
</script>
</head>
<body >
<H1> THE HEADING ONE {ltoken=keyword}</H1>
<H2> THE HEADING TWO</H2>
<H3> THE HEADING THREE</H3>
<P>I AM A PARAGRAPH {ltoken=keyword}</P>
<div>TODO write content</div>
<input type ="button" onclick="searchReplace('keyword')" value="Clicke ME">
</body>
</html>

jQuery .html() not setting content correctly?

Here is the example I prepared to tell about the problem easier.
http://codepen.io/anon/pen/EVpYXm
As you can see the initial <html> is set to display a text:
"This is the old html!"
It sets the whole content to the data in the variable myHtml. however here is what I notice:
the style is not carried from the <body> element. Moreover, the <body> element is somehow not created at all!
Here is the sring myHtml, tidied up to display as an html:
<html>
<head>
<title>Title Here</title>
<link href='style.css' rel='stylesheet' type='text/css'/>
</head>
<body style='background-color: red'>
<div>Div!</div>
</body>
</html>
I've realized that when link element is removed, everything works fine. Try it, see it yourself.
Stuck with this issue for the last few hours. Looking for a result.
Here is the full code:
page html:
<html>
This is the old html!
</html>
javascript:
$(function(){
var myHtml = "<html><head><title>Title Here</title><link href='style.css' rel='stylesheet' type='text/css'/></head><body style='background-color: red'><div>Div!</div></body></html>"
$("html").html(myHtml);
})
The main purpose of this question is to understand the reason of this behavior as well as finding the best solution.
The issue is that, when you use jQuery's html(val), it does something like this:
html: function(value) {
/* ... */
// See if we can take a shortcut and just use innerHTML
if ( typeof value === "string" && !rnoInnerhtml.test( value ) && /* ... */) {
/* ... */ elem.innerHTML = value; /* ... */
}
/* ... */
}
That is, it checks the string with the regex rnoInnerhtml, which is
rnoInnerhtml = /<(?:script|style|link)/i
Therefore, presumably to avoid inserting stylesheets, jQuery avoids innerHTML and does complicated things with domManip.
I recommend using native innerHTML:
$("html").prop('innerHTML', myHtml);
var myHtml = "<head><title>Title Here</title><link href='style.css' rel='stylesheet' type='text/css'/></head><body style='background-color: red'><div>Div!</div></body>"
$("html").prop('innerHTML', myHtml);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This is the old html!
Or with vanilla-js:
document.documentElement.innerHTML = myHtml;
var myHtml = "<head><title>Title Here</title><link href='style.css' rel='stylesheet' type='text/css'/></head><body style='background-color: red'><div>Div!</div></body>"
document.documentElement.innerHTML = myHtml;
This is the old html!
The problem is that you're appending an html element inside the root html element, which is undefined behavior and cannot be rendered reliably by the browser. Strip the opening and closing <html> and </html> tags from your myHtml string and it works!
Working demo
$(function() {
var myHtml = "<head><title>Title Here</title></head><body style='background-color: red; '><div>Div!</div></body>"
$('html').html(myHtml);
})
Alternatively, you could keep the tags and write directly to the document object instead, which opens a new stream and overwrites the previous document.
// ...
document.write(myHtml);

Regular Expression to select part in HTML

I have requirement to extract meta property from scrolled HTML source code. After scrolling HTML code contains as follows
Example:
<meta property="og:site_name" content="asasasas">
<meta property="og:title" content="asajhskajhsaksp;" />
<meta property="og:image" content="images.cxs.com/2014/09/modit1.gif?w=209" />
Here I want to get the content of only where meta property="og:image" ie result should be only
images.cxs.com/2014/09/modit1.gif?w=209
was it so difficult to use jquery
$('meta[property="og:image"]').attr('content')
As #Biffen said, don't use regex to parse html.
If you have the said string in a variable you can use querySelector() like
var html = '<meta property="og:site_name" content="asasasas" /><meta property="og:title" content="asajhskajhsaksp;" /><meta property="og:image" content="images.cxs.com/2014/09/modit1.gif?w=209" />';
var el = document.createElement('div');
el.innerHTML = html;
var meta = el.querySelector('meta[property="og:image"]');
console.log(meta.content);
document.getElementById('result').innerHTML = meta.content;
<div id="result"></div>
If it is part of the current page then
var meta = document.querySelector('meta[property="og:image"]');
console.log(meta.content);
document.getElementById('result').innerHTML = meta.content;
<meta property="og:site_name" content="asasasas"/>
<meta property="og:title" content="asajhskajhsaksp;" />
<meta property="og:image" content="images.cxs.com/2014/09/modit1.gif?w=209" />
<div id="result"></div>
You can use the approach suggested by Arun, however there may be user agents that don't support the Selectors API or don't support the required features (e.g. IE8). In that case, you can use getElementsByTagName and a plain old for loop.
var node, nodes = document.getElementsByTagName('meta');
for (var i=0, iLen=nodes.length; i<iLen; i++) {
node = nodes[i];
if (node.getAttribute('property') == 'og:image') {
// do something with content
console.log(node.content);
}
}
the above will work in any browser in use and doesn't require any external library.

Javascript Special Character removal not working

i have written a jsp code with values coming from other jsp and i need to remove the special characters in the string.But iam not able to remove special characters. Please help
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
<script>
function change(chars){
var dchars=document.getElementById("chars").value;
dchars = dchars.replaceAll("!##$%^&*()+=[]\\\';,/{}|\":<>?", '');
document.getElementById("chars").innerHTML=dchars;
}
</script>
</head>
<%
String res=request.getParameter("tes");
%>
<body onload="change(chars)" ><script>
change(res)
</script>
<div id="chars"> <%=res%></div>
</body>
</html>
There is no "value" for div elements. You need to use innerHtml insted:
document.getElementById('chars').innerHTML = dchars;
try this....
document.getElementById('chars').innerHTML = dchars; //div has no value..
Assuming by special characters, you mean anything that's not letter, here is a solution:
alert(dchars.replace(/[^a-zA-Z ]/g, ""));
OR
alert(dchars.replace(/[^a-z0-9\s]/gi, '')); //will filter the string down to just alphanumeric values
The problem with using innerHTML is that certain characters are automatically converted to HTML entities such as & which is converted to &
function cleanCharsText(){
var el = document.getElementById("chars");
var txt = el.innerText || el.textContent;
el.innerHTML = txt.replace( /[!##$%^&*()+=\\[\]\';,/{}\|\":<>\?]/gi, '');
}
However if you have the following <span> text </span> inside your chars element the html span tags will be removed when you run the above function as we are only extracting the text.

Categories