reptile7's JavaScript blog
Tuesday, April 10, 2007
 
Framed
Blog Entry #72

You may recall that we briefly encountered frames for the first time in HTML Goodies' JavaScript Script Tip #41. We delve much more deeply into frames in today's entry as we examine a "Frame Maker" script addressed by Script Tips #49, #50, and #51. The Script Tips #49-51 Script enables a user to create and view various frames layouts, and initially contains six preset frameset templates; prior to its display, however, the frameset code is usefully loaded into textarea boxes, in which it can be edited by the user - a feature that breaks new ground for us interactivitywise.

The Script Tips #49-51 Script can actually be accessed by following the "Here's the Code" link in Script Tip #51 (but not via the corresponding links in Script Tips #49 and #50), and is reproduced in the div below:

<html>
<head>
<title>Frame Maker</title>

<script language="javascript">

// Below are variables that will be used in each paste function.

var top = "<html>" + "\r" + "<title>My Frame Page</title>" + "\r" +"<head></head>";
var nf = "<noframes>" + "\r" + "You need a frames capable browser to view this page." + "\r" + "</noframes>" + "\r" + "</html>";
var f = "</frameset>";
var bc = "bordercolor=blue>";
var MW = "marginwidth=0";
var MH = "marginheight=0";

// Below are the six functions that produce the frame code in the textarea box.

function framesa( ) 
{
document.Framer.Fillit.value = top
+ "\r" + "<frameset cols=50%,* "
+ " " + bc + "\r" + "<frame src=w.htm" +" " + "name=One" 
+ "\r" + "scrolling=auto" + " " + MW + " " + MH + " " + "noresize=yes>" 
+ "\r" + "<frame src=x.htm" +" " + "name=Two"
+ "\r" + "scrolling=auto" + " " + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + f 
+ "\r" + nf;
}

function framesb( ) 
{
document.Framer.Fillit.value = top
+ "\r" + "<frameset rows=50%,* "
+ " " + bc + "\r" + "<frame src=w.htm" +" " + "name=One" 
+ "\r" + "scrolling=auto" + " " + MW + " " + MH + " " + "noresize=yes>" 
+ "\r" + "<frame src=x.htm" +" " + "name=Two"
+ "\r" + "scrolling=auto" + " " + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + f 
+ "\r" + nf;
}

function framemixa( ) 
{
document.Framer.Fillit.value = top
+ "\r" + "<frameset cols=30%,* " + bc + " " + "noresize=yes>"
+ "\r" + "<frame src=w.htm" + " " + "name=One" + " " + "scrolling=yes"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + "<frameset rows=50%,*>"
+ "\r" + "<frame src=x.htm" + " " + "name=Two" + " " + MW
+ "\r" + MH + " " + "scrolling=yes>"
+ "\r" + "<frame src=y.htm" + " " + "name=Three" + " " + "scrolling=no"
+ "\r" + MW + " " + MH + " " + "noresize=no>" 
+ "\r" + f
+ "\r" + f
+ "\r" + nf;
}

function frames3v( )
{
document.Framer.Fillit.value = top
+ "\r" + "<frameset cols=33%,33%,*" + " " + bc
+ "\r" + "<frame src=w.htm name=One" + " " + "scrolling=auto"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + "<frame src=x.htm" + " " + "name=Two" + " " + "scrolling=auto"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + "<frame src=y.htm" + " " + "name=Three" + " " +
"scrolling=auto"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + f
+ "\r" + nf;
}

function frames3h( )
{
document.Framer.Fillit.value = top
+ "\r" + "<frameset rows=33%,33%,*" + " " + bc
+ "\r" + "<frame src=w.htm name=One" + " " + "scrolling=auto"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + "<frame src=x.htm" + " " + "name=Two" + " " + "scrolling=auto"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + "<frame src=y.htm" + " " + "name=Three" + " " +
"scrolling=auto"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + f
+ "\r" + nf;
}

