Why does the `onload` event not fire on nested iframes with framebusting? - javascript

Consider the following three pages.
Foo.html is opened locally in the browser, and so has a URL with prefix file:///.
Bar.html is in the same directory has Foo.html.
Bar2.html lives in /var/www and I am running Apache on localhost.
Foo.html
<html>
<head>
<script>
foo = function() {
alert("frame changed");
};
</script>
</head>
<body>
<iframe width="200" height="300" src="Bar.html" id="my-iframe" onLoad="foo" />
</body>
</html>
Bar.html
<html>
<body>
<iframe width="200" height="300" src="http://localhost/Bar2.html" id="my-iframe" />
</body>
</html>
Bar2.html
<html>
<head>
<script>
if (top.location != self.location){
parent.location = self.location;
}
</script>
</head>
<body>
<button type="button" onclick="document.location.href='http://bing.com'">Hello World</button>
</body>
</html>
When Foo.html is loaded in Firefox, by running firefox /path/to/Foo.html on the command line, the frame busting code in Bar2.html breaks out of Bar.html. At this point, the user gets an alert frame changed.
When I click the button, the iframe changes (the button vanishes), but I do not get an alert.
Why is the onLoad not firing the second time when the page changes?

The issue lays in the fact that when Bar2.html is being loaded by the iframe in Bar.html this condition is false
if (top.location != self.location)
As a result, when Bar.html is loading Bar2.html this is called
parent.location = self.location;
Which issues a redirect in the page and cancels the affect of the onload event since the page technically never finished loading.

Your script
if (top.location != self.location){
parent.location = self.location;
}
will run on Bar2.htm and change the location of its parent (previously Bar.htm). Then the alert comes.
Then, the script will run in the parent (previously Bar.htm) but top.location is still not equal to self.location . (top.location is now equal to Foo.htm and self.location is equal to Bar.htm ) so when you click the button, the parent page has been redirected to Bar2.htm . Meaning the alert code and the iframe is gone.

Related

Get Back Button to work on parent page when iframe is involved

I am working on a legacy app that has an iframe involved. The back button is working on the iframe and I need it to bypass the iframe and work on the parent window only.
Here is a dumbed down version of the issue and description of what I know.
the main page "index.html" has an iframe that is being added via javascript. It loads a.html, makes an ajax call that then does a window.location = "b.html" At this point if you use the back button it essentiallys makes the iframe go back to a.html and then redirects to b.html so you are effectively stuck on the page. If I remove the ajax call and do an window.location on load everything works ok. However given the architecture and what happen on the page I can't remove the Ajax call from the picture.
Here is the code I am looking at, let me know your thoughts on how to solve this issue. Also I should mention in Chrome 41 this isn't an issue, however the newer chrome 48 and 49 it is an issue. I tried history.replaceState but wasn't able to figure out a way to use it in this situation that made things work.
index.html
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
</head>
<body>
hello world!
<div id="iframeContainer"></div>
<script>
$(function () {
var newIframe = document.createElement('iframe');
newIframe.src = "a.html";
newIframe.id = "A";
document.getElementById("iframeContainer").appendChild(newIframe);
});
</script>
</body>
</html>
a.html
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
</head>
<body style="background-color:#F00;">
<script>
$(function(){
$.ajax({
url:"b.html",
complete:function(){
window.location="b.html";
}
});
});
</script>
</body>
</html>
b.html
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
</head>
<body style="background-color:#00F;">
<script>
$(function(){
})
</script>
</body>
</html>
This is only possible in HTML5 compatible browsers, and it would go something like this..
This goes in the child frame..
// catch the back button click.
window.onpopstate = function(event) {
// make the parent window go back
top.history.back();
};
This also only works if both frames are in teh same domain.

Chrome JavaScript console is null after submitting the page

