Cross-domain iFrame communication and IE
For an upcoming project I needed to be able to circumvent the same-origin policy where two iframes are located on separate domains. This is in place for a very good reason, but there are always times when the rules need to be broken.
In a nutshell, I had page A (hosted on domain X) containing an iframe pointing to page B (hosted on domain Y). When the user performs a certain action on page B, I needed to send some data to a script on page A - let's say a function foo().
window.name transport
Because the pages are hosted on different domains, trying to access the function via window.parent.foo will throw a security error. Searching for workarounds, the window.name transport seemed a likely solution. This involves adding data to the window's name property, which unlike other properties is persistent over page reloads. This fact, combined with some redirection shenanigans to avoid the policy restrictions, would probably have done the trick.
Besides it being a bit complex, the redirection involved has a nasty side-effect in Internet Explorer. The default "navigation" sound that plays whenever you click a link? That happens when an iframe's window.location is changed, too, resulting in a sequence of nasty "machine gun" noises. Not good at all.
location.hash
So, I changed tactic and tried passing the data to the parent window's location.hash property (although it can't be read by the child window, it can be written to). This wouldn't force a page refresh as the hash value alone has changed. To detect the state change and pass the data to foo(), I added a combination of the onhashchange event for browsers that support it and a timer for those that don't. All worked fine - except IE still triggers the navigation sound, even though the page hasn't changed.
ActiveX (urgh)
Moving on, I came across a neat idea at Grack, which used an ActiveX control to disconnect the iframe from the main page, thus surpressing the audio playback. Unfortunately I couldn't get this to work (and resulted in crashing my PC by spawning an infinite loop of new windows).
Three's a crowd, but it works
Finally, inspiration hit!
On page B, whenever the user performed the required action, I created a new iframe dynamically. This iframe is hidden to the user, and the "src" attribute is set before attaching the iframe to the document. This prevents the audio playback in IE.
The iframe's "src" attribute is pointed to a new page, C, which is hosted on the same domain as page A. When setting the attribute, I attach the data to the hash property of the URL. When page C loads, it can extract the data from the hash.
The final part relies on the fact that page A and C are hosted on the same domain. Even though script on page C can't access information about its parent window B, it can access its grand-parent window. So from within page C we call window.parent.parent.foo();, passing the extracted data. Voila!
Of course, this all hangs on the ability to host this third page on the same domain as the originating page. My guess is that if you aren't able to add this page, you're stuck with those sounds for good.
Page A (domain X):<html>
<head>
<script type='text/javascript'>
var foo=function(data){
console.log(data);
};
</script>
</head>
<body>
<iframe src='http://domainY.com/pageB'></iframe>
</body>
</html>
Page B (domain Y):
<html>
<head>
<style type='text/css'>
#frame {border:none;width:1px;height:1px}
</style>
<script type='text/javascript'>
window.onload=function(){
var x=0;
var iframe;
document.onclick=function(){
if (iframe){
iframe.parentNode.removeChild(iframe);
}
iframe = document.createElement('iframe');
iframe.id='frame';
iframe.src="http://domainX.com/pageC#"+(++x);
document.body.appendChild(iframe);
};
};
</script>
</head>
<body>
</body>
</html>
Page C (domain X):
<html> <head> <script type='text/javascript'> window.parent.parent.foo(window.location.hash.replace(/^#/,'')); </script> </head> </html>
Øyvind Sean Kinsey on
Why don't you take a look at easyXDM?`
It works a lot better than what you suggest here
It even provides RPC, just take a look here
Øyvind Sean Kinsey on
The last link should be http://consumer.easyxdm.net/current/example/methods.html
Graham on
Wow Øyvind, howcome I hadn't heard of this before? I knew someone would have a far better solution than my quick 'n' dirty fix, but I didn't expect such a fully-featured lib. I haven't taken a proper look yet but it looks excellent.
Øyvind Sean Kinsey on
Well, I guess I'm better at programming than marketing
But I'm working on it, for instance I've got an article up on Script Junkie about it, and I believe it will get some more coverage in the future...