0

So I am making a JS playground like JSFiddle. While adding the JavaScript functionality and calling different functions, it seems like the code is running from the page document root and not the iframe one.

$(document).ready(function()
{
    var result = $("#result"); 

    htmlVal = htmlEditor.getValue();
    cssVal = cssEditor.getValue();
    jsVal = jsEditor.getValue();

    iframe = $("<iframe></iframe>");

    result.append(iframe);

    var iframeDoc = $(iframe.get(0).contentDocument) //iframe.contents();
    bodyFrame = iframeDoc.find("body");
    headFrame = iframeDoc.find("head");
    cssFiddle = headFrame.append("<style id='cssEdit'>"  + settings.JS + "\n" +  cssVal + "</style>").children("#cssEdit");
    jsFiddle = bodyFrame.append("<script id='jsEdit'>" + settings.JS + "\n" + jsVal + "</script>").children("#jsEdit");

    $("#update").click(updateResult);

    //setInterval(updateResult, 100);
});

function updateResult()
{
    htmlVal = htmlEditor.getValue();
    cssVal = cssEditor.getValue();
    jsVal = jsEditor.getValue();

    if(htmlVal.split("</body>").length == 2)
    {
        var bodyText = htmlVal.split("<body>")[1].split("</body>")[0];
        bodyFrame.html(bodyText);
        jsFiddle = bodyFrame.append("<script id='jsEdit'>" + settings.JS + "\n" + jsVal + "</script>").children("#jsEdit");
    }
    if(htmlVal.split("</head>").length == 2)
    {
        var headText = htmlVal.split("<head>")[1].split("</head>")[0];
        headFrame.html(headText);
        css = headFrame.append("<style id='cssEdit'>" + settings.JS + "\n" + cssVal + "</style>").children("#cssEdit");
    } else
    {
        bodyFrame.html(htmlVal);
        js = bodyFrame.append("<script id='jsEdit'>" + settings.JS + "\n" + jsVal + "</script>").children("#jsEdit");
    }

    jsFiddle.html(settings.JS + "\n" + jsVal);
    cssFiddle.html(settings.CSS + "\n" + cssVal);
}

Example

Gagik
  • 96
  • 3

2 Answers2

1

This answer really helped.

So the reason of the code being executed in global namespace is because of jQuery. Calling bodyFrame.append('script'), runs document.createElement('script'), meaning the code will run in document, not in iframeDoc in my case. So we need to use pure javascript.

    jsFiddle = doc.createElement("script");
    jsFiddle.setAttribute("type", "text/javascript");
    jsFiddle.textContent = "console.log(document.body)";

    bodyFrame[0].appendChild(jsFiddle);
Community
  • 1
  • 1
Gagik
  • 96
  • 3
0

To access an iframe's document do this:

var iframeDoc = $(iframe.get(0).contentDocument)

Then you can do:

bodyFrame = iframeDoc.find("body");
headFrame = iframeDoc.find("head");

Because an iframe has it's own document root you have to search for the iframe's html from that document root.

EDIT

So a/the issue is that changing the innerHTML of a script tag doesn't run new JS. So I would recommend either using jQuery's .replaceWith() method (http://api.jquery.com/replacewith/#replaceWith-newContent) or wrapping the embedded JS in a div or something and changing that element's HTML

winhowes
  • 7,845
  • 5
  • 28
  • 39
  • Doesn't seem to do any difference – Gagik Feb 21 '15 at 10:01
  • Sorry for confusion. But the code itself does execute, what I am asking is that is there a way to make the code run inside iframe's document root (in the screenshot the code worked, but it changed the background of the body of the whole page, not the iframe (4th block)) – Gagik Feb 21 '15 at 12:39
  • Thanks for this though, this was the next problem that came up after fixing this one. – Gagik Feb 21 '15 at 13:16