Faithfully insert a string in an area - javascript

I would like to dynamically print a string (which is NOT constant) in a certain area (eg, div result). Then I use the following code:
<!DOCTYPE html>
<html>
<body>
<div id="result"></div>
<script>
var elt = document.createElement("span");
elt.innerHTML = "=A2<C2";
document.querySelector("#result").appendChild(elt);
</script>
</body>
</html>
The problem is that if the string I want to print contains <, it interprets that and does not print < faithfully. For example, the above code prints =A2.
I see some threads proposing to replace < by < + space. But I don't like the space inserted. Additionally, I don't know if there are other special characters that will be interpreted.
So does anyone know any general solution to print a string faithfully?
PS: JSBin

You can substitute .textContent for .innerHTML
elt.textContent = "=A2<C2";

Definitely don't insert text with innerHTML; only insert HTML that way. Inserting text is a bit more verbose, but not too difficult:
elt.appendChild(document.createTextNode("=A2<C2"));

Related

How to render only parts of a string as HTML

I want to render a text as common HTML and parse occurrences of [code] tags that should be output unrendered - with the tags left untouched.
So input like this gets processed accordingly:
<p>render as HTML here</p>
[code]<p>keep tags visible here</p>[/code]
<p>more unescaped text</p>
I've regexed all code-tags but I have no idea how to properly set the text of the element afterwards. If I use jQuery's text() method nothing gets escaped, if I set it with the html() method everything gets rendered and I gained nothing. Can anybody give me a hint here?
Try replacing [code] with <xmp> and [/code] with </xmp> using regex or alike, and then use the jQuery html() function.
Note that <xmp> is technically deprecated in HTML5, but it still seems to work in most browsers. For more information see How to display raw html code in PRE or something like it but without escaping it.
You could replace the [code] and [/code] tags by <pre> and </pre> tags respectively, and then replace the < within the <pre> tags by & lt;
A programmatic solution based on Javascript is as follows
function myfunction(){
//the string 's' probably would be passed as a parameter
var s = "<p>render as HTML here</p>\
[code]<p>keep tags visible here</p>[/code]\
<p>more unescaped text</p>";
//keep everything before [code] as it is
var pre = s.substring(0, s.indexOf('[code]'));
//replace < within code-tags by <
pre += s.substring(s.indexOf('[code]'), s.indexOf('[/code]'))
.replace(new RegExp('<', 'g'),'<');
//concatenate the remaining text
pre += s.substring(s.indexOf('[/code]'), s.length);
pre = pre.replace('[code]', '<pre>');
pre = pre.replace('[/code]', '</pre>');
//pre can be set as some element's innerHTML
return pre;
}
I would NOT recommend the accepted answer by Andreas at all, because the <xmp> tag has been deprecated and browser support is totally unreliable.
It's much better to replace the [code] and [/code] tags by <pre> and </pre> tags respectively, as raghav710 suggested.
He's also right about replacing the < character with <, but that's actually not the only character you should replace. In fact, you should replace character that's a special character in HTML with corresponding HTML entities.
Here's how you replace a character with its corresponding HTML entity :
var chr = ['&#', chr.charCodeAt(), ';'].join('');
You can replace the [code]...[/code] with a placeholder element. And then $.parseHTML() the string with the placeholders. Then you can insert the code into the placeholder using .text(). The entire thing can then be inserted to the document (run below or in JSFiddle).
var str = "<div><b>parsed</b>[code]<b>not parsed</b>[/code]</div>";
var placeholder = "<div id='code-placeholder-1' style='background-color: gray'></div>";
var codepat = /\[code\](.*)\[\/code\]/;
var code = codepat.exec(str)[1];
var s = str.replace(codepat, placeholder);
s = $.parseHTML(s);
$(s).find("#code-placeholder-1").text(code);
$("#blah").html(s);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Text
<div id="blah">place holder</div>
Around
The code above will need some modifications if you have multiple [code] blocks, you will need to generate a unique placeholder id for each code block.
If you may be inserting untrusted structure code, would highly recommend using large random number for the placeholder id to prevent a malicious user from hijacking the placeholder id.

innerHTML to ascii

