0

I am currently using Ace (http://ace.c9.io/) to take code from an editor and execute it within an iFrame. My issue is that when I add something along the lines of

Code in Editor

<script type="text/javascript">
    window.onload = function() {
        alert("hello");
    }
</script>

to the head or body of the iFrame, the code is never executed. This is my current code:

Injecting Code into iFrame

$("#btnRun").click(function(event) {  
    event.preventDefault();

    // iFrame with id="preview"
    var preview = $("#preview").contents();

    // Get code from editor and wrap in <script> tags
    var script = "<script type='text/javascript'>" + ace.edit("js-editor").getSession().getValue()  + "</script>";

    // Append code to head or body, in this case head
    preview.find("head").append(script);
});

The code is successfully added to the iFrame, however it is never executed. I can also successfully add HTML/CSS and it displays in the iFrame, but the javascript is never touched.

I have tried wrapping the code in script tags within the editor only, as well as using an escape character on the closing tag: "</script>" but to no avail.

This is the iFrame in my index.html document.

iFrame in index.html

<iframe class="editor" id="preview" name="result" sandbox="allow-forms allow-popups allow-scripts allow-same-origin" frameborder="0">
    #document
    <!-- Editor content goes here -->
</iframe>

After the code is injected the iFrame looks like this

iFrame with Injected Code

<iframe class="editor" id="preview" name="result" sandbox="allow-forms allow-popups allow-scripts allow-same-origin" frameborder="0">
    #document
    <html>
      <head>
        <script type="text/javascript">
          window.onload = function() {
            alert("hello");
          }
        </script>
      </head>
    <body>
    </body>
  </html>
</iframe>

Also when calling the window.onload or window.top.onload event from within the iFrame, the code executes but only affects the page containing the iFrame and not the contents of the iFrame itself.

Thank you.

Note: When the code is not within window.onload it runs fine. However I wish to be able to execute this code when the frame's onload function is executed.

John Cipponeri
  • 882
  • 8
  • 12
  • https://developer.mozilla.org/en-US/docs/Web/API/Window.top – Jonathan Feb 01 '15 at 20:14
  • Changing the window.onload to window.top.onload didn't change the outcome. The executed javascript also only seems to affect the parent page rather than the contents of the iFrame. – John Cipponeri Feb 01 '15 at 20:32
  • you are inserting the script tag after the onload event has likely fired. So why not simply insert the code without wrapping it up in an event handler? – Rune FS Feb 01 '15 at 21:32
  • Well my concern isn't exactly what event it is wrapped in, but how to get the "window" that belongs to the iFrame from within the iFrame. – John Cipponeri Feb 01 '15 at 21:36
  • See my answer here: http://stackoverflow.com/a/36155560/3894981 – dude Mar 22 '16 at 13:31

3 Answers3

2

I would think that you are adding the JS to the iframe after the onload event has already fired.

Perhaps you could try simulating an event to run the preview code or dispatching the onload event again?

Might help: https://developer.mozilla.org/en-US/docs/Web/API/Window.dispatchEvent

Stuart Miller
  • 647
  • 3
  • 8
  • I think you're right and I will try that now. However when I called window.onload after defining it the code executes but it only affects the content of the parent page and not that of the iFrame. – John Cipponeri Feb 01 '15 at 20:33
  • Are you calling onload on the iframe? Not the parent window? This may help: http://www.w3schools.com/jsref/prop_frame_contentwindow.asp – Stuart Miller Feb 01 '15 at 20:35
  • I am adding the code window.onload = function() { // do stuff } window.onload(); This code is then injected into the iFrame however it is executed with the window being the parent page for some reason. – John Cipponeri Feb 01 '15 at 20:37
  • @JohnCipponeri How are you injecting it? are you inserting the text or are you passing a function reference? – Rune FS Feb 01 '15 at 20:54
  • @RuneFS Please see the **Injecting Code into iFrame** section of my question. I am appending the script as a string to the iFrame. – John Cipponeri Feb 01 '15 at 20:55
  • Don't suppose you have a link to you code online? It's quite hard to get running in a scratchpad app or jsfiddle! – Stuart Miller Feb 01 '15 at 21:01
  • @StuartMiller https://github.com/johncipponeri/jstinker This is only slightly different. It adds the content all together (HTML/CSS/JS) to the body tag but the problem still exists. If you clone it it will work out of the box. – John Cipponeri Feb 01 '15 at 21:03
  • I'm afraid I cannot figure out how to do it, fiddle does seem to do it using the No wrap - in mode though... – Stuart Miller Feb 01 '15 at 22:13
1

I was able to fix this myself. The problem was that appending the script to be within the iFrame wasn't enough to make it work. To make the script only be executed within the iFrames DOM was to write directly to it.

$("#btnRun").click(function(event) {  
    event.preventDefault();

    var previewDoc = window.frames[0].document;

    var css    = ace.edit("css-editor").getSession().getValue();
    var script = ace.edit("js-editor").getSession().getValue();
    var html   = ace.edit("html-editor").getSession().getValue();

    previewDoc.write("<!DOCTYPE html>");
    previewDoc.write("<html>");
    previewDoc.write("<head>");
    previewDoc.write("<style type='text/css'>" + css + "</style>");
    previewDoc.write("<script type='text/javascript'>window.onload = function() {" + script + "}</script>");
    previewDoc.write("</head>");
    previewDoc.write("<body>");
    previewDoc.write(html);
    previewDoc.write("</body>");
    previewDoc.write("</html>");
    previewDoc.close();
});
John Cipponeri
  • 882
  • 8
  • 12
  • And that fires the onload event? That's a nice solution. Though without wrapping it as fiddle does it, does that mean it's possible for any JS written in there to change the parent frame? – Stuart Miller Feb 02 '15 at 10:00
  • @StuartMiller Yes it executes upon the onload event. No it does not alter the parent of the iFrame whatsoever, whether it is wrapped or not with the window.onload. I have actually used this to implement all 4 code wrapping functions used by JSFiddle with ultimate success. – John Cipponeri Feb 02 '15 at 15:31
  • Awesome :) The user couldn't reference the parent frame either from the script? – Stuart Miller Feb 02 '15 at 15:32
  • No, that was actually one of my tests with this was trying to use jQuery (imported by the parent) and to alter the parent page but to no avail thankfully. – John Cipponeri Feb 02 '15 at 15:34
  • Nice one, glad you got it sorted. Be careful not to look at the JSFiddle source too much. I'm no copyright lawyer but though the idea isn't protected, copy and pasting from the site or appearing to may be an infringement. – Stuart Miller Feb 02 '15 at 15:37
  • Thanks for the head's up. As far as I can tell JSFiddle uses it's own software stack, I'm only creating a clone from looking/using not reading the code. Especially since most of it is server-sided and I am attempting to make a client-side only and offline clone. – John Cipponeri Feb 02 '15 at 15:39
1

I think it would be more elegant to use the contentDocument property of the iframe, and then inject the script and trigger the parser so it actually interprets it as JavaScript.

I put up a small proof of concept on github. I hope it solves your problem in a more elegant manner.

https://github.com/opreaadrian/iframe-injected-scripts

Cheers,
Adrian.

Adrian Oprea
  • 2,360
  • 3
  • 21
  • 23