function framemixb( ) 
{
document.Framer.Fillit.value = top
+ "\r" + "<frameset cols=30%,* " + bc + " " + "noresize=yes>"
+ "\r" + "<frameset rows=50%,*>" + "\r" + "<frame src=w.htm" + " " +
"name=One"
+ " " + "scrolling=no" + " " + MW + "\r" + MH + " " + "noresize=yes>" 
+ "\r" + "<frame src=x.htm" + " " + "name=Two" + " " + MW
+ "\r" + MH + " " + "scrolling=yes>"
+ "\r" + f
+ "\r" + "<frameset rows=50%,*>" + "\r" + "<frame src=y.htm" + " " +
"name=Three"
+ "\r" + "scrolling=no" +" " + MW + " " + MH + " " + "noresize=no>"
+ "\r" + "<frame src=z.htm" +" " + "name=Four" + " " + "scrolling=yes"
+ "\r" + MW + " " + MH + " " + "noresize=yes>"
+ "\r" + f
+ "\r" + f
+ "\r" + nf;
}

// Below is the function that copies over the text from one box to the other.

function Copy( )
{
if (document.Framer.Fillit.value == "") 
{ alert("The top box is empty. Please enter a script by clicking one of the frames buttons."); }
else 
{ document.Framer.Pastebox.value = document.Framer.Fillit.value; }
}

// Below is the function that displays the code in a new window.

function view( )
{
if (document.Framer.Pastebox.value == "") 
{ alert("The paste box is empty. Please enter a script by clicking the Copy/Edit button.");
return false;
}
else 
{ alert("If you like the results, remember to paste it to a text editor!");
boat = open("","DisplayWindow");
see = parent.document.Framer.Pastebox.value;
boat.document.write(see);
return true;
}
}

</script>

</head>

<body alink="#ff0000" bgcolor="#c0c0c0" link="#0000ee" text="#000000" vlink="#551a8b">

// Below is the form and table code that creates the look on the page.

<form name="Framer">
<table border="1">
<tbody>
<tr>
<td width="150">

<b>1.</b> Choose One:<p>

<input onclick="framesa( );" type="button" value="2 Vertical"><br> 
<input onclick="frames3v( );" type="button" value="3 Vertical"><br> 
<input onclick="framesb( );" type="button" value="2 Horizontal"><br> 
<input onclick="frames3h( );" type="button" value="3 Horizontal"><br> 
<input onclick="framemixa( );" type="button" value="3 Mixed"><br> 
<input onclick="framemixb( );" type="button" value="4 Mixed"><br> </td>
<td valign="top">
<textarea cols="56" name="Fillit" rows="15"></textarea> 
<center>
</td></tr>
<tr>
<td>

<b>2.</b> Paste it in:<p>

<input onclick="Copy( );" type="button" value="Copy/Edit"><p> 
<input onclick="alert('Misfire? No problem, a new copy will be pasted to the bottom box. Good Luck!'); Copy( );" type="button" value="Start Over"><br> 
<input onclick="reset( );" type="button" value="Clear All"><br> </td>
<td valign="top">
<textarea cols="56" name="Pastebox" rows="15"></textarea> 

<center>
<b>3.</b> Then: <input onclick="view( );" type="button" value=" View It! ">
</center>

</td>
</tr>
</tbody>
</table>

<p>
</form>
</p>

</body>

</html>

Overview of the Script Tips #49-51 Script

The "See it in Action" links in Script Tips #50 and #51 lead to a script demo page (the corresponding link in Script Tip #49 points to the Script Tips #45-48 Script demo page). The Script Tips #49-51 Script demo page is in the form of a large two-row, four-cell table. The northwest cell holds a "1. Choose One:" heading and a series of six push buttons; when clicked, each button calls a function in the script's script element.

