reptile7's JavaScript blog
Wednesday, May 24, 2017
 
Document Son of Iframe
Blog Entry #374

Bringing back my <iframe src="some_file.html"> demos was in general a bit of a chore but not difficult. Some cases were tricky, however, in particular those that themselves make use of an external text resource, for example:
(1) the showModalDialog( ) demo of Blog Entry #184, which now calls on a document fragment appearing later in the entry source;
(2) the Ajax demo of Blog Entry #217, which now accesses an XML element planted in a preceding entry.

The Nikki's Diner Example discussed in Blog Entries #261 and #262 loads <select>-ed .htm files into a common space on the page. In the Calling Dr. Iframe section of Blog Entry #262 I talk up the iframe as the obvious choice of elements to replace the layer placeholder in Netscape's original code. Prior to restoring my lost dinerdemo.html demo for the example I mused, "If I'm going to spend all this time talking about iframes, it would be kind of dishonest on my part to trade in the demo's iframe for a div, wouldn't it? Is there some way I can hold onto the iframe container?"

An iframe is a type of frame, and a frame is a type of window. I knew that the frames[ ] collection of the window object accesses <iframe>s as well as <frame>s. I thought back to HTML Goodies' JavaScript Primers #12 and its code for building a document from scratch in a var OpenWindow = window.open("", "newwin", "height=300,width=300"); window - I ought to be able to do that with an iframe, right?

I picked up the dinerdemo.html <iframe> and
(a) set its src attribute to an empty string and
(b) changed its id="menu" attribute to a name="menu" attribute because window.frames["iframeName"] returns an iframe as an [object Window] whereas window.frames["iframeID"] returns an iframe as an [object HTMLIFrameElement] (vide infra).

<iframe name="menu" width="410" height="425" style="position:relative;left:50px;" src="" frameborder="0">It seems that your browser does not support iframes. Please call Nikki's Diner at 123-4567 for today's specials.</iframe>

I then crafted a new showSpecials( ) function that writes out an iframe document template to which pre-arrayed day-specific data is added via an n index.

var bgcolorArray = ["#bbee99", "#6699ff", "#ee99ee", "#22bbcc", "#ffbb00", "#66ffff", "#ee7777"];
var dayArray2 = ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"];
var entreeArray = ["Curried Tofu with BeanSprouts and Raisins", "Tofu and Mushroom Pie", "Tofu, Artichoke, and Asparagus Surprise", "Tofu and Leek Tart", "Tofu and Mandarin Torte", "Tofu Burgers with Endive Salad", "Tofu and Parsnip Casserole"];
...

function showSpecials(n) {
    window.frames["menu"].document.open( );
    window.frames["menu"].document.write("<html><head><title>Specials<\/title>");
    window.frames["menu"].document.write("<style type='text/css'>body { background-color:" + bgcolorArray[n] + "; } h1, h2 { text-align:center; }<\/style>");
    window.frames["menu"].document.write("<\/head><body><hr />");
    window.frames["menu"].document.write("<h1>" + dayArray2[n] + "<\/h1><hr />");
    window.frames["menu"].document.write("<h2>Entrees<\/h2>");
    window.frames["menu"].document.write("<p>" + entreeArray[n] + "<\/p>");
    ...
    window.frames["menu"].document.close( ); }
showSpecials(0);


XHTML 1.0 deprecates the name attribute of the iframe element. The contentWindow attribute of the HTMLIFrameElement interface returns the [object Window] associated with an iframe so we can revert to the id="menu" identifier if we recast the window.frames["menu"] references as window.frames["menu"].contentWindow references.

