Resizing an iframe based on content
https://developer.mozilla.org/en/DOM/window.postMessage
window.postMessage()
window.postMessage is a method for safely enabling cross-origin communication. Normally, scripts on different pages are only allowed to access each other if and only if the pages which executed them are at locations with the same protocol (usually both http), port number (80 being the default for http), and host (modulo document.domain being set by both pages to the same value). window.postMessage provides a controlled mechanism to circumvent this restriction in a way which is secure when properly used.
Summary
window.postMessage, when called, causes a MessageEvent to be dispatched at the target window when any pending script that must be executed completes (e.g. remaining event handlers if window.postMessage is called from an event handler, previously-set pending timeouts, etc.). The MessageEvent has the type message, a data property which is set to the string value of the first argument provided to window.postMessage, an origin property corresponding to the origin of the main document in the window calling window.postMessage at the time window.postMessage was called, and a source property which is the window from which window.postMessage is called. (Other standard properties of events are present with their expected values.)
The iFrame-Resizer library uses postMessage to keep an iFrame sized to it's content, along with MutationObserver to detect changes to the content and doesn't depend on jQuery.
https://github.com/davidjbradshaw/iframe-resizer
jQuery: Cross-domain scripting goodness
http://benalman.com/projects/jquery-postmessage-plugin/
Has demo of resizing iframe window...
http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
This article shows how to remove the dependency on jQuery... Plus has a lot of useful info and links to other solutions.
http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/
Barebones example...
http://onlineaspect.com/uploads/postmessage/parent.html
HTML 5 working draft on window.postMessage
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
John Resig on Cross-Window Messaging
http://ejohn.org/blog/cross-window-messaging/
If you do not need to handle iframe content from a different domain, try this code, it will solve the problem completely and it's simple:
<script language="JavaScript">
<!--
function autoResize(id){
var newheight;
var newwidth;
if(document.getElementById){
newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
}
document.getElementById(id).height= (newheight) + "px";
document.getElementById(id).width= (newwidth) + "px";
}
//-->
</script>
<iframe src="usagelogs/default.aspx" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>
We had this type of problem, but slightly in reverse to your situation - we were providing the iframed content to sites on other domains, so the same origin policy was also an issue. After many hours spent trawling google, we eventually found a (somewhat..) workable solution, which you may be able to adapt to your needs.
There is a way around the same origin policy, but it requires changes on both the iframed content and the framing page, so if you haven't the ability to request changes on both sides, this method won't be very useful to you, i'm afraid.
There's a browser quirk which allows us to skirt the same origin policy - javascript can communicate either with pages on its own domain, or with pages it has iframed, but never pages in which it is framed, e.g. if you have:
www.foo.com/home.html, which iframes
|-> www.bar.net/framed.html, which iframes
|-> www.foo.com/helper.html
then home.html
can communicate with framed.html
(iframed) and helper.html
(same domain).
Communication options for each page:
+-------------------------+-----------+-------------+-------------+
| | home.html | framed.html | helper.html |
+-------------------------+-----------+-------------+-------------+
| www.foo.com/home.html | N/A | YES | YES |
| www.bar.net/framed.html | NO | N/A | YES |
| www.foo.com/helper.html | YES | YES | N/A |
+-------------------------+-----------+-------------+-------------+
framed.html
can send messages to helper.html
(iframed) but not home.html
(child can't communicate cross-domain with parent).
The key here is that helper.html
can receive messages from framed.html
, and can also communicate with home.html
.
So essentially, when framed.html
loads, it works out its own height, tells helper.html
, which passes the message on to home.html
, which can then resize the iframe in which framed.html
sits.
The simplest way we found to pass messages from framed.html
to helper.html
was through a URL argument. To do this, framed.html
has an iframe with src=''
specified. When its onload
fires, it evaluates its own height, and sets the src of the iframe at this point to helper.html?height=N
There's an explanation here of how facebook handle it, which may be slightly clearer than mine above!
Code
In www.foo.com/home.html
, the following javascript code is required (this can be loaded from a .js file on any domain, incidentally..):
<script>
// Resize iframe to full height
function resizeIframe(height)
{
// "+60" is a general rule of thumb to allow for differences in
// IE & and FF height reporting, can be adjusted as required..
document.getElementById('frame_name_here').height = parseInt(height)+60;
}
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>
In www.bar.net/framed.html
:
<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>
<script type="text/javascript">
function iframeResizePipe()
{
// What's the page height?
var height = document.body.scrollHeight;
// Going to 'pipe' the data to the parent through the helpframe..
var pipe = document.getElementById('helpframe');
// Cachebuster a precaution here to stop browser caching interfering
pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();
}
</script>
Contents of www.foo.com/helper.html
:
<html>
<!--
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content
-->
<body onload="parentIframeResize()">
<script>
// Tell the parent iframe what height the iframe needs to be
function parentIframeResize()
{
var height = getParam('height');
// This works as our parent's parent is on our domain..
parent.parent.resizeIframe(height);
}
// Helper function, parse param from request string
function getParam( name )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
</script>
</body>
</html>