I've got a script that inserts some content into an element using innerHTML
.
The content could for example be:
<script type="text/javascript">alert('test');</script>
<strong>test</strong>
Problem is that the code inside the <script>
tag doesn't get executed.
I googled it a bit but there were no apparent solutions. If I inserted the content using jQuery $(element).append(content);
the script parts got eval
'd before being injected into the DOM.
Has anyone got a snippet of code that executes all the <script>
elements? The jQuery code was a bit complex so I couldn't really figure out how it was done.
Edit:
By peeking into the jQuery code I've managed to figure out how jQuery does it, which resulted in the following code:
Demo:
<div id="element"></div>
<script type="text/javascript">
function insertAndExecute(id, text)
{
domelement = document.getElementById(id);
domelement.innerHTML = text;
var scripts = [];
ret = domelement.childNodes;
for ( var i = 0; ret[i]; i++ ) {
if ( scripts && nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
}
}
for(script in scripts)
{
evalScript(scripts[script]);
}
}
function nodeName( elem, name ) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
}
function evalScript( elem ) {
data = ( elem.text || elem.textContent || elem.innerHTML || "" );
var head = document.getElementsByTagName("head")[0] || document.documentElement,
script = document.createElement("script");
script.type = "text/javascript";
script.appendChild( document.createTextNode( data ) );
head.insertBefore( script, head.firstChild );
head.removeChild( script );
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
}
insertAndExecute("element", "<scri"+"pt type='text/javascript'>document.write('This text should appear as well.')</scr"+"ipt><strong>this text should also be inserted.</strong>");
</script>
Extending off of Larry's. I made it recursively search the entire block and children nodes.
The script now will also call external scripts that are specified with src parameter. Scripts are appended to the head instead of inserted and placed in the order they are found. So specifically order scripts are preserved. And each script is executed synchronously similar to how the browser handles the initial DOM loading. So if you have a script block that calls jQuery from a CDN and than the next script node uses jQuery... No prob! Oh and I tagged the appended scripts with a serialized id based off of what you set in the tag parameter so you can find what was added by this script.
A solution without using "eval":
This essentially clones the script tag and then replaces the blocked script tag with the newly generated one, thus allowing execution.
@phidah... Here is a very interesting solution to your problem: http://24ways.org/2005/have-your-dom-and-script-it-too
So it would look like this instead:
<img src="empty.gif" onload="alert('test');this.parentNode.removeChild(this);" />
You may take a look at this post. The code might look like this:
Thanks to Larry's script, which worked perfectly well in IE10, this is what I've used:
scriptNode.innerHTML = code
didn't work for IE. The only thing to do is replace withscriptNode.text = code
and it work fine