views:

3564

answers:

8

Lets suppose that I have the following markup:

<div id="placeHolder">
</div>

and I have a javascript variable jsVar that contains some markup and some javascript.

By using Mootools 1.1 I can inject the javascript content to the placeholder like this:

$('placeHolder').setHTML(jsVar);

This works in Firefox, Opera and even Safari and the resulting markup looks like this:

<div id="placeHolder">
    <strong>I was injected</strong>
    <script type="text/javascript">
        alert("I was injected too!");
    </script>
</div>

However, on IE 8 I get the following:

<div id="placeHolder">
    <strong>I was injected</strong>
</div>

Is there any way to inject the javascript on IE 8 or does it security model forbid me from doing this at all?

EDIT

I just tried Luca Matteis suggestion of using

document.getElementById("placeHolder").innerHTML = jsVar;

instead of the MooTools code and I get the same result. This is not a MooTools issue.

+1  A: 

I am not sure about MooTools, but have you tried innerHTML ?

document.getElementById("placeHolder").innerHTML = jsVar;

Luca Matteis
I just tried it. I get the same results. But thanks, this proves that it is not a mootools issue.
adolfojp
+1  A: 

You may need to eval the contents of the script tag. This would require parsing to find scripts in your jsVar, and eval(whatsBetweenTheScriptTags).

Joel Potter
That is the path that I will have to follow. I am currently using eval, or executing a temporary function on the contents of the script elements in the master placeholder element. Because IE 8 doesn't insert the scripts into the markup I will have to parse them at the variable level. It does work.
adolfojp
+3  A: 

This MSDN post specifically addresses how to use innerHTML to insert javascript into a page. You are right: IE does consider this a security issue, so requires you to jump through certain hoops to get the script injected... presumably hackers can read this MSDN post as well as we can, so I'm at a loss as to why MS considers this extra layer of indirection "secure", but I digress.

From the MSDN article:

<HTML>
<SCRIPT>
function insertScript(){
    var sHTML="<input type=button onclick=" + "go2()" + " value='Click Me'><BR>";
    var sScript="<SCRIPT DEFER>";
    sScript = sScript + "function go2(){ alert('Hello from inserted script.') }";
    sScript = sScript + "</SCRIPT" + ">";
    ScriptDiv.innerHTML = sHTML + sScript;
}    
</SCRIPT>
<BODY onload="insertScript();">
    <DIV ID="ScriptDiv"></DIV>
</BODY>
</HTML>

If at all possible, you may wish to consider using a document.write injected script loading tag to increase security and reduce cross-browser incompatibility. I understand this may not be possible, but it's worth considering.

Jarret Hardie
Dennis Cheung
+1  A: 

Since IE refuses to insert the content by default you will have to execute it yourself, but you can at least trick IE into doing the parsing for you.

Simply use string.replace() to swap all the <script> tags for <textarea class="myScript" style="display:none">, preserving the content. Then stick the result into an innerHTML of a div.

After this is done, you can use

div.getElementsByTagName("textarea")

to get all the textareas, loop through them and look for your marker class ("myScript" in this case), and either eval(textarea.value) or (new Function(textarea.value))() the ones you care about.

levik
+1  A: 

I never tried it, it just came to my mind... Can you try the following:

var script = document.createElement('script');
script.type = 'text/javascript';

script.innerHTML = '//javascript code here'; // not sure if it works
// OR
script.innerText = '//javascript code here'; // not sure if it works
// OR
script.src = 'my_javascript_file.js';

document.getElementById('placeholder').appendChild(script);

You can use the same technique (DOM) to insert HTML markup.

presario
+2  A: 

This is how we did it on our site about a year ago to get it working in IE. Here are the steps:

  • add the HTML to an orphan DOM element
  • search the orphan node for script tags (orphan.getElementsByTagName)
  • get the code from those script nodes (save for later), and then remove them from the orphan
  • add the html leftover that is in the orphan and add it to the placeholder (placeholder.innerHTML = orphan.innerHTML)
  • create a script element and add the stored code to it (scriptElem.text = 'alert("my code");')
  • then add the script element to the DOM (preferably the head), then remove it
function set_html( id, html ) {
    // create orphan element set HTML to
    var orphNode = document.createElement('div');
    orphNode.innerHTML = html;

    // get the script nodes, add them into an arrary, and remove them from orphan node
    var scriptNodes = orphNode.getElementsByTagName('script');
    var scripts = [];
    while(scriptNodes.length) {
        // push into script array
        var node = scriptNodes[0];
        scripts.push(node.text);

        // then remove it
        node.parentNode.removeChild(node);
    }

    // add html to place holder element (note: we are adding the html before we execute the scripts)
    document.getElementById(id).innerHTML = orphNode.innerHTML;

    // execute stored scripts
    var head = document.getElementsByTagName('head')[0];
    while(scripts.length) {
        // create script node
        var scriptNode = document.createElement('script');
        scriptNode.type = 'text/javascript';
        scriptNode.text = scripts.shift(); // add the code to the script node
        head.appendChild(scriptNode); // add it to the page
        head.removeChild(scriptNode); // then remove it
    }   
}

set_html('ph', 'this is my html.  alert("alert");');
howardr
A: 

When you say it "works" in those other browsers, do you mean you get the alert popup message, or do you just mean the <script> tag makes it into the DOM tree?

If your goal is the former, realize that the behaviour of injecting html with embedded <script> is very browser-dependent. For example in the latest MooTools I can try:

$(element).set('html', '<strong>Foo</strong><script>alert(3)</script>')

and I do not get the popup, not in IE(7), not in FF(3) (however I do get the <script> node into the DOM successfully). To get it to alert in all browsers, you must do as this answer does.

JPot
A: 

I am sorry, perhaps I am missing something here--but with this being a mootools 1.11 question, why don't you use assets.js?

// you can  also add a json argument with events, etc.
new Asset.javascript("path-to-script.js", { 
    onload: function() { 
        callFuncFromScript(); 
    }, 
    id: "myscript"
});

Isn't one of the reasons why we're using a framework not to have to reinvent the wheel all over again...

as far as the 'other' content is concerned, how do you happen to get it? if through the Request class, it can do what you want nicely by using the options:

{
    update: $("targetId"),
    evalScripts: true,
    evalResponse: false
}
Dimitar Christoff