(1) The "2 Vertical" button calls the framesa( ) function, which contains a single assignment statement. Using the global variables at the beginning of the script element - top, nf, f, etc. - the right side of the statement pieces together and stringifies the code for a two-column frames layout:
The framesa( ) layout
The frameset document string is formatted/shaped with several "\r" carriage returns and then displayed in the Fillit textarea box in the table's northeast cell.

(2) The "3 Vertical" button calls the frames3v( ) function, which similarly assembles and loads into the Fillit box the code for a three-column frames layout:
The frames3v( ) layout

(3) The "2 Horizontal" button calls the framesb( ) function, which assembles and loads into Fillit the code for a two-row frames layout:
The framesb( ) layout

(4) The "3 Horizontal" button calls the frames3h( ) function, which assembles and loads into Fillit the code for a three-row frames layout:
The frames3h( ) layout

(5) The "3 Mixed" button calls the framemixa( ) function, which assembles and loads into Fillit the code for a column-row-row three-frame layout:
The framemixa( ) layout

(6) The "4 Mixed" button calls the framemixb( ) function, which assembles and loads into Fillit the code for a four-frame layout:
The framemixb( ) layout

Moving on to the table's second row, the southwest cell holds a "2. Copy it in:" heading and a series of three push buttons. Both the "Copy/Edit" and "Start Over" buttons use the script element's Copy( ) function to copy and paste Fillit's contents into the Pastebox textarea box in the table's southeast cell. The "Clear All" button, as you might guess, functions as a reset button.

Finally, at the bottom of the southeast cell is a "View It!" button that, via the script element's view( ) function, displays Pastebox's code in a new browser window.

The Copy( ) and view( ) functions both include some don't-leave-it-blank-type data validation, popping up an alert( ) message if Fillit or Pastebox is empty, respectively.

Frameset/frame element attributes

Joe doesn't discuss the attributes of the frameset and frame elements to any extent, so perhaps we should do that.

Frameset attributes

(1) The cols and rows attributes of the frameset element are fairly self-explanatory, but what about those asterisks, huh?

<frameset rows="50%,*">

You can probably figure out that the * in the tag above is equivalent to 50%. More precisely, the * value is a relative length representing the remaining available space, as explained in the "Lengths" section of the HTML 4.01 Specification; cols="30%,*" and cols="30%,70%" are thus also equivalent.

(2) The bordercolor attribute, appearing in the global variable bc, adds color to the borders between frames; I say "adds color to" because, at least on my iMac, the bordercolor="blue" border is not solidly blue but contains blue and black regions:

A bordercolor border, up close

The bordercolor attribute was first implemented by Netscape in Navigator 3.0, and support by MSIE followed shortly thereafter; however, bordercolor is not 'standardized': you won't find it in the HTML 4.01 Specification's Index of Attributes.

Buried in the HTML Goodies site (and shamefully no longer appearing in the Frames Tutorial sector) is a "So You Want Colored Frames, Huh?" legacy tutorial that discusses the bordercolor attribute.

Frame attributes

(1) A frame's src attribute, much like an img src attribute, specifies a file that will load into the frame. (The frame and img elements are both 'placeholder' elements having an "EMPTY" content model.)

(2) A name attribute allows a frame to be targeted by a link in another frame - see the "Naming Cells and Using Targets" section of HTML Goodies' "So, You Want Some Frames, Huh?" tutorial for more information and a demo.

(3) The scrolling attribute has three possible values:
(a) scrolling="auto" installs vertical and horizontal scrollbars if a frame needs them (i.e., if the src file's display overflows the frame's visible area), and doesn't install scrollbars if a frame doesn't need them;
(b) scrolling="no" ensures that a frame won't have scrollbars, even if they are needed; and
(c) scrolling="yes" ensures that a frame that needs scrollbars will have them, and, depending on the browser, may (MSIE) or may not (Netscape) provide disabled (greyed-out) scrollbars for a frame that doesn't need them, or at least that's what I see on my computer.

