Get the "outest" window object in html document - javascript

If I have a document with for example 2 or more Iframes in each other, how can I access the main document's window object from the last one down the tree?
<html>
...
<iframe>
<iframe>
<!-- I'm here -->
</iframe>
</iframe>
...
I want to be able to redirect the browser window to another page but I cant seem to find a way to grab it's window object.
I tried something like
var outest = window;
if(outest.parent){
outest = outest.parent
}
But for some reason it appears that window has infinite parents. Any ideas?

top refers to the outmost window object, i.e. the browser window.

Related

Nested iframe css manipulation in javascript after load

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";
});

Reloading iframe from separate iframe

I have checked all the reload iframe from another iframe posts on stackoverflow...and I have tried all their solutions but it doesn't seem to help me! So my problem is that I have two iframes on the same page. The iframe's sources are php files that interact with each other, however I need the iframes to reload that way the changes are shown. I have tried many different ways (which I will list below). These iframes are from the same domain. Maybe it is something else that is messing this up? Thanks in advance.
Different statements called from inside one iframe:
parent.document.getElementById(id).src = parent.document.getElementById(id).src;
parent.getElementById(id).location.reload();
Trying to call a parent function that works in the parent window:
Inside iframe -
parent.refresh(id);
Parent window working function -
function refresh(id) {
document.getElementById(id).src = document.getElementById(id).src;
}
If you assign name to iframe most browsers will let you access the iframe's window object via the name value. This is different from referring to an iframe by its id property which will give you a reference to the iframe element itself (from its owner document), and not the iframe's content window.
Simple Example: (from the parent document)
<iframe name='iframe1Name' id='iframe1Id'></iframe>
<script>
// option 1: get a reference to the iframe element:
var iframeElem = document.getElementById('iframe1Id');
// update the element's src:
iframeElem.src = "page.html";
// option 2: get a reference to the iframe's window object:
var iframeWindow = window.iframe1Name;
// update the iframe's location:
iframeWindow.location.href = "page.html";
</script>
Let's review your code:
parent.document.getElementById(id).src = parent.document.getElementById(id).src;
This works if executed from within the iframe, provided you use the correct id. You may want to use a debugger to verify that parent.document.getElementById(id) returns a reference to the correct element, and check your console to see if any exceptions are being thrown (try hitting F12). Since you didn't post your full code (including markup) there's no way I can to think of to tell what the issue is here.
Debugging tips:
check parent.location.href to make sure you are accessing the window you think you are,
check parent.document.getElementId(id) to make sure that you get an element object (as opposed to null or undefined),
check parent.document.getElementById(id).tagName to make sure you are using the correct ID (tagName should === "IFRAME")
This line:
parent.getElementById(id).location.reload();
has two problems:
getElementById() is a function of document, but it is being called from parent which is a window object, and
location is a property of a window object. You are trying to access the iframe element's location property, which does not exist. You need a reference to the iframe's window, not its element.
Besides the name method, there are other ways to get the iframe's window object:
document.getElementById('iframeId').contentWindow; // for supported browsers
window.frames["iframeName"]; // assumes name property was set on the iframe
window.frames[i]; // where i is the ordinal for the frame
If changing the src of the iframe element is not working for you, these other fixes might:
parent.document.getElementById(id).contentWindow.location.reload();
or
parent.frames["yourIframeName"].location.reload(); // requires iframe name attribute
or
parent.frames[0].location.reload(); // frames of immediate parent window
or
top.frames[0].location.reload(); // frames of top-most parent window
Caution: If using the name method be careful not to use a common value for name, like "home", for example, as it conflicts with a FireFox function called home() and so Firefox will not automatically create a reference to an iframe's window if it is named home. The most reliable method is probably to use window.frames[] as I believe that has been around for a long time (works in FF / Chrome / Safari / IE6+ (at least))
A more in-depth (but pretty minimal) example follows, tested in Chrome, FF, and IE:
File #1: frametest.html (the parent window)
<!DOCTYPE html>
<html>
<body>
<iframe id="frame1Id" name="frame1Name" src="frame1.html"></iframe>
<iframe id="frame2Id" name="frame2Name" src="frame2.html"></iframe>
</body>
</html>
File #2: frame1.html (frame 1's src)
<!DOCTYPE html>
<html>
<body>
FRAME 1
<script>
document.body.style.backgroundColor="#ccc";
setTimeout(function(){document.body.style.backgroundColor="#fff";},100);
document.write(new Date());
</script>
<input type="button" onclick="parent.document.getElementById('frame2Id').src=parent.document.getElementById('frame2Id').src;" value="Refresh frame 2 by ID"/>
<input type="button" onclick="parent.frame2Name.location.reload();" value="Refresh frame 2 by Name"/>
</body>
</html>
File #3: frame2.html (frame 2's src)
<!DOCTYPE html>
<html>
<body>
FRAME 1
<script>
document.body.style.backgroundColor="#ccc";
setTimeout(function(){document.body.style.backgroundColor="#fff";},100);
document.write(new Date());
</script>
<input type="button" onclick="parent.document.getElementById('frame1Id').src=parent.document.getElementById('frame1Id').src;" value="Refresh frame 2 by ID"/>
<input type="button" onclick="parent.frame1Name.location.reload();" value="Refresh frame 2 by Name"/>
</body>
</html>
This example demonstrates how to define and manipulate iframes by id and by name, and how to affect one iframe from within a different iframe. Depending on browser settings, origin policy may apply, but you already said that your content was all from the same domain so you should be OK there.

