More than one year ago I was playing with AJAX, and I was facing a problem with scripts contained in documents loaded through XMLHttpRequest. So, at that time, I wrote two blog posts talking about this issue. The first was just a modify to the well known AHAH technique, while the second post was a script I entirely wrote by myself: “Javascript script execution in innerHTML: the revenge”.
Now more than a year has passed and technologies are evolved. Now the web is full of very powerful AJAX frameworks and much probably, for medium/big projects you won’t need this kind of “hack” anymore. But there are few developers across the world that still hand-code their little ajax tricks and needs this. So, since I received a lot of comments about that, I’m writing here again to update you about the modifies that have been done to that script.
That script suffered of a (relatively) big problem: if you had a document.write() call in the external script you loaded, well, it won’t work. Jeremy Bell has modified that script in order to have this functionality included. You can see it working at http://www.blackoutwebdesign.com/ajax.demo.php.
For other discussion about the topic, look at the comments in the post, they have been very helpful to me to correct various compatibility issues.
The execJS() I posted some time ago have some problems (and it, yes, was just a modify to the AHAH version). I didn’t really realized what exactly it is, but I found a simple (?) solution. The problem, as far as I can understand, is that eval() doesn’t always execute the code. So here it is the workaround: look for <script> tags, take its content and create a new element into the <head> with createElement/appendChild. In this way we should also be more standard-compliant than before:
function execJS(node)
{
var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
var bMoz = (navigator.appName == 'Netscape');
if (!node) return;
/* IE wants it uppercase */
var st = node.getElementsByTagName('SCRIPT');
var strExec;
for(var i=0;i<st.length; i++)
{
if (bSaf) {
strExec = st[i].innerHTML;
st[i].innerHTML = "";
} else if (bOpera) {
strExec = st[i].text;
st[i].text = "";
} else if (bMoz) {
strExec = st[i].textContent;
st[i].textContent = "";
} else {
strExec = st[i].text;
st[i].text = "";
}
try {
var x = document.createElement("script");
x.type = "text/javascript";
/* In IE we must use .text! */
if ((bSaf) || (bOpera) || (bMoz))
x.innerHTML = strExec;
else x.text = strExec;
document.getElementsByTagName("head")[0].appendChild(x);
} catch(e) {
alert(e);
}
}
};
I tested it only under firefox, but it should work on other browsers too. If it doesn’t, let me know.
Update (October 1st, 2006): now it works under Internet Explorer too (if you want to inject some text in a script element in IE you can’t use .innerHTML, but you have to use .text!)
I am developing a new website for a club I’m founding. I can’t tell you what this club will do (also because I don’t really know, yet) but the site is going to become a challenge.
I wanted to use all the latest, innovative technologies around here. So, I just took PHP, Javascript, XHTML (strictly 1.0 strict!) and a MySQL database in my gunnysack and gone around with them.
There’s an issue I’ve been facing against that just got me crazy: if I include a HTML page (not really, a php generated one to be precise) through innerHTML the content that was into the <script>...</script> tags was not executed. After some google-ing, I found that this is a security implementation: browsers doesn’t allow code to be executed into a innerHTML block. If you break a moment and think about it, it makes perfectly sense, but I need of such a feature so I had to found a workaround.
The idea was this: let threat the html page as an xml file (although it is really one), so let use the DOM to browse it looking for <script></script>, then pass its content to eval().
I was not using any AJAX library, so I had to wrote all the code by myself. Here is a snippet:
function execJS(node) {
var bSaf = (navigator.userAgent.indexOf('Safari') != -1);
var bOpera = (navigator.userAgent.indexOf('Opera') != -1);
var bMoz = (navigator.appName == 'Netscape');
var st = node.getElementsByTagName('SCRIPT');
var strExec;
for(var i=0;i<st.length; i++) {
if (bSaf) {
strExec = st[i].innerHTML;
} else if (bOpera) {
strExec = st[i].text;
} else if (bMoz) {
strExec = st[i].textContent;
} else {
strExec = st[i].text;
}
try {
eval(strExec);
} catch(e) {
alert(e);
}
}
}
function handlePageChanging()
{
if (http.readyState == 4) {
var cnt_big = document.getElementById('cnt_big');
cnt_big.innerHTML = http.responseText;
execJS(cnt_big);
hideLoading();
doLinks();
}
}
function changeContentPage(param)
{
_current = param;
var url = param + '&aJ=y';
showLoading();
http.open("GET", url, true);
http.onreadystatechange = handlePageChanging;
http.send(null);
}
Of course you can’t copy and paste this code except the execJS function (since it is this post’s purpose) but the important thing is that you notice how it works. Pratically, the page makes an AJAX request with changeContentPage(), then handle it through handlePageChanging(). So when we’re going to set up the content with innerHTML, we call execJS() so it will eval()-ize all the <script></script> contents.
Update: see this http://kratcode.blogspot.com/2006/03/javascript-script-execution-in.html