This was unexpected. I use Chrome as my primary development browser and make generous use of "console.log" (way better than alerts!)
Anyway, I have a page inside an IFrame (for uploading images). That page includes scripts that often write out to the console window (console.log) for tracking purposes. The first time the parent page submits the embedded page via script, everything goes smoothly. If I, however, then attempt to submit the page a second time I get the error ...
Uncaught TypeError: Cannot call method 'log' of null
All of a sudden it seems that the console is no longer available. If I replace it with an alert the alert box appears as expected, but the page no longer submits either.
Has anybody experienced anything like this before?
I want to thank folks for their responses. I did not include any code in the OP because it is an extensive script and parsing out an "example" of what I was attempting to do so that it wasn't too tedious to go through would likely strip out any relevancy.
I am posting, however to say that I did discover the problem.
I have PageA which contains an IFrame which is in turn loaded with PageB.
<html>
<head><title>PageA</title></head>
<body>
<IFrame src="PageB" name="frame1" id="frame1"></IFrame>
</body>
</html>
PageB contains a function that needs to be called from PageA when a button is clicked.
<!-- PageB -->
<html>
<head><title>PageB</title></head>
<body>
<form id="form1" name="form1" >
</form>
<script>
var SubmitForm = function(){
var $form = $("form[id$='form1']");
$form[0].submit(); // this was not firing
console.log("some log output"); // this was throwing an error
};
</script>
</body>
</html>
<!-- PageA -->
<html>
<head><title>PageA</title></head>
<body>
<IFrame src="PageB" name="frame1" id="frame1"></IFrame>
<button onclick="submitIFrameForm()">Submit</button>
<script>
var frameWindow = frames["frame1"];
var frameForm = frameWindow.SubmitForm;
function submitIFrameForm(){
frameForm();
};
</script>
</body>
</html>
THE PROBLEM
When PageA first loads, the IFrame is loaded with PageB and the script in PageA makes it's reference (frameForm) to the "SubmItForm()" function on PageB. When I click on the submit form button in PageA, PageB is submitted back to the server. No problem ...
However when PageB is submited it is UNLOADED from the window. So when I click on the
submit button in PageA a second time, although PageB may reload it is a different instance of the page. Therefore all the variables which reference the original PageB are now pointing to nothing ... hence the window that console was referencing no longer exists, so the "log" method cannot run.
THE FIX
Instead of creating a global reference to the contents of the IFrame, we must re-establish this reference to the function each time the button is clicked. (Since the IFrame is a member of PageA we do not need to re-establish the IFrame reference).
<!-- PageA -->
<html>
<head><title>PageA</title></head>
<body>
<IFrame src="PageB" name="frame1" id="frame1"></IFrame>
<button onclick="submitIFrameForm()">Submit</button>
<script>
var frameWindow = frames["frame1"];
function submitIFrameForm(){
frameWindow.SubmitForm(); // move the reference to the click event handler
};
</script>
</body>
</html>
I hope that this made sense and that it helps someone out there. I get caught up on this kind of stuff constantly.

Can I communicate between two local html files using javascript?

I have two local .html files in the same folder. One page opens a window with the other page, and attempts to call a function in the newly opened window. However, the function call fails, and I get this in the console:
Unsafe JavaScript attempt to access frame with URL file:///***/A.html from frame with URL file:///***/B.html. Domains, protocols and ports must match.
This happens on both Chrome and Webkit (Mac). Is there any way I can either: disable the cross-domain checks for the file:// protocol, or call a javascript function in a different local file?
You can use window.postMessage to do something like this:
The initial window html file:
<!DOCTYPE html>
<html>
<head>
<script>
var otherWindow;
function openOther() {
otherWindow = window.open("other.html", "otherWindow");
}
function otherFunc() {
otherWindow.postMessage("otherFunc", "*");
}
</script>
</head>
<body>
<div onclick="openOther()">Open the other window</div>
<div onclick="otherFunc()">Call the other window's function</div>
</body>
</html>
Html for the second window:
<!DOCTYPE html>
<html>
<head>
<script>
window.addEventListener("message", function(event) {
alert("The other window's function executed.");
}, false);
</script>
</head>
<body>
<div>This is the other window.</div>
</body>
</html>
Here's a good reference for window.postMessage.

changing iframe url changes parent window url

i'm using following page to display content of a url in a iframe and changing it based on input value .
<html>
<head>
<script type="text/javascript">
function changeUrl()
{
var url=document.getElementById('browseurl').value;
if(url!="")
{
if(url.indexOf("http")==-1)
{
url="http://"+url;
}
document.getElementById('browserWnd').src=url;
}
}
</script>
</head>
<body>
<div >
<span>Url</span>
<input id="browseurl" name="browseurl" type='textbox' />
<input id="browse" type='button' value="changeurl" onclick="changeUrl()" />
</div>
<iframe id="browserWnd" src="http://www.coolmath.com/" height="700" width="625"></iframe>
</div>
</body>
</html>
my problem is browsing some inner pages of an url loaded in iframe changes the parent window url instead of loading in iframe ...
for ex http://www.coolmath.com/ load in iframe but while browsing some links loads the entire page in parent window.
From www.coolmath.com:
if (window.self != window.top) ...
meaning the site activly escapes being framed.
You may notice that even something like this <iframe src='http://www.coolmath-games.com/0-fraction-splat/index.html'></iframe> results in the same. This is a technique called frame-busting. It's in their page's code:
<script>
<!-- Hide Script
if (top.location != self.location) {
top.location = self.location
}
//End Hide Script-->
</script>
If you have a server, that can respond with a HTTP/1.1 204 No Content header, you may be able to "deactivate" this frame buster as described here.

Child of window.open doesn't call function in parent window

parent.html
<html>
<head>
<script type="text/javascript">
function openWin()
{
myWindow=window.open('child.html','','width=200,height=100');
}
function callback(){
alert("test");
}
</script>
</head>
<body>
<input type="button" value="Open 'myWindow'" onclick="openWin()" />
</body>
</html>
child.html
<html>
<head>
<script type="text/javascript">
window.opener.callback();
</script>
</head>
<body>
</body>
</html>
And the problem is that the child page calls parent's page callback function in FF, IE but not in Chrome.
Any idea ?
Problem happens because of Chrome security error. Domains, protocols and ports must match. But it also happens when page is open from local files system.
Open your page from server, it should be without any problems.
The problem might be the way how chrome run javascript. Chrome sometimes run the js so fast and early and even the DOM is not ready for manipulation. Try this in your child.html
<script type="text/javascript">
setTimeout(function(){window.opener.callback();}, 100);
</script>
I am not sure if this is the exact problem for you, I encountered this problem with jQuery.ready() on chrome.

Categories

Resources