I'm having trouble accessing the DOM of an iframe content document if I create the iframe dynamically in JavaScript rather than hard-coding it in the HTML.
I'm finding this so far testing in Mac FF26 and Safari 6. It is a local iframe document on the desktop, so there should be no cross-domain issues.
The iframe I generate appears normally in the browser window. But trying to access it with contentDocument, the body element seems to be empty.
Is this a known issue? Perhaps I'm generating my iframe in an unusual way:
var newIframe = document.createElement("iframe");
newIframe.id = "generatedIframe";
newIframe.src = "test.html";
document.body.appendChild(newIframe);
var iframeTag = document.getElementById("generatedIframe");
// the iframe will be appearing normally in the browser now
// but this fails -- innerHTML is empty string:
var iframeContent = iframeTag.contentDocument.getElementsByTagName("body")[0].innerHTML;
// same reference code works if the iframe is hard-coded in HTML instead
In fact your problem is not the way you generated your iframe.
The iframe DOM is only available after it has been loaded.
The code behind illustrates what I mean :
In your parent window container :
<script>
function doSomething() { alert(iframeTag.contentDocument.getElementsByTagName("body")[0].innerHTML()); }
</script>
In your iframe document
<body onload="window.parent.doSomething();"></body>
Related
My goal is to change a fill attribute in a polyline element in an svg sitting in a nested, same-domain, iframe.
When my page loads, I can see the content in the browser. In the chrome console, from javascript, I can access the nested iframe, and the div containing the svg.
document.querySelectorAll('iframe#my-frame')[0]
.contentDocument.querySelectorAll('iframe')[0]
.contentDocument.querySelector('#mydiv')
but the content of that div is evidently not in any dom that I can interrogate. The div is effectively empty, even though it's content is rendered in the browser.
<div id="mydiv"></div>
When I right-click > 'Inspect' the nested iframe, the devtools redirect to the body element of the iframe#document. I am now able to interrogate the div, and manipulate the svg elements' attributes. At this point I can no longer interrogate the parent page, because the window object is now the nested iframe itself--this is not unexpected.
But I can't reset window programmatically, I don't think, i.e., this doesn't work:
window = document.querySelectorAll('iframe#my-frame')[0].contentDocument.querySelectorAll('iframe')[0].contentWindow
Is there a way to programmatically change focus or window of the javascript running in the browser--what I assume is forcing the iframe content into the dom in order to manipulate a css attribute after page load? Remember this is not an iframe domain issue.
You can't access the iframe's content instantly
You need something like a load eventListener to wait until the <iframe> content is fully loaded.
const myFrame = document.querySelector("#my-frame");
myFrame.addEventListener("load", (e) => {
// content loaded - query and manipulate elements
let doc = myFrame.contentDocument;
let iframeSvg = doc.querySelector("svg");
let svgEl = iframeSvg.querySelector("rect");
svgEl.style.fill = "green";
});
I need to run code as if it were running inside an iframe that is on the page, meaning that when I use window inside that code, it should use the iframe's window object. It is not an iframe I created, so my function is not defined inside it.
var myfunction = function () { // defined in parent, not in the iframe
console.log(window); // window here should be the iframe's window object, not the parent/
window.document.body.appendChild("Appending to iframe body");
}
// Need to somehow run this function inside the iframe
myfunction(); // as if I did this inside the iframe
I need this exact code to run inside the iframe, I know that I can use to fix this myself
frames["FrameName"].document.body.appendChild("Appending to iframe body");
but that won't fix my problem.
This is because I did not write the code myself, there is a module called Opentip that I use to create tool tips. I need to set a tooltip on an element inside the iframe; however, Opentip uses the window object in it's code to be able to create the tooltip properly.
So I need to run
Opentip(myelement, data);
as if I were running it inside the iframe, but without defining it inside the iframe.
So the Opentip function needs to use the iframe window, rather than the parent window.
The code provided is of course untested. This is answer is assuming:
OP circumstances are that the requirements of same origin policy are met.
OP cannot edit the child page directly.
OP cannot use Ajax.
Resources
Dyn-Web
Javascript injected into iframe of same origin not working
Injecting Javascript to Iframe
Snippet
//A//Ref to iframe
var iFrm = document.getElementById('iFrm')
//B//Listen for load event
iFrm.addEventListener('load', function(e) {
//C//Ref to iframe Window
var iWin = iFrm.contentWindow;
//D//Ref to iframe Document
var iDoc = iFrm.contentDocument? iFrm.contentDocument:iFrm.contentWindow.document;
//E//Ref element targeted by Opentip--replace {{>SEL<}} with appropriate selector
var iTgt = document.querySelector({{>SEL<}});
//F//Create, configure, deploy, and inject <script> tag to iframe <head>
var iNode = document.createElement(`script`);
iNode.src = "https://cdn.jsdelivr.net/opentip/2.4.6/opentip-native.min.js";
iDoc.head.appendChild(iNode);
//G//Call Opentip from iframe Window, and hopefully in iframe's context
iFrm.contentWindow.Opentip = function(iTgt, data);
}
/* Notes */
/*//F//Alternative to target iframe <head>:
window.frames["iFrm"].document.getElementsByTagName("head")[0];*/
/*//If not successful in accuirring iframe, try replacing all
"document." with "contentWindow", "contentDocument", or "contentWindow.document"*/
<iframe id="iFrm" name="iFrm" src="/"></iframe>
<!--Optionally you can add an onload event to the iframe itself
<iframe id="iFrm" name="iFrm" src="/"></iframe>
-->
I'm trying to attach new <div> element with some content via bookmarklet and add some inline CSS.
The problem is that the CSS from the main page usually affects this div too.
What would be preferred approach to ensure that my styles from bookmarklet are always more important that the ones from any parent page?
The most trustworthy solution would be to set all possible CSS properties for each element inside the div. Is this wise? Where can I get the list?
I've found cleanstate.css which may do the reset.
Maybe some js solution would work better? Eg. detect which styles has been aplied by the main page, and reset them to default values? I'll have jQuery available in this bookmarklet anyways.
The reliable solution would be iframe.
You can create it dynamically and assign content using 'javascript:' protocol in src tag.
var iframe = document.createElement('iframe');
iframe.src = "javascript:'<div> Yours Content </div>'";
document.body.appendChild(iframe);
Or you can insert empty iframe, wait it to be loaded and modify iframe document as required. For example:
var iframe = document.createElement('iframe');
iframe.src = 'about:blank';
document.body.appendChild( iframe );
iframe.onload = function() {
iframe.contentWindow.document.body.innerHTML = '<div> Yours content </div>';
};
Alternatively, you can create separate .html page and insert it as iframe. <iframe src="http://example.com">Although, you will need to host page somewhere and document won't be able to access parent page without additional scripting. ( .postMessage() )
I have a main page that include a javascript that was creating an iframe dynamically same below:
<script>
document.domain = "mydomain.com"
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
// creating other element in ifram dynamically
</script>
But in IE I kept receiving a security warning because of document.domain = "mydomain.com" (I need document.domain and I can not remove it).
I found a solution for IE8. this is the solution :
var u = 'javascript:(function(){document.open();document.domain="mydomain.com";document.close();})()';
iframe.src = u;
But it does not work on IE6. Is there any solution for my problem?
Note: I want to create other element in iframe by script and I want to load the content of iframe by src.
Create the iFrame using innerHTML.
Write the full HTML for the iFrame including the SRC attribute. Then find your element and set innerHTML to the string with the iFrame source.
I want to be able to remove an iframe from within itself. The iframe is created dynamically and the content is loaded with 'src'.
I create my iframe like this:
var i = document.createElement('iframe');
i.id = 'proxy_frame';
i.name = 'proxy_frame';
i.setAttribute('src', url);
document.body.appendChild(i);
Then from within 'url' I want to be able to remove/close the iframe.
Before loading the data into the iframe with src I used document.write:
window.frames['proxy_frame'].document.write(html);
and then I was abloe to remove the iframe with:
window.parent.document.getElementById("proxy_frame").parentNode.removeChild(window.parent.document.getElementById("proxy_frame"));
But this does not work with 'src'.
Note: This is for a bookmarklet so I don't want to use jQuery or another library.
Define a method in your parent page
function removeElement() {
var d = document.getElementById('body'); // or any other parent element
var proxy_frame = document.getElementById('proxy_frame');
d.removeChild(proxy_frame);
}
To call this method from your iframe simply use this
Remove me
For local domain iframes you don't need to rely on ids.
window.parent.document.body.removeChild(window.frameElement);
window.frameElement has reasonable support https://developer.mozilla.org/en-US/docs/Web/API/Window/frameElement
You can't access the parent page as long as it's in a different domain.
Set up a page in your site that can be used to remove the iframe, then in the iframe you just go to that page.