reptile7's JavaScript blog
Thursday, August 23, 2012
I Can't Choose Either, Norah
Blog Entry #262

Welcome back to our discussion of the Nikki's Diner Example: in today's post we move from theory to practice.

showSpecials( ) execution

As it happens, the two example versions do not work equally well - the subsections below detail what I see when using Netscape Communicator 4.61 in the SheepShaver environment.


The dinercss.htm document specifies a width:400px; style declaration for the menulayer div. When the sat.htm file initially loads into the menulayer div, the menulayer display does have a width of 400 pixels - so far, so good.

The initial menulayer display

Upon choosing an other-than-Saturday option from the menu1 selection list - say, the Tuesday option - the corresponding specials/ file (tues.htm) loads into the menulayer block but the width of the block increases to 100%, i.e., the block's width spans the width of the viewport.

The menulayer display upon choosing the Tuesday option

With respect to its identity as a layer, the menulayer block's clip.width property now returns 816. With respect to its identity as a div, the menulayer block's document.ids.menulayer.width style width continues to read 400px, as though the tues.htm content were overflowing the div. Weird, huh? But such are the vicissitudes of working with primitive browsers like Netscape 4.x.

Setting the menulayer clip.width (Netscape did not equip the layer object with a 'normal' width property) to 400 cuts off the right half of the display - the layer width does not shrink to 400 pixels.


There are no problems with this version: as for the dinercss.htm version, the showSpecials( ) function smoothly loads the specials/ files into the specials layer, but the menu layer's width="400" attribute faithfully keeps the layer/display width at 400 pixels. FYI: Netscape 4.x does not support the width attribute for the div element.

Calling Dr. Iframe

With an eye on getting the example to work with modern browsers, the obvious choice of elements to replace the menu layer is an iframe, you know, the thing I used to use for my demos on this blog (including the demo at the end of the post) back when I had EarthLink server space at my disposal. The iframe element has a src attribute for importing an external document and width and height attributes for bounding the imported content. As for the menu layer's left="50" attribute - no standard HTML elements have a left attribute - an iframe can be CSS-offset like any other element.

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