I am attempting to write my own piece of Javascript that converts html to ascii code (for learning purposes) so that the browser will render the code as you would see it in a text editor.
After looking around on Stack I have gotten as far as below. I am trying to turn an html element into a string; at this stage I am just trying to .replace() the angular brackets into ascii. If anyone could tell me where I am going wrong as far as having my test <body> tag showing up in the console that would be much appreciated.
<code class="lang-html">
<body></body>
</code>
(function() {
var html = $('.lang-html').innerHTML;
html.replace('<', '<');
html.replace('>', '>');
console.log(html);
});
Just to clarify, I am expecting that the console would spit out <body></body>.
Any help would be much appreciated.
A few things:
$('.lang-html').innerHTML
Assuming this is jQuery, this won't work. .innerHTML only works on raw DOM elements, like what's returned from document.getElementById(...). Instead, $('.lang-html') returns a jQuery collection, which has its own accessor methods. You should do:
$('.lang-html').html() // get the HTML as text from this element
Moving on, .replace() won't modify the original string. It returns a new copy. In the simplest case you can do:
var html = $('.lang-html')
.html()
.replace('<', '<')
.replace('>', '>');
But you still have to re-assign it to the HTML source. Again, jQuery provides a simple API for this.
$('.lang-html').html(html);
However, there's one more problem. .replace() only replaces the first match in a string. To replace all of them, you need to construct a regex and use the /g (global) flag. Here's the complete code:
var $element = $('.lang-html');
var html = $element.html()
.replace(/</g, '<')
.replace(/>/g, '>');
$element.html(html)
If you want get html code representation of an DOMElement in your browser then you won't need the replace to escape the html special chars. But you can use the browser to take care of all edge cases.
You could just use innerHTML/outerHTML and textContent.
This will e.g. will replace the content of the body with its html code representation.
var elm = document.getElementsByTagName('body')[0];
elm.textContent = elm.outerHTML;
Or if you just want to have the result as string but not displayed in the browsers then you could wrap that into a function:
function escapeHTML(html) {
var div = document.createElement('div');
div.textContent = html;
return div.innerHTML;
}
console.log( escapeHTML('<div>test</div>') );
You can also do a
$('.lang-html').prop("innerText")
which will hand you back the contents of that div, as real text.
No further translation should be needed.
Actually <body> tags will not be returned in the innerHTML of the posted code because the HTML is invalid. To explain:
To cater for changes to the DOM made in Javascript, browsers dynamically create innerHTML strings from the DOM by inspecting child elements of a specified node and generating HTML code from them.
Since <body> tags are only valid immediately following the head section, browsers silently respond to the <code> tag in your post by first creating a body element in which to place it. The <body> tags which follow are then ignored because they are invalid in this position. Hence there is no body element child of the code node, and no body tags in its innerHTML
Update (2): To pretty print the HTML without viewing page source you could try.
(function() {
var body = document.body;
var html = body.parentNode.outerHTML;
html = html.replace(/</g, '<');
html = html.replace(/>/g, '>');
html = html.replace(/\ /g, " ");
html = html.replace(/\n/g, '<br>\n');
// console.log(html);
body.innerHTML = html;
body.style.fontFamily = "monospace";
});

Outputting Escape Characters in JavaScript

I think it is a bit simple question but I couldn't find my answer neither on Stackoverflow nor Google. Here is my question. I want to output strings with escape characters. I have used the method document.getElementIdBy().
Here is my example
<!DOCTYPE html>
<html>
<head>
<title>JavaScript</title>
</head>
<body>
<p id="example1"></p><br>
<p id="example2"></p><br>
<p id="example3"></p><br>
<p id="example4"></p><br>
<script>
var x = "\"ABC\""
var y = "\'ABC\'"
var z = "ABC\nDEF"
var t = "ABC\bDEF"
document.getElementById("example1").innerHTML=x;
document.getElementById("example2").innerHTML=y;
document.getElementById("example3").innerHTML=z;
document.getElementById("example4").innerHTML=t;
</script>
</body>
</html>
The first two works fine. The third one doesn't create a new line and the fourth one doesn't crate a backspace. I assume that the variable z is like this
ABC
DEF
If I write this into a p element, it must show up like this: ABC DEF. Therefore I can understand why it doesn't appear as I expected (If I style the p element with white-space:pre it works as I expected)
However I wonder why \b escape character doesn't work as expected. Actually I was expecting the output to be: ABDEF (without C). There may be some logic similar to the upper one but I cannot find. Can someone explain why it doesn't work?
I think these chars are just stripped from HTML, you could achieve what you want by replacing \n with <br/>
e.g.
document.getElementById("example3").innerHTML=z.replace("\n","<br/>");
The third one doesn't create a new line
New lines in text are ignored in HTML tags. They are rendered as a space. Use <pre> tags to keep formatting:
<pre id="example3"></pre>
Or add <p> tags instead of new lines:
var z = "<p>ABC</p><p>DEF</p>"
Or <br>
var z = "ABC<br>DEF"
the fourth one doesn't crate a backspace
Do not pretty sure that HTML/JS supports \b.
new line (\n) doesn't generate new line in html.
so if you write:
<p>first line
second line</p>
you will get:first line second line.
so to write \n to html you must convert it to <br>.
document.getElementById("example3").innerHTML=z.replace(/\n/g,'<br>');
this regular expression replaces all \n with <br>.
and \b is just character with code 8. its special behavior occurs only when you send it to an input or text box.

Why JavaScript converts my < into >

