14.3 Including External HTML Content
NN 6, IE 5
14.3.1 Problem
You want to combine (include)
content from another HTML document into a single document on the
page.
14.3.2 Solution
Put the external content into an
iframe element, and disguise the
iframe so that it looks to be part of the regular
document flow. Here is an example of an iframe
element that blends seamlessly into a plain HTML page:
<iframe id="myFrame" frameborder="0" vspace="0" hspace="0" marginwidth="0"
marginheight="0" width="100%" src="external.html" scrolling="no"
style="overflow:visible"></iframe>
To size the iframe element correctly, you must
wait for the content to load, and then use scripts to find out the
content height. The following function is invoked by the
onload event handler of the page, which passes the
ID of the iframe to be adjusted:
function adjustIFrameSize(id) {
var myIframe = document.getElementById(id);
if (myIframe) {
if (myIframe.contentDocument && myIframe.contentDocument.body.offsetHeight) {
// W3C DOM (and Mozilla) syntax
myIframe.height = myIframe.contentDocument.body.offsetHeight;
} else if (myIframe.Document && myIframe.Document.body.scrollHeight) {
// IE DOM syntax
myIframe.height = myIframe.Document.body.scrollHeight;
}
}
}
For the example iframe element, the
onload event handler is:
onload = "adjustIFrameSize('myFrame');"
The user will see the page rearrange itself when the
iframe resizes.
14.3.3 Discussion
For the resizing script to work, both the host and external pages
must be served from the same domain and server, to allow the script
to dive into the otherwise protected realm of the
iframe's content. Notice that the
reference to the content of the iframe element is
not as direct as you might be accustomed to from working with
framesets. If you begin with a reference to the
iframe element, you then need the DOM-compatible
syntax to reach the document object within that
frame: Document for IE and
contentDocument for W3C DOM-based browsers.
References to those documents point to the root document containing
the content visible in the frame. From there, you can reach the
body or other elements within the document. In the
case of the embedded iframe, the total height of
the rendered content (unknown until it loads) governs the ultimate
height of the iframe.
Be aware that hyperlinks in the
iframe's content will load their
destination documents into the iframe, unless the
targets of those links are set to _top. Also, any
new content loaded into the iframe that is not the
same height as the original either leaves a gap (too short) or is
clipped (too long). The only fix is to resize the
iframe for the new content.
To prepare the iframe for automatic resizing, you
must bind an onload event handler to the
iframe element. While a hardwired
onload event handler or event property assignments
may not work for the iframe element in Netscape 6
or later, more modern event binding does. Even so, you need to branch
for the event-model specific ways of binding elements. Revise the
function shown in the Solution to bind the events as follows:
function adjustIFrameSize(id) {
var myIframe = document.getElementById(id);
if (myIframe) {
if (myIframe.contentDocument && myIframe.contentDocument.body.offsetHeight) {
// W3C DOM (and Mozilla) syntax
myIframe.height = myIframe.contentDocument.body.offsetHeight;
} else if (myIframe.Document && myIframe.Document.body.scrollHeight) {
// IE DOM syntax
myIframe.height = myIframe.Document.body.scrollHeight;
}
// bind onload events to iframe
if (myIframe.addEventListener) {
myIframe.addEventListener("load", resizeIframe, false);
} else {
myIframe.attachEvent("onload", resizeIframe);
}
}
}
The events invoke a function that processes the event to pass the
desired information (the ID of the iframe) back to
the adjustIFrameSize(
) function:
function resizeIframe(evt) {
evt = (evt) ? evt : event;
var target = (evt.target) ? evt.target : evt.srcElement;
// take care of W3C event processing from iframe's root document
if (target.nodeType = = 9) {
if (evt.currentTarget &&
evt.currentTarget.tagName.toLowerCase( ) = = "iframe") {
target = evt.currentTarget;
}
}
if (target) {
adjustIFrameSize(target.id);
}
}
The tricky part is that the onload event fires for
the content document of the iframe in W3C DOM
browsers rather than for the iframe element
directly. Fortunately, the event bubbles up to the containing
iframe, and the W3C DOM event
object's currentTarget property
gives us a reference to the element that is actually processing the
event, regardless of original target. The event bindings are invoked
again in adjustIFrameSize( ) function, but there
is no harm in doing so. If you have some other initializations on the
page that occur in response to the main page's
onload event handler, you can shift these
assignments to that initialization function so they execute only one
time.
14.3.4 See Also
Recipe 9.1 for handling conflicting event models together; Recipe 9.2
for details about the onload event handler.
|