(4) The marginwidth and marginheight attributes respectively add horizontal and vertical margin areas between a frame's boundaries and src content area. HTML Goodies' "HTML 4.01: Frames" tutorial alleges, The[se] commands allow you to set margin height and width in pixels or percentages; however, the W3C classifies marginwidth/marginheight as a %Pixels; attribute type, for which percentages are not valid (and not a %Length; attribute type, for which percentages are acceptable). In practice, I find that MSIE acts on marginwidth/marginheight percentage values, but Netscape ignores them.

(5) The noresize attribute is set to either yes or no in the frameset functions but is actually a Boolean attribute. Putting noresize (or perhaps noresize="noresize") in a frame element's start-tag fixes the frame's width and height; if you leave it out, then the frame's interframe borders can be shifted by normal mouse-cursor dragging and dropping.

I myself would have left the scrolling, marginwidth, marginheight, and noresize attributes out of the Script Tips #49-51 Script. I don't like unresizable windows, and I don't like it when document content is pushed to a window's edges, which is what happens when marginwidth and marginheight are set to 0, as is done in the script via the global variables MW and MH (curiously, the W3C asserts that the marginwidth/marginheight value "must be greater than zero"); regarding the scrolling attribute, I see that auto is the default value - I'll take it.

Fortunately, all of the above attributes can be modified, or even deleted, right there in the Fillit/Pastebox boxes; we can similarly change the document title, the nesting of frameset elements, and also the noframes element, bringing us to...

The noframes element

Each frameset function concludes, via the global variable nf, with a noframes element, which specifies content that should be displayed only by user agents that do not support frames or are configured not to display frames, quoting the W3C. The noframes element appears, optionally, in the content model of the frameset element

<!ELEMENT FRAMESET - - ((FRAMESET|FRAME)+ & NOFRAMES?) -- window subdivision-->
<!--As for a regular expression, ? is a quantifier that means "occurs 0 or 1 time(s)."-->

so it would seem that the noframes element should be a child, and not a sibling, of the frameset element and that nf should be placed before the last f (frameset element end-tag) in each frameset function.

And what kind of content are we talking about? The noframes element's own content-model description is somewhat confusing:

<![ %HTML.Frameset; [
<!ENTITY % noframes.content "(BODY) -(NOFRAMES)">
]]>
<!ENTITY % noframes.content "(%flow;)*">
<!ELEMENT NOFRAMES - - %noframes.content; >

Can or cannot the noframes element contain a body element? (The HTML.Frameset entity's replacement text is "IGNORE".) We can sort out the noframes element's content with a frames-disabled browser; in this regard, MSIE straightforwardly allows me to disable frames as follows:
(1) At the bottom of the Edit menu, access the Preferences pane.
(2) On the Web Browser menu, select the Web Content option.
(3) In the Page Content section, uncheck the Show frames checkbox and then click OK.

Disabling frames with MSIE

Having done this, I can confirm that
(a) it's OK if nf follows the last f in each frameset function - nf's "You need a frames capable browser to view this page" text string is rendered without incident - and
(b) the noframes element can contain
(i) a body element and
(ii) the various block and inline elements that can be descendants of the body element,
at least when using MSIE.

(I ran into trouble when I tried to configure Netscape (7.02) to not show frames. To make a long story short, I somehow botched an attempt to import a user_pref("browser.frames.enabled",false) command into my Mozilla prefs.js file; subsequently, I was unable to launch Netscape and an "Error launching browser window:no XBL binding for browser" alert( ) message would pop up - I ultimately had to uninstall and reinstall Netscape. Needless to say, I really need to upgrade my computer.)

Hmmm...a
Too-much-text-in-file message
message is popping up in my "Framed" source file, so perhaps we should finish off the remaining script issues in the next entry.

reptile7

Labels: , ,


Comments: Post a Comment

<< Home

Powered by Blogger

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