Home > Back-end >  How can I manually append three.js code into an iframe
How can I manually append three.js code into an iframe

Time:07-05

I recently asked this question on SO, asking how to feed code into an iframe WITHOUT a file or url. This worked in simple cases, like <h1>Hello World</h1>, but in the long run, I want to implement three.js into these iframes. Here is how I tried adding to the iframe:

var iframe = document.getElementById("my-iframe");
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;

iframeDocument.body.innerHTML = "<h1>Hello World</h1>";

This works fine, but now I try to create a very simple three.js scene, just to kick things off. Here is how I tried it:

generatedCode = `\
    <!DOCTYPE html>\
    <html>\
        <head>\
            <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js" ></script>\
        </head>\
        <body style="margin: 0;">\
            <script>\
        var scene = new THREE.Scene();\
        var camera = new THREE.PerspectiveCamera(90, window.innerWidth/window.innerHeight, 0.1, 1000);\
        \
        var mesh = new THREE.Mesh(\
            new THREE.BoxGeometry(1,1,1),\
            new THREE.MeshBasicMaterial({color:0xff0000})\
        );\
        \
        scene.add(mesh);\
        \
        camera.position.z = -5;\
        camera.lookAt(0, 0, 0);\
        \
        var renderer = new THREE.WebGLRenderer();\
        renderer.setSize(window.innerWidth, window.innerHeight);\
        document.body.appendChild(renderer.domElement);\
    \
    function animate(){\
        requestAnimationFrame(animate);\
        renderer.render(scene, camera);\
    }\
    \
    animate();\
        </script>\
        </body>\
    </html>\
    `

Just a variable, sorry if this isn't the best way to do things. After defining this variable, I apply it the same way:

var iframe = document.getElementById("my-iframe");
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;

iframeDocument.body.innerHTML = generatedCode; //Now using the variable instead of a heading

Why doesn't this work? Thanks!

CodePudding user response:

Provided the parent window is considered to be of the same origin, code in an iframe element can access its parent window using window.parent, or the top most window in a group of nested iframes as window.top. And global variables declared using var can be accessed as window properties.

The example below uses document.write because, without further testing, it compiled the script written to the iframe document - there may be other ways of doing it. The script written calls a test function in the parent iframe, which logs text on the console.

This code doesn't work on Stack Overflow (which triggers a not-same origin error) but testd successfully when when loaded in a browser :

<!DOCTYPE html>
<html><head><meta charset="utf-8">
   <title>Iframe Access</title>
</head>
<body>
<h1>Parent window</h1>

<iframe id="my-iframe"></iframe>


<script>"use strict";
  var test = ()=>console.log("test() call in parent window");
  var iframe = document.getElementById("my-iframe");
  var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
  iframeDocument.open();
  iframeDocument.write( `
    <h1>iframe Body</h1>
    Check the console for output...
    <script>
      console.log(window.parent);
      window.parent.test();
   <\/script>`
  );
  iframeDocument.close();
</script>
</body>
</html>


Returning to the question, the first thing to try from the parent frame might be

iframe.contentWindow.generateContent = generateContent

which would make generateContent a property of the window within the iframe. It says nothing about whether generateContent will run under such circumstances!

CodePudding user response:

Your generatedCode will produce error Unterminated template literal you need to escape/replace </script> in variable with <\/script>

because the variable start with <!DOCTYPE html><html> it better to write the iframe using iframeDocument.write(), becasuse the iframeDocument.body.innerHTML is to write in <body>

run on jsfiddle

let generatedCode = `
<!DOCTYPE html>
<html>

<head>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"><\/script>
</head>

<body style="margin: 0;">
    <script>
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.1, 1000);
        var mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({
            color: 0xff0000
        }));
        scene.add(mesh);
        camera.position.z = -5;
        camera.lookAt(0, 0, 0);
        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        function animate() {
            requestAnimationFrame(animate);
            renderer.render(scene, camera);
        }
        animate();
    <\/script>
</body>

</html>`;

var iframe = document.getElementById("my-iframe");
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;

iframeDocument.write(generatedCode);
iframeDocument.close();
<iframe id="my-iframe"></iframe>

  • Related