Unescaping ampersand characters in javascript - javascript

I'm having trouble properly displaying values that contain escaped characters (i.e. apostrophes are stored as \' and not ' and brackets are > and < rather than > and <).
Items stored in my database have the characters (' < >) escaped to (\' < >), respectively. When I try to dynamically add them to the page with JavaScript, they print out in the escaped form in Firefox, rather than returning to their normal values like in IE (< is being printed to the HTML rather just <).
<html>
<head>
<script type="text/javascript">
$(document).ready(function() {
var str = ">";
$(document.body).html(str);
});
</script>
</head>
<body>
</body>
</html>
I know that if I simply do a replace, I can print correctly, but by doing so, I'm allowing the injection of HTML code, which is why I escaped the string in the first place.
ADDED:
Firstly, I apologize about the mistakes in my initial post. After closer examination, in the instances where I am using $().html(), the strings are printing correctly. The times where they aren't printing correctly are when I am using code like below.
var str = ">";
$('#inputField').val(str);
In this instance, the text ">" is shown, rather than ">". Is there something I can do to fix this?

You need to decode them like this:
$('#myText').val($("<div/>").html(str).text());
Demo: http://jsfiddle.net/QUbmK/
You can move the decode part to function too and call that instead:
function jDecode(str) {
return $("<div/>").html(str).text();
}
$('#myText').val(jDecode(str));

First off, you can't run the code you have in your example. document.body is not ready for manipulation in the HEAD tag. You have to run that after the document has loaded. If I put your code in a safe place to run, it works fine as you can see here.
So ... there must be more to your situation than the simple example you show here. You can see your simple example works fine here when the code is put in the right place:
http://jsfiddle.net/jfriend00/RDSNz/

That doesn't happen, at least not with jQuery. If you do, literally: $(document.body).html('<div>'), you will get <div> printed to the screen, not a div tag. If you're doing something not listed in your question:
either use .text() instead of .html() or replace all & with &:
$(document.body).text(str);
$(document.body).html(str.replace(/&/g, '&'))

Related

Remove script elements from html string converting query string to symbol

I am using this solution here to remove script elements from ajax responses. However, when my response looks like this :
'console.log("test");https://x.ya.com/home?abc=1&currency=EUR'
It converts the &curren to ¤ symbol.
The result looks like this:
'https://x.ya.com/home?abc=1¤cy=EUR'
How do I avoid this?
Try using the escaped ampersand & to represent the character & in the HTML where this problem occurs, like so;
HTML
Example Link
Produces
Example Link
I used the approach as mentioned in the answer here. This removes all the script elements from the text without treating it as html (without creating a div and appending the text to innerHTML of the div), which solves the case.
No html = no html symbol decode.
Works for me!

Javascript HTML escaping but preserving linebreaks

I have written a small jQuery script to help me build a styleguide. The script is used to copy and escape a piece of HTML and print it as documentation. My problem, however, is preversing linebreaks in the html. I would love for my escaped HTML to be formatted just like I have typed it. How is that possible?
$('.documentation-element').each(function() {
var HTML = $(this).html();
$(this).next().find('code').text(HTML).html();
});
See full example here:
http://jsfiddle.net/tolborg/nr7fs/
Change the text() method to html():
$(this).next().find('code').html(HTML);
JSFiddle
You're using a <code> tag, but that doesn't preserve line breaks. You need a <pre> tag for that. So wrap your <code> tag inside a <pre> tag and your code should work as is - except you don't need the extra .html() at the end (it doesn't hurt anything, it just doesn't do anything):
$('.documentation-element').each(function() {
var HTML = $(this).html();
$(this).next().find('code').text(HTML);
});
Here's an updated fiddle.
You may also want to tweak the leading whitespace on each line, but what you want there will depend on the output you want.
For example, here's a version that strips leading whitespace and also removes the extra newlines at the beginning and end:
$('.documentation-element').each(function() {
var HTML = $(this).html().trim().replace( /\n\s+/, '\n' );
$(this).next().find('code').text(HTML);
});

"%3Cscript" vs "<script"

Every once in a while, I'll see an HTML code snippet with:
%3Cscript
where the %3C replaces the <. Is this because the code was auto-generated or needs to display properly in an editor or was it coded that way explicitly for some reason and needs to keep that form on the HTML webpage? In case it is helpful here is the full beginning of the line of code I was questioning:
document.write(unescape('('%3Cscript
Wouldn't the line of code work just fine it you replaced the %3C with a <?
The unescape() Javascript function converts the %3C back to < before it gets written into the document. This is apparently an attempt to avoid triggering scanners that might see the literal <script tag in the source and misinterpret what it means.
When writing javascript in a script tag embedded in html, the sequence </script> cannot appear anywhere in the script because it will end the script tag:
<script type="text/javascript">
var a = "<script>alert('hello world');</script>";
</script>
Is more or less treated as:
<script type="text/javascript">
var a = "<script>alert('hello world');
</script>
";
<script></script>
In the eyes of the html parser.
Like mplungjan said, this is convoluted way and one can simply <\/script> in a javascript string literal to make it work:
<script type="text/javascript">
var a = "<script>alert('hello world');<\/script>";
</script>
This is not related to document.write technically at all, it's just that document.write is a common place where you need "</script>" in javascript string literal.
Also note that "<script>" is indeed totally fine as is. It's just the "</script>" that's the problem which you have cut out from the code.
As mentioned, possible attempt to fool scanners.
A more useful and important one is the
<\/script> or '...<scr'+'ipt>' needed to not end the current script block when document.writing a script inline

Need to escape /> (forward slash and greater than) with jQuery or Javascript

I'm working on a web page that will display code inside pre tags, and need to render characters used to form HTML tags within those pre tags. I'm able to escape the greater-than and less-than symbols via jQuery/Javascript per my code below.
However, the combination of a forward slash and a greater than symbol (/>) is problematic. Additionally, I'm getting more expected results rendered in the final output when the page runs.
The contents of the pre tag are simple.
<pre>
<abc />
<xyz />
</pre>
Here is my jQuery code.
$(function(){
$('pre').html(function() {
//this.innerHTML = this.innerHTML.replace(new RegExp(['/>'],"g"), "#");
//this.innerHTML = this.innerHTML.replace(new RegExp(['/'],"g"), "*");
this.innerHTML = this.innerHTML.replace(new RegExp(['<'],"g"), "<");
this.innerHTML = this.innerHTML.replace(new RegExp(['>'],"g"), ">");
});
});
When this runs, what I expect to happen is the page will render the following:
<abc/><xyz/>
Pretty simple. Instead, here is what gets rendered in Chrome, Firefox, and IE.
<abc>
<xyz>
</xyz></abc>
The tags get duplicated, and the forward slashes get moved after the less-than symbols. Presently I'm learning jQuery, so there may be something more fundamental wrong with my function. Thanks for your help.
You have some invalid HTML. The browser then tries to turn the invalid HTML into a DOM. jQuery then asks the browser to turn the DOM back into HTML. What it gets is a serialisation of the DOM at that stage. The original source is lost.
You can't use jQuery to recover the original broken source of an HTML document (short of making a new HTTP request and forcing it to treat the response as plain text).
Fix the HTML on the server before you send it to the client.

Expansion of Struts 2 Tags Messes Up Rendering Of Page

Often times, when I use struts 2 tags, the loading of a page will be incomplete apparently because of single quote or double quote characters from the struts 2 tag interfering with such characters from javascript.
One example I am very eager to get working is as follows:
var me = '<s:a href=\'http://www.google.com\'>Google Link</s:a>';
$('#appnSelect').html(me);
So what I am concerned about is when single and double quotes are inside that me string on the right side of line 1. Ultimately, I need to get <s:select> to work, but this problem seems to creep in with a number of tags like the above example. Replace the <s:a> tag with an <a> tag, and voila, it works. However, when the <s:a> tag gets expanded, the page will incompletely load.
Is there an easy solution somewhere I am missing? One thing I did try was with the theme attribute setting theme="simple" because sometimes that helps me when the output gets rendered incorrectly. That did not work in this case.
Generating HTML from tags like that in the middle of a JavaScript string constant is always going to be an ugly business. In addition to quote characters, you're also likely to get newlines. Strictly speaking you don't know what you're going to get, and you can't control it.
One thing that comes to mind is that you could drop the tags into dummy <script> blocks marked as a non-JavaScript type:
<script id='anAnchor' type='text/html'>
<s:a href='http://www.google.com'>Google Link</s:a>
</script>
The browser won't try to execute that. You can then do this in your JavaScript code:
$('#appnSelect').html($('#anAnchor').html());
What should work with very little thinking:
<s:a id="google" style="display: none;" href="www.google.com">Google Link</s:a>
Now just grab the the element using the id in your script. Might be better if you set up a class. There are id, style and class attributes for all struts2 tags.
I believe the issue is with your escaping of the single quotes inside the <s:a> tag. In my experience with using <s:url>, I've done the following:
var url = "<s:url value='/someAction.action' />"
I believe the same syntax should hold true for <s:a>.
Additionally, look in your JSP container's error log, and see if you can find an error relating to that <s:a> tag. That may provide some additional insight to the problem.
This is my answer, which will not be the best answer because Pointy's response pointed me in the correct direction. However, up votes still appreciated :)
First, you need the script blocks which are not rendered. I have 2 because a checkbox will toggle between which one is displayed:
<script type="myType" id="abc">
<s:select name="selectName" list="#list1" listValue="%{prefix + '-' + name}" theme="simple"/>
</script>
<script type="myType" id="abc2">
<s:select name="selectName" list="#list2" listValue="%{prefix + '-' + name}" theme="simple"/>
</script>
Next, I create a region which is blank in the html code
<div id="innerRegion">
</div>
Then, I need to put something on the screen when the page first comes up, so go with this:
<script type="text/javascript">
$(document).ready(function(){
$('#innerRegion').html( $('#abc').html() )
});
I needed to put this at the end of my document because onLoad was already being used by a parent page. So I am saying abc is the correct default.
Then I need logic to handle what happens when the checkbox is pushed:
var buttonPressed = false;
$(window).load(
function()
{
LocalInit();
});
function LocalInit() {
$('#myForm input[name=buttonValue]').change(
function()
{
buttonPressed = !buttonPressed;
if (buttonPressed == true)
{
$('#innerRegion').html( $('#abc2').html() )
} else
{
$('#innerRegion').html( $('#abc').html() )
}
$('#dataId').href = document.location.href;
}
);
}
I think what was tripping me up ultimately was that I was trying to force the s:select tag through jQuery functions when as you see above it did not turn out to be necessary. I could just write the s:select as normal.

Categories