The HTML Goodies JavaScript Primers #12 Script does not include document.open( ) and document.close( ) operations.
• An explicit document.open( ) call can be used to clear an already-open document stream with some browsers but as far as I know is unnecessary under other circumstances. Joe isn't clearing anything and I'm not either, and therefore we don't need to open( ) our respective documents, but doing so strikes me as 'good form', so I put a window.frames["menu"].document.open( ); command in there.
• An open document stream is a work in progress in that you can render what you've got so far but the loading process isn't finished until the document is close( )d. It's not really necessary for Joe and me to close( ) our respective documents, but in my case the main page's loading progress indicator spins indefinitely when using Firefox or Google Chrome if I don't do so, so I do so.
(For more on this topic, see Stack Overflow's "Are document.open and document.close necessary?" page.)

How does my plan work in practice? Check it yourself.

An alternative, more efficient approach is possible. With an eye on getting rid of those document.write( ) commands, I discovered that, its readonly status notwithstanding, the HTMLIFrameElement contentDocument attribute can be used to append freshly created elements to the head and body of an iframe document.

window.frames["menu"].onload = function ( ) { /* This listener is necessary when using Firefox. */
    iframeDoc = window.frames["menu"].contentDocument;
    sRules = document.createElement("style");
    sRules.type = "text/css";
    sRules.textContent = "h1, h2 { text-align:center; }";
    iframeDoc.getElementsByTagName("head")[0].appendChild(sRules);
    iframeDoc.body.appendChild(document.createElement("hr"));
    heading1 = document.createElement("h1");
    iframeDoc.body.appendChild(heading1);
    ... }


With a new document template in place, we can shrink the showSpecials( ) function to only those operations that set values that change from day to day.

function showSpecials(n) {
    iframeDoc.body.style.backgroundColor = bgcolorArray[n];
    heading1.textContent = dayArray2[n];
    ... }


Other related cases

(1) As part of a window.opener demo in Blog Entry #26, a remote control window loads http://www.htmlgoodies.com/ via an object element into a div on the main page, as though the div has a src capability.

zork.document.write("<input type='button' value='Click here to load HTML Goodies into the opener pane' onclick='window.opener.document.getElementById(\"openerDiv\").innerHTML = \"<object width=100% height=193 data=http://www.htmlgoodies.com/>Oops, data loading did not occur.<\/object>\";'>");

(2) The fram1.html-fram5.html frameset/frames demo in the Referencing a Window section of Blog Entry #18 would certainly seem to require the use of external files but I figured out a way to code the whole shebang in the main document. An outer iframe serves as the fram1.html top window:

<iframe name="fram1.html" width="100%" height="480" src="" frameborder="1"></iframe>

The fram2.html and fram3.html frame windows are created via:

window.frames["fram1.html"].document.write("<frameset cols='70%,30%'>");
window.frames["fram1.html"].document.write("<frame name='fram2.html' src=''>");
window.frames["fram1.html"].document.write("<frame name='fram3.html' src=''>");
window.frames["fram1.html"].document.write("<\/frameset>");


The fram2.html and fram3.html windows are then respectively accessed with:

window.frames["fram1.html"].window.frames["fram2.html"] // and
window.frames["fram1.html"].window.frames["fram3.html"]
/* window.frames["fram1.html"] is the parent of window.frames["fram2.html"] and window.frames["fram3.html"]. */


The fram4.html and fram5.html frame windows are created

window.frames["fram1.html"].window.frames["fram2.html"].document.write("<frameset rows='30%,70%'>");
window.frames["fram1.html"].window.frames["fram2.html"].document.write("<frame name='fram4.html' src=''>");
window.frames["fram1.html"].window.frames["fram2.html"].document.write("<frame name='fram5.html' src=''>");
window.frames["fram1.html"].window.frames["fram2.html"].document.write("<\/frameset>");


and accessed

window.frames["fram1.html"].window.frames["fram2.html"].window.frames["fram4.html"] // and
window.frames["fram1.html"].window.frames["fram2.html"].window.frames["fram5.html"]
/* window.frames["fram2.html"] is the parent of window.frames["fram4.html"] and window.frames["fram5.html"]. */


in an analogous manner.
I'll briefly discuss the restoration of code samples and dead links in my posts in the next entry.

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)