nightcoder
nightcoder

Reputation: 13509

jQuery's attr() function breaks html with html special characters?

Please take a look at the following code:

http://jsfiddle.net/htdTg/2/

In the first link there is a title attribute containing the html special character &lt; followed by "!" (it doesn't matter which character it is followed by actually). When we take the value of that title attribute with jQuery's attr() function the html is broken (you can see that there is no "<" character printed as long as the following text is also missing.

In the second link the only difference is that I have added a space after &lt; and now it works as expected.

Do you think it's a bug in jQuery or I just don't understand something?

PS. If you think I'm doing something strange - it's just some piece of code from some tooltip plugin.

HTML:

<a href="#" title="<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>">This is a link</a><br>
<a href="#" title="<div style='color:red'>This is the less than sign: &lt; ! Now you know it?</div>">This is a link</a><br>​

jQuery:

$('a').each(function() {
    $('body').append($(this).attr('title')); });

// just to exclude that it's append() function's fault :)
$('body').append("<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>");​

Upvotes: 5

Views: 3303

Answers (6)

Gabriele Petrioli
Gabriele Petrioli

Reputation: 195982

Nothing is really wrong..

The issue is that html inside attributes must be encoded. You already have encoded the < as &lt; and that means that it will be read as <.

So .attr() will return a pure < character and not the encoded..

The reason it does not show is with .append which will try to parse the html if it thinks there is html in it.. It finds the <! text and it considers it as html comment. actually this is done directly by the browser.


If you look at

var e = document.createElement('div');
e.innerHTML = '<!';
console.log(e.innerHTML);

you will see that the inner HTML of the div after setting it to <! is <!---->.

So that is how the browsers interpret this code.. it has nothing to do with jQuery..

Upvotes: 1

Shiplu Mokaddim
Shiplu Mokaddim

Reputation: 57650

Why its happening?

This is happening because &lt;! Now you know it? </div> is converted to <! Now you know it? </div-->

According to HTML standard <! and > is the start and end of comment structure. Note this is comment structure not comment. Hence browwer converts the rest as comment unless it gets a end delimiter >.

From W3C

<!-- this is a comment -->
<!-- and so is this one,
    which occupies more than one line -->

White space is not permitted between the markup declaration open delimiter(<!) and the comment open delimiter (--), but is permitted between the comment close delimiter (--) and the markup declaration close delimiter (">"). A common error is to include a string of hyphens (---) within a comment. Authors should avoid putting two or more adjacent hyphens inside comments.

Also in here

The syntax for comment declarations in SGML is

 comment declaration =
    MDO ("<!"), (comment, ( s | comment )* )?, MDC (">")
 comment =
    COM ("--"), SGML character*, COM ("--")

How to solve it?

You already know it. use &amp; to replace &. So write &amp;lt;! instead of &lt;!. This will make &lt; appended to body element instead of <! which is comment structure opening.

Upvotes: 3

Holf
Holf

Reputation: 6431

I'm not sure if you're just asking the question or actually looking for a solution to the problem. If the latter, then strangely this seems to work fine: &amp;lt;

Updated code:

HTML:

<a href="#" title="<div style='color:red'>This is the less than sign: &amp;lt;! Now you know it?</div>">This is a link</a><br>
<a href="#" title="<div style='color:red'>This is the less than sign: &amp;lt; ! Now you know it?</div>">This is a link</a><br>​

jQuery:

$('a').each(function() {
    $('body').append($(this).attr('title')); });

// just to exclude that it's append() function's fault :)
$('body').append("<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>");​

Updated fiddle: http://jsfiddle.net/htdTg/3/

Upvotes: 1

Ricardo Lohmann
Ricardo Lohmann

Reputation: 26320

The text isn't missing the problem is that it get commented because &lt;! is the same of <! which is being translated to <!--(don't know why) which starts a comment in html.

If you inspect your html you'll see the following.

<div style='color:red'>This is the less than sign: <!-- Now you know it? --></div>
<div style='color:red'>This is the less than sign: < ! Now you know it?</div> 

Upvotes: 1

Sparky
Sparky

Reputation: 98728

In this case...

title="<div style='color:red'>This is the less than sign: &lt;! Now you know it?</div>"

&lt;! is converted to <! which is the start of a HTML comment and exactly why it does not render in the browser window.

For all cases, you should not have HTML entities contained within an attribute. Use this instead...

title="&lt;div style='color:red'&gt;This is the less than sign: &amp;lt;! Now you know it?&lt;/div&gt;"

http://jsfiddle.net/htdTg/5/

If you want to preserve the HTML entities, use &lt;div&gt; to be processed as <div>. Alternatively, &amp;lt;div&amp;gt; will actually render <div> in the browser window.

See: http://jsfiddle.net/htdTg/8/

So if you want the browser to actually display a <!, then use this: &amp;lt!

Upvotes: 1

Blender
Blender

Reputation: 298156

This is pretty interesting. I looked up what text can be in a title attribute and the reference says:

User agents should interpret attribute values as follows:

  1. Replace character entities with characters,
  2. Ignore line feeds,
  3. Replace each carriage return or tab with a single space.

Apparently, this is the expected behavior. &lt; is being parsed as < by the browser, which might be interpreted as HTML by jQuery.

You should be escape the ampersand as well:

&amp;lt;

Demo: http://jsfiddle.net/htdTg/9/

Even better demo: http://jsfiddle.net/PsZeY/6/

Upvotes: 5

Related Questions