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>