JavaScript converts my < into >. I want to alert it but my message is with encoded marks like ##&*()}{>?>? - how to display it normally but prevent from executing as HTML code?
<span id="ID" onClick="alertIt(this.id);">
<p>Some string with special chars: ~!##&*()}{>?>?>|{">##$#^#$</p>
<p>Why when clicked it gives something like this:</p>
<p>'<br>
Some string with special chars: ~!##&*()}{>?>?>|... and so on
<br>'</p>
</span>
<script type="text/javascript">
function alertIt(ID)
{
var ID = ID;
var content = document.getElementById(ID).innerHTML;
alert(content);
}
</script>
Use innerText instead of innerHTML. http://jsfiddle.net/WVf95/
Your problem is that you use the wrong approach to get the text to display with alert().
Some characters are illegal in HTML text (they are used for HTML tags and entities). innerHTML will make sure that text is properly escaped (i.e. you can see tags and escaped text).
If you want to see tag and text in alert(), there is no solution.
If you want only the text, then you will have to extract it yourself. There is no built-in support for that. It's also not really trivial to implement. I suggest to include jQuery in your page; then you can get the text with:
function alertIt(ID) {
alert($(ID).text());
}
Using textContent instaed of innerHTML or innerText is a solution.

Javascript Removing Whitespace When It Shouldn't?

I have a HTML file that has code similar to the following.
<table>
<tr>
<td id="MyCell">Hello World</td>
</tr>
</table>
I am using javascript like the following to get the value
document.getElementById(cell2.Element.id).innerText
This returns the text "Hello World" with only 1 space between hello and world. I MUST keep the same number of spaces, is there any way for that to be done?
I've tried using innerHTML, outerHTML and similar items, but I'm having no luck.
HTML is white space insensititive which means your DOM is too. Would wrapping your "Hello World" in pre block work at all?
In HTML,any spaces >1 are ignored, both in displaying text and in retrieving it via the DOM. The only guaranteed way to maintain spaces it to use a non-breaking space .
Just a tip, innerText only works in Internet Explorer, while innerHTML works in every browser... so, use innerHTML instead of innerText
The pre tag or white-space: pre in your CSS will treat all spaces as meaningful. This will also, however, turn newlines into line breaks, so be careful.
Just an opinion here and not canonical advice, but you're headed for a world or hurt if you're trying to extract exact text values from the DOM using the inner/outer HTML/TEXT properties via Javascript. Different browsers are going to return slightly different values, based on how the browser "sees" the internal document.
If you can, I'd change the HTML you're rendering to include a hidden input, something like
<table>
<tr>
<td id="MyCell">Hello World<input id="MyCell_VALUE" type="hidden" value="Hello World" /></td>
</tr>
</table>
And then grab your value in javascript something like
document.getElementById(cell2.Element.id+'_VALUE').value
The input tags were designed to hold values, and you'll be less likely to run into fidelity issues.
Also, it sounds like you're using a .NET control of some kind. It might be worth looking through the documentation (ha) or asking a slightly different question to see if the control offers an official client-side API of some kind.
Just checked it and it looks like wrapping with the pre tag should do it.
Edit: I am wrong, ignore me.
You can get a text node's nodeValue, which should correctly represent its whitespace.
Here is a function to recursively get the text within a given element (and it's library-safe, won't fail if you use something that modifies Array.prototype or whatever):
var textValue = function(element) {
if(!element.hasOwnProperty('childNodes')) {
return '';
}
var childNodes = element.childNodes, text = '', childNode;
for(var i in childNodes) {
if(childNodes.hasOwnProperty(i)) {
childNode = childNodes[i];
if(childNode.nodeType == 3) {
text += childNode.nodeValue;
} else {
text += textValue(childNode);
}
}
}
return text;
};
This is a bit hacky, but it works on my IE.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title></title>
</head>
<body>
<div id="a">a b</div>
<script>
var a = document.getElementById("a");
a.style.whiteSpace = "pre"
window.onload = function() {
alert(a.firstChild.nodeValue.length) // should show 4
}
</script>
</body>
</html>
Some notes:
You must have a doctype.
You cannot query the DOM element before window.onload has fired
You should use element.nodeValue instead of innerHTML et al to avoid bugs when the text contains things like < > & "
You cannot reset whiteSpace once IE finishes rendering the page due to what I assume is an ugly bug
If someone could format my last post correctly it would look more readable. Sorry, I messed that one up. Basically the trick is create create a throwaway pre element, then append a copy of your node to that. Then you can get innerText or textContent depending on the browser.
All browsers except IE basically do the obvious thing correctly. IE requires this hack since it only preserves white-space in pre elements, and only when you access innerText.
This following trick preserves white-space in innerText in IE
var cloned = element.cloneNode(true);
var pre = document.createElement("pre");
pre.appendChild(cloned);
var textContent = pre.textContent
? pre.textContent
: pre.innerText;
delete pre;
delete cloned;

Categories

Resources