reptile7's JavaScript blog
Thursday, September 27, 2012
The Colored Squares and Their New Homes
Blog Entry #265

Today we will begin modernizing the Expanding Colored Squares Example of Netscape's Dynamic HTML in Netscape Communicator resource. As of this writing I have not been able to update all of the example's JavaScript to my satisfaction, but that's no reason to not get going on the example's HTML and CSS in this post.

Parent layer to div

Two entries ago I identified a key reason why the example's colored squares are not housed in divs: Netscape 4.x supports the width and height attributes for a number of elements, but the div element isn't one of them. Of course, modern browsers duly apply the CSS width and height properties to all block-level elements, giving us the green light to replace the topleftblock, toprightblock, bottomleftblock, and bottomrightblock (document.layers) layer elements with div elements.

"What about the reason you gave in the previous post? 'The widths of div-based layers do not hold when external files are loaded into them.' The HTML DOM's HTMLDivElement interface doesn't have a src attribute - you won't be able to carry out the thislayer.src = thislayer.mysource; operation with a div." True enough: fortunately the point#.htm documents are sufficiently small such that their constituent elements can be brought into or even created in the main document. (I gave fleeting thought to putting the colored squares in iframes but quickly scotched the idea upon realizing that users won't see any non-src iframe content unless their iframe rendering has been turned off.)

The document.layers layer elements have top, left, width, height, and bgcolor presentational attributes; this data is easily moved to a style sheet:

#topleftblock, #toprightblock, #bottomleftblock, #bottomrightblock { position: absolute; width: 200px; height: 200px; }
#topleftblock { top: 50px; left: 50px; background-color: #ff5555; }
#toprightblock { top: 50px; left: 250px; background-color: #5555ff; } ...

We can't clip the divs with a clip element attribute but we can definitely do so via the CSS clip property, which applies to absolutely positioned elements and whose boundary coordinate order begins with the value and proceeds clockwise (, clip.right, clip.bottom, clip.left).

#topleftblock { clip: rect(150px, 200px, 200px, 150px); }
#toprightblock { clip: rect(150px, 50px, 200px, 0px); } ...

The document.layers layers were clipped scriptically; we can clip the divs that way too if we want:

document.getElementById("topleftblock").style.clip = "rect(150px, 200px, 200px, 150px)"; ...

As for the layers' onload and onmouseover behavioral attributes, we'll get to those guys later.

Child layer to span