obtain reference to _blank target window on form submit

I have a form that is opening a new window on submit:
<form id="form-id" target="_blank">
I want to access the newly created window via javascript, without manually generating a unique name for target, and without resorting to an alternative method for opening the window.
It seems like there has to be an easy way of doing this but I wasn't able to find one that will work in my specific situation.
Instead of _blank then you can use name your new window.
<form id="form-id" target="newName">
Then you can use it in JS by doing:
var newWindow = window.open(null, 'newName');
I'm not 100% sure this works in all browsers, but Firefox seems to set window.opener when a target attribute on an <a> or <form> causes a new window to open. Thus, you can go the other direction and find the original window from the new one (assuming you control the code there; if not, well I can't imagine you could do much with the window reference anyway).
Of course one of the things the code in the new window can do is call a function in the old window, passing in its own window reference.
Thus, specifically, if you have:
<form action=whatever target=_blank>
on the original page, then the page that ends up in the newly-opened window can do this:
<head>
<script>
if (window.opener) {
window.opener.announceWindow( window );
}
</script>
That assumes announceWindow() is a function on the original page, something perhaps like:
function announceWindow( win ) {
// do stuff with "win", a newly-opened window
}

Javascript activex dynamic loading

I have the following question:
I am trying to use a dwf viewer application, this is backuped by an activex that permits to view dwf files when the plugin is installed.
Usually one would use this plugin like this:
<object
classid = "clsid:A662DA7E-CCB7-4743-B71A-D817F6D575DF"
codebase = "http://www.autodesk.com/global/dwfviewer/installer/DwfViewerSetup.cab#version=6,0,0,200"
ID = "Eview"
width = "500"
height = "500"
border="0"></object>
then just call functions like this:
Eview.Viewer.ExecuteCommand("BLACKANDWHITE");
etc..
The thing is I am now creating the object in an Iframe by server side:
<iframe id="dwfFrame" name="dwfFrame" src="plot.aspx" width="100%" height="100%" onload="initDWF()"/>
in plot.aspx I write the dynamic dwf, and then when loading the iframe, the activex is opened and the dwf shown correctly.
// Now output the resulting DWF.
OutputReaderContent(Response, byteReader);
The problem is on my page I am unable to make Javascript calls cause I do not have a reference to the object, I tried issuing them to the Iframe but it doesn't work. Like this:
dwfViewer = document.dwfFrame;
dwfViewer.Viewer.ExecuteCommand("BLACKANDWHITE");
dwfViewer.ExecuteCommand("BLACKANDWHITE");
I beleive this is because the iframe is not the instancied activex object, is there anyway I could get ahold of this object so I can work on it?
Try:
var dwfFrameDoc = parent.dwfFrame.document;
var dwfViewer = dwfFrameDoc.getElementById('Eview');
I don't play around with multiple frames too often, but that is how you would address another frame. It shouldn't matter that the frame in question is an iframe. Each frame has its own window object. The document is a property of that object. parent refers to the parent of the current window or to itself if it is already the top level.
document.dwfFrame would get you the element whose id is dwfFrame, which is not the same as the window object of the iframe. Even if it were, doing dwfViewer.ExecuteCommand('BLACKANDWHITE'); would try to call ExecuteCommand as a method of the iframe's window, not the viewer object.

How to call javascript function inside an adjacent iframe

I have an html page where I have this layout essentially:
<html>
<body>
<!-- iFrame A -->
<iframe></iframe>
<!-- iFrame B -->
<iframe></iframe>
</body>
</html>
In IFRAME "B", I'd like to call a js function in IFRAME "A", which will ultimately change the window.location property and redirect the page. I have jquery at my disposal as well, but have been unable to figure out a way of calling something in that adjacent frame.
Any suggestions?
Assuming everything is on the same domain, and you have two iframes with ids "iframe-a" and "iframe-b", with jQuery in the parent:
In frame A:
function foo() {
alert("foo from frame A");
}
From frame b:
window.parent.$("#iframe-a")[0].contentWindow.foo();
And you should see "foo from frame A" get alerted.
In some browsers, the window.frames array is only populated if the frames are named, rather than having only an ID
If the frames are named and the content are from the same origin (domain, port, protocol), then
window.frameb.functionName() will trigger the function in standard javascript. See other answer(s) for jQuery version
Use window.parent to get the parent (the main window) then use window.frames on the parent window to get frame B. From there call your function.

Categories