tags:

views:

297

answers:

2

I was recently trying to find a bug in some scripting and I discovered this very interesting behavior when loading a page with jQuery.

File #1: Test1.htm

<div id="test"></div>

<script type="text/javascript">
$(document).ready(function(){
 $('#test').load('test2.htm #content',function(){
  alert('done loading!');
 })
})
</script>

File #2: Test2.htm

<div id="content">
howdy

<script type="text/javascript">
$(document).ready(function(){
 alert('hello #1');
})
</script>
<SCRIPT type="text/javascript">
$(document).ready(function(){
 alert('hello #2');
})
</SCRIPT>

</div>

Now when I run Test1.htm, I get the following:

  • hello #2 alert
  • howdy from test2.htm displays
  • done loading alert

As you can see the only difference is the script tag is in upper case for the hello #2 alert. The script to show the hello #1 alert never gets exectued...

So far, I've tested this in Firefox 3.55, IE 8.0.6001.18702 and Chrome 3.0.195.33 with similar results.

In the past, I've wanted to execture javascript from the loaded content, similar to this SO question. So my question is, is this a bug or a solution?


Update: As Jitter states below, the same thing happens if Test2.htm has the script outside the content I am loading.

<div id="content">
howdy from test2.htm
</div>

<script type="text/javascript">
$(document).ready(function(){
 alert('hello #1');
})
</script>
<SCRIPT type="text/javascript">
$(document).ready(function(){
 alert('hello #2');
})
</SCRIPT>
+8  A: 

Actually this seems to be a bug in jQuery. You should post a bug-ticket. Nice find btw.

In jQuery 1.3.2 line 3270-3272 we have

// inject the contents of the document in, removing the scripts
// to avoid any 'Permission Denied' errors in IE
.append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))

Clearly the case-insensitive flag i on this regex is missing. Thus every <script>...</script> tag which isn't all lower case like <SCRIPT>, <Script>, <scriPt>, ... isn't removed by jQuery as intended.

So line 3272 should look like

.append(res.responseText.replace(/<script(.|\s)*?\/script>/gi, ""))

Additionally this bug is only triggered by your usage of an selector in the load url test2.htm #content. If you leave that one out and use

$('#test').load('test2.htm',function(){....});

and test2.htm looks like the following it will fire three alerts too (no matter how you write the script tag). So this is also a corner case bug too.

howdy

<SCRIPT type="text/javascript">
$(document).ready(function(){
 alert('hello #1');
});
</SCRIPT>
<script type="text/javascript">
$(document).ready(function(){
 alert('hello #2');
})
</script>
jitter
Please comment if you decide to post a bug-ticket (or if you decide not to) and include a link to it. Else I will post one
jitter
+1 for bugfix implementation and erroneous line.
cballou
Even the presence of the `.replace()` is suspect. As you point out, without the selector jQuery does explicitly parse out and execute embedded `<script>` elements. So why, when specifying a selector string, does jQuery break consistency with itself by *not* executing the embedded `<script>` elements? knowwhatamean?
Crescent Fresh
Indeed. It stinks of a quick browser workaround hack that wasn't thought through. The way `clean()` handles scripts is already bad enough as it is without this cherry on top.
bobince
Hi Jitter, nice answer... I'll leave it to you to post a bug-ticket since you have the solution :)
fudgey
I looked at the jQuery bug tracker and didn't see a submission, so I did it today: (http://dev.jquery.com/ticket/5668)
fudgey
Ah... completely forgot about this. Hadn't the time at that moment to check the bugtracker if this wasn't already posted. Thanks. Maybe you could add that the behavior is also inconsistent in the sense `script` tags only get removed if you provide a selector. But not if you just load the whole document. `load("test.html")` vs `load("test.html #selector)` behaves differently
jitter
YAY, It'll be fixed in v1.4. Thanks for your help and input :)
fudgey
+2  A: 

Injecting script elements via HTML is very difficult to do reliably cross-browser, and consequently broken in various ways in jQuery. It does some things to work around known browser problems, but this can end up just making it worse.

With jitter's bug (+1) fixed you'll find the scripts don't get inserted at all, to try to avoid these kinds of problem. Even with the fix, this line is vile and fragile code, trying to process HTML with regex, and will fail if the string /script> is included in the script block (which is quite valid). And will fail for </script >. And so on.

So do yourself a favour and leave <script> out of HTML content you intend to load dynamically. Always pass any script content to be executed back separately from the HTML.

bobince
;) http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454
jitter
What a strange answer, there must be something wrong with whoever posted that.
bobince
Hmmm and I was thinking it'd be kind of nice to have some code automatically run LOL... oh well :)
fudgey
+1 btw... Oh and sadly, I discovered this by loading a page that I don't have content control over... also, the <SCRIPT> tag is not contained in the `<div>` I was trying to load.
fudgey