• In the absence of a height setting (the menu layer doesn't have a height attribute), the iframe-supporting browsers on my computer give an iframe a default height of 150 pixels, which is well short of what we want.

• By default, a layer does not have a border whereas an iframe has an inset 2px border. IMO a border neither adds to nor detracts from the display, but you can lose the iframe border with a frameborder="0" attribute if you don't like it.

• If an iframe's src content overflows the iframe viewport, then the browser will automatically equip the iframe with scrollbars so that the user can access the beyond-the-viewport content; you can mandate that an iframe not have scrollbars via a scrolling="no" attribute, but it is generally a good idea to allow for scrollbars in case they are needed. The above width="410" and height="425" settings eliminate content overflow for all of the specials/ pages if the browser's Preferences... default font size is 16px or smaller; push the font size to 18px and you'll get a vertical scrollbar.

• The iframe can be absolutely or relatively positioned, the difference being that in the relative case you also get 8px of default margin-left indentation and in the absolute case you don't.

• Something that is true for modern browsers but not older browsers, and is a bit surprising given that an iframe is a replaced element: if the specials/ pages did not have background colors (they all do, although some of those colors don't go very well with black text), then a #menu { background-color: <color>; } style rule in the main document would impart a background color to the pages. N.B. The pages' paragraphs and h2 headings cannot be styled in this way, but these elements can be styled from the main document with a bit of JavaScript, as we'll see below.

Before moving on:
Quirksmode reports that iframes can be disabled with IE 9, Firefox, and Opera. Upon applying the Firefox and Opera disablements to the above iframe element (as a Mac user I can't tell you how the IE disablement shakes out), I find that
(a) Firefox completely removes the element - both its specials/ src content and its It seems that your browser does not support iframes... content string - whereas
(b) Opera removes the src content and renders the content string, as you would expect.

Oh, in case you were wondering, iframes are not supported by Netscape 4.x.

showSpecials( ) retool

Do we need to use a switch statement to map the user's chosen menu1 option onto its corresponding specials/ file? Nah...

var dayArray = ["sat", "sun", "mon", "tues", "wed", "thurs", "fri"];
function showSpecials(n) {
    var specials = document.getElementById("menu");
    specials.src = "specials/" + dayArray[n] + ".html"; }

Set up a dayArray Saturday-to-Friday array of specials/ day abbreviations, get the menu iframe, concatenate specials/ and dayArray[n] and .html, and assign the resulting string to the src property of the menu/specials iframe object, and you're good to go.

Styling the specials/ text

The diner.htm document applies a tags.P.marginLeft = 50; style statement to the paragraphs of the specials/ files whereas the dinercss.htm document applies a p { margin-left: 10%; margin-right: 10%; } style rule set to those paragraphs; these stylings work as advertised notwithstanding that the specials layer is again a replaced element.

Without any CSS, the specials/ paragraphs get 8px of margin-left indentation. Do they need to be further 'marginized'? Not really, but suppose you wanted to push them rightward by 10 pixels. You could add a p { margin-left: 10px; } style rule to each specials/ document; however, through the magic of the contentDocument attribute of the HTML DOM's HTMLIFrameElement interface, which accesses the src document held by an iframe, we can style the paragraphs in one go from the main document as follows:

function formatIframe( ) {
    var specials = document.getElementById("menu");
    var slideParas = specials.contentDocument.getElementsByTagName("p");
    for (i = 0; i < slideParas.length; i++) slideParas[i].style.marginLeft = "10px"; }

The documents' h2 elements can be scooped up and centered

for (i = 0; i < slideH2s.length; i++) slideH2s[i].style.textAlign = "center";

in an analogous manner.

The formatIframe( ) function should be called whenever a new specials/ document has loaded into the menu iframe; we accordingly trigger the function via an onload="formatIframe( );" iframe element attribute.
(A corresponding document.getElementById("menu").onload = formatIframe; statement is buggy with Opera - there's no offset for the first load but things are OK for subsequent loads - so I encourage you to stick with the element attribute approach.)

Uh-oh - our friends at W3Schools warn:
Note: Internet Explorer 8 (and higher) supports the contentDocument property only if a !DOCTYPE is specified. For earlier versions of IE, use the contentWindow property.
The contentWindow property references a frame|iframe directly as a window object (as opposed to an object implementing the Core DOM's Element interface); regarding the formatIframe( ) function, specials.contentWindow.document would be equivalent to specials.contentDocument. Excepting IE 5.2.3, the contentWindow property is supported by all of the OS X GUI browsers on my computer - Netscape 7 also supports it. The contentDocument and contentWindow members are both now part of the HTML5 HTMLIFrameElement interface.

It subsequently occurred to me that we could access the iframe window and its document in a more basic and general way via the window.frames collection, i.e., window.frames["menu"].document would be equivalent to specials.contentDocument. The frames member is now part of the HTML5 Window interface.

Either the contentWindow approach or the window.frames approach will be fine for most if not all users; however, the conditional below should allow you to reach anyone who falls through the cracks:

if (specials.contentDocument) iframeDocument = specials.contentDocument;
else if (specials.contentWindow) iframeDocument = specials.contentWindow.document;
else if (window.frames) iframeDocument = window.frames["menu"].document;

You're just an object, part 2

The Notes on embedded documents section of the HTML 4.01 Specification shows how to recast an iframe element as an object element.

<object id="menu" width="410" height="425" data="specials/sat.html">sat.html is not available, blah blah blah...</object>

As shown above, the data attribute of the object element plays the role of the src attribute of the iframe element.

Changing the specials.src = "specials/" + dayArray[n] + ".html"; showSpecials( ) statement to = "specials/" + dayArray[n] + ".html"; should be all we need to do to use the menu object with the Nikki's Diner Example. In the event, I find that Chrome and Safari will not write the property (i.e., you're stuck with the Saturday display); Firefox and Opera will write it but the file-to-file transitions are less smooth than when writing the specials.src property for an iframe. So for importing the specials/ documents into the main document, an iframe is clearly the way to go.


January 2017 Update: The restored demo below does not in fact leverage an external set of specials/*.html files but instead document.write( )s the *.html contents from scratch - I refer you to the source of this page for the details.

Welcome to Nikki's Diner!

Nikki's Diner is the best place for vegan food in Netscapeville.

You can find us at the corner of Communicator Street and Navigator Way. We're open from 10 am to 6 pm every day. We don't take reservations, so just come on down. We guarantee that after you visit us once, you'll be back on a regular basis!

We have an extensive regular menu of tasty meals in addition to our daily specials.

You can use the following menu (no pun intended) to view the Specials for any day this week. Our specials change every week.

Please select a day of the week:

I'll bet your mouth is watering for some Tofu, Artichoke, and Asparagus Surprise right about now - mmm, mmm, sounds scrumptious, doesn't it? As for myself, I think I'll mosey on over to the po-boy shop down the street, where they've got a smoked sausage on french - dressed, no mayo, con cebolla - with my name on it...

Our next DHiNC project, the Expanding Colored Squares Example, is the most complicated of the lot, and we'll tuck into it in the following entry.

Comments: Post a Comment

<< Home

Powered by Blogger

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