We next consider the nested layers that respectively hold the 1, 2, 3, and 4 numeral headings of the initial example display. As a practical matter I decided to trade in these layers and their h1 children for spans and not divs because I wanted to collectively access the aforediscussed parent divs via a document.getElementsByTagName("div") operation in the JavaScript part of the code (even though divs would probably be more appropriate semantically, given that the nested layers aren't flanked by any content).

#span0, #span1, #span2, #span3 { position: absolute; font: xx-large bold; }
#span0 { left: 168px; top: 160px; }
#span1 { left: 18px; top: 160px; } ...
<div id="topleftblock"><span id="span0">1</span></div>
<div id="toprightblock"><span id="span1">2</span></div> ...

The h1 'styling' is roughly reproduced via a font: xx-large bold; style declaration.

The last layer

Something I didn't mention two entries ago:
In the squares.htm source the bottomrightblock layer element is followed by a

<layer top="500"><p></p></layer>

layer element that enables access to all of the fully expanded bottomleftblock and bottomrightblock layers by effectively increasing the height of the squares.htm page if the pre-expansion squares.htm height is less than that of the entire display (450px) - in this case, when the page loads Netscape 4.x provides a vertical scrollbar via which the user can get to the beyond-the-viewport (bottom) parts of the two bottom layers. Even back in the day (when 640 x 480 screen resolutions were the norm) it wasn't necessary to use a layer for this purpose: a document.height = 500; command would have done the trick. A body { height: 500px; } style rule would seem to be the safe cross-browser replacement for the last layer (we noted in the Page dimensions section of Blog Entry #240 that document.height is not supported by IE and Firefox); in practice, the post-Netscape 4.x browsers on my computer either provide initially or generate on the fly (in response to mousing over the 3 or 4 square) a vertical scrollbar for accessing the entire display if the viewport height is less than 450px - no page height-increasing mechanism of any kind is needed.

point#.htm content

Perhaps the easiest way to bring the point#.htm documents into the squares.htm document is to stringify each point#.htm document (body) and place each string in the squares.htm JavaScript; the strings can then be written to the innerHTMLs of the parent divs by either the changeNow( ) or expand( ) function.

var expandedsource = ["<h3>Netscape Navigator</h3><p>Netscape Navigator 4.0 is ...</p>",
    "<h3>Netscape Messenger</h3><p>Netscape Messenger is ...</p>",
    "<h3>Netscape Composer</h3><p>Netscape Composer is ...</p>",
    "<h3>Netscape Netcaster</h3><p>Netscape Netcaster is ...</p>"]; ...
squares = document.getElementsByTagName("div"); ...
squares[n].innerHTML = expandedsource[n];

A related approach:
Put the eight point#.htm elements in a display:none; div in the squares.htm HTML. Give the elements ordinalized ids that allow them to be respectively loaded into the corresponding parent divs.

squares[n].innerHTML = document.getElementById("blockheader" + n);
squares[n].appendChild(document.getElementById("blockpara" + n));
<div style="display:none;">
<h3 id="blockheader0">Netscape Navigator</h3><p id="blockpara0">Netscape Navigator 4.0 is ...</p>
<h3 id="blockheader1">Netscape Messenger</h3><p id="blockpara1">Netscape Messenger is ...</p> ...

Alternatively, you can create the point#.htm elements from scratch in the squares.htm JavaScript:

var headerArray = new Array(4), paraArray = new Array(4);
var headerText = ["Netscape Navigator", "Netscape Messenger", "Netscape Composer", "Netscape Netcaster"];
var paraText = ["Netscape Navigator 4.0 is ...", "Netscape Messenger is ...", "Netscape Composer is ...", "Netscape Netcaster is ..."];
for (i = 0; i < squares.length; i++) {
    headerArray[i] = document.createElement("h3");
    headerArray[i].textContent = headerText[i];
    paraArray[i] = document.createElement("p");
    paraArray[i].textContent = paraText[i]; }

Parent div initialization

The differing coordinate requirements of the colored square expansions/contractions notwithstanding, the example's four initialization functions can be consolidated into a single window.onload-triggered function by pre-arraying the values of the various initialization properties à la the expandedsource array of the previous section.

CSS does not have individual, clip.right, clip.bottom, and clip.left properties, but we can define matching ctop, cright, cbottom, and cleft custom properties and attach them to the parent divs.

window.onload = function ( ) {
    var cliptop = [maxclipcontracted, maxclipcontracted, minclip, minclip];
    var clipright = [maxclip, minclipcontracted, maxclip, minclipcontracted];
    var clipbottom = [maxclip, maxclip, minclipcontracted, minclipcontracted];
    var clipleft = [maxclipcontracted, minclip, maxclipcontracted, minclip];
    squares = document.getElementsByTagName("div");
    for (i = 0; i < squares.length; i++) {
        squares[i].status = "waitingToExpand";
        squares[i].ctop = cliptop[i];
        squares[i].cright = clipright[i];
        squares[i].cbottom = clipbottom[i];
        squares[i].cleft = clipleft[i]; }

The status, dtop/dright/dbottom/dleft, myposition, mysource, and mytext custom properties that are attached to the document.layers layers can be transferred as is to the parent divs. Excepting the status property, the values of these properties do not change and we therefore have the option of making them 'top-level' properties, i.e., it is not necessary to associate them with the parent divs.

var dtop = [-delta, -delta, 0, 0];
var dright = [0, delta, 0, delta];
window.onload = function ( ) { ... }

We are now ready to take on the mouseover-triggered expansion/contraction functions - we'll hit 'em with our best shot in the following entry.

Comments: Post a Comment

<< Home

Powered by Blogger

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