reptile7's JavaScript blog
Monday, April 28, 2008
 
The Script Tips #92-93 Script, Part 3
Blog Entry #111

We continue today our analysis of the pop-up tables script of HTML Goodies' JavaScript Script Tips #92-93. In this post, we'll turn our attention to the script's pop-up tables; as noted two entries ago, Joe for his part discusses the pop-up tables in a not-at-HTML Goodies "Post the Tables" article.

Culled from the script's document body, here's the pop-up table code:

<div style="position:relative">
<script language="javascript">
    for (var j = 0; j < Titles.length; ++j)
    {
        name = Titles[j];
        document.write(
        "<div style=\"position:absolute;top:5px;width:350px\">\n" +
        "    <table id=\"" + name + "\"" +
        " cellpadding=1 cellspacing=4 border=2" +
        " bgColor=" + bgColor + "\n style=" +
        "\"display:none; position:absolute; left:200px\">");
        document.write(
            "<tr bgColor=" + bgColor + ">");
        document.write(
            "  <th bgColor=" + fgColor + " align=center>" +
            " <font color=" + bgColor + ">Language</font>");
        document.write(
            "  <th bgColor=" + fgColor + " align=center>" +
            " <font color=" + bgColor + ">Years Used</font>");
        document.write
            ("  <th bgColor=" + fgColor + " align=center>" +
             " <font color=" + bgColor + ">Last Used</font>");
        for (var i = 0; i < Text[j].length; i = i + nCols)
        {
            if (Text[j][i + 3] == 0)
            {
                document.write(
                "  <tr><td>" + Text[j][i] + 
                "\n    <td align=\"center\">" + Text[j][i+1] + 
                "\n    <td>" + Text[j][i+2] + "\n  </tr>");
            }
            else
            {
                document.write(
                "  <tr><td><b>" + Text[j][i] + 
                "</b>\n    <td align=\"center\"><b>" + Text[j][i+1] + 
                "</b>\n    <td><b>" + Text[j][i+2] + "</b>\n  </tr>");
            }
        }
        document.write("</table>");
        document.write("</div>");
    }
</script>
</div>

Table position

Between the document body's "Pop-up table sample" heading and the initial display table, which we deconstructed in the previous entry, is a div element holding a script element that codes a set of ten div elements in which the pop-up tables are assembled respectively. The outer div element

<div style="position:relative;"> ... </div>

is given a position: relative style but is not given values for the CSS left and top properties; consequently, the outer div - let's give it an id="div1" identifier - is located at its "normal flow" position even as it contains no renderable content (we'll see in a moment that the pop-up tables are external to div1). The div1 div has an effective width value of 100%, spanning the width of the browser window; more specifically, per Section 10.3.3 of the CSS 2.1 Specification, the width of the div1 div is equal to that of its containing block, which is established by the body element.

In contrast, the inner div elements, which we'll give a class='div2' identifier, are absolutely positioned and have a specific width:

document.write("<div style=\"position:absolute;top:5px;width:350px;\" class='div2'> ... </div>");

The containing block for the div2 divs is established by the div1 div by virtue of the latter's relative positioning (the W3C addresses this situation in the second example of this CSS 2.1 Specification section); if the div1 div were not positioned, then the div2 containing block would be the "initial containing block", i.e., the div2 divs would be positioned relative to the upper left-hand corner of the document content area (a.k.a. the "canvas origin"). So, the div2 divs are set 5 pixels below the div1 div; because the div1 div contains no renderable content, and because an absolutely positioned element is removed from the normal flow entirely (it has no impact on later [elements]), this means in practice that the div2 divs lie outside the div1 div and slightly below the top of the initial display table - this can be verified via giving differently colored 1px borders to the div1 div, the div2 divs, and the initial display table.

The pop-up tables are also absolutely positioned:

var bgColor = "Yellow"; // bgColor is declared in the document head's script element.
name = Titles[j];
document.write("<table id=\"" + name + "\" cellpadding='1' cellspacing='4' border='2' " +
"bgcolor=" + bgColor + " style=\"display:none; position:absolute; left:200px;\"> ... </table>");


The containing block for each pop-up table is established by its div2 div parent by virtue of the latter's absolute positioning; the left edge of each table is pushed 200 pixels to the right of the left edge of its div2 parent, whereas the top edge of each table coincides with the top edge of its div2 parent. If we give the initial display table and its cells a border: 1px solid black style, then the top edge of each pop-up table will coincide with the top border of the right-hand cell of the first row of the initial display table:

Absolute position of a pop-up table

The script's nested-div positioning scheme works OK with MSIE 5.1.6 (but not with Netscape 7.02 - we'll look at Netscape's execution of the script in the next post) on my computer but is nonetheless more complex than it needs to be; specifically, I find that the div2 divs can be removed and that the div1 div is suitable for positioning the pop-up tables:

#div1 { position: relative; }
#div1 table { display: none; position: absolute; left: 200px; top: 5px; }

Writing the tables

Like the initial display table, the pop-up tables are created by a pair of nested for loops.

Each iteration of a 10-iteration outer loop

for (var j = 0; j < Titles.length; ++j) { ... }

codes a div2 div and the pop-up table it contains.

Structurally, each pop-up table begins with a row of headers: "Language", "Years Used", and "Last Used". The header rows are written by the outer loop:

var fgColor = "Black"; // fgColor is declared in the document head's script element.
document.write("<tr bgColor=" + bgColor + ">");
document.write("<th bgColor=" + fgColor + " align=center>" + "<font color=" + bgColor + ">Language</font>");
document.write("<th bgColor=" + fgColor + " align=center>" + "<font color=" + bgColor + ">Years Used</font>");
document.write("<th bgColor=" + fgColor + " align=center>" + "<font color=" + bgColor + ">Last Used</font>");

/* The </tr> and </th> tags are omitted in the script; they are optional in HTML but required for XHTML-compliance. */

Below the header row are (depending on the table) 2-10 rows whose cell data is taken from a corresponding child array of the Text two-dimensional array in the document head; these rows are written by the inner loop:

for (var i = 0; i < Text[j].length; i = i + nCols) {

if (Text[j][i + 3] == 0) // For non-bolded rows
document.write("<tr><td>" + Text[j][i] + "<td align=\"center\">" + Text[j][i + 1] + "<td>" + Text[j][i + 2] + "</tr>");

else // For bolded rows
document.write("<tr><td><b>" + Text[j][i] + "</b><td align=\"center\"><b>" + Text[j][i + 1] + "</b><td><b>" + Text[j][i + 2] + "</b></tr>"); }

Presentationally (besides the positional aspects covered above):

(1) Regarding their 'border model', the pop-up tables are equipped with cellpadding='1', cellspacing='4', and border='2' attributes, none of which is deprecated.

(2) (a) The tables are given a yellow background color via the bgColor variable. The background color of the table cells in the rows below the header rows is also yellow because these cells and their tr element parents have a "transparent" background and thus the table background color shows through - see the "Table layers and transparency" section of the CSS 2.1 Specification for a fuller treatment of table element backgrounds as a function of table structure.
(b) The cells in the header rows are given a 'complementary'* color scheme - yellow text on a black background - via the bgColor and fgColor variables. (*The below-the-header-rows cell text color is the same as the browser's default text color (as set in the browser's "Preferences" file), which should be black for most users; it is not specfically set to black by the script.)
All color-related attributes were deprecated by HTML 4.0.

(3) An align="center" attribute is applied to the text in the cells under the "Years Used" header (i.e., in the middle column) and also to the header-row cell text; actually, there's no point in centering the "Years Used" and "Last Used" headers, which effectively set the maximum cell widths for their respective columns for all ten pop-up tables. The align attribute has been deprecated for most of the elements that could carry it (e.g., img, p, h#) but is, curiously, still legit for 'internal' table elements: tr, td/th, etc.

(4) Finally, the bolding or non-bolding of pop-up table rows is discussed in the "To bold or not to bold" section below.

Hmmm...do we need to go through a sample "here's what happens" for a pop-up table, now that we have the 2-D array thing under our belts? Let's briefly look at the Testing pop-up table,

The 'Testing' pop-up table ,

which is assembled by the outer loop's second (j = 1) iteration and whose td cells are respectively populated with the elements of the Text[1] child array:

//       Language     Years Last Used   Bold //       -----------  ----- ---------   ----     Text[1] = new Array(  "QA Partner (4Test)", 6, "Current", 1,  "DTM",                3, 1986,      0,  "WinRunner",        1/4, 1997,      0);

As noted earlier, the table's header row is written by the outer loop and the other rows are written by the inner loop. Here's a quick rundown on the inner loop action:

(1) First iteration: (i = 0): the Text[1][3] == 0 if condition returns false, so the else block bolds and then loads QA Partner (4Test) (Text[1][0]), 6 (Text[1][1]), and Current (Text[1][2]) into the cells of the second table row.

(2) Second iteration: (i = 4): the Text[1][7] == 0 if condition returns true, so the if block loads DTM (Text[1][4]), 3 (Text[1][5]), and 1986 (Text[1][6]) into the cells of the third table row but does not bold them.

(3) Third iteration: (i = 8): the Text[1][11] == 0 if condition returns true, so the if block loads WinRunner (Text[1][8]), 1/4 (Text[1][9], which is rendered as 0.25), and 1997 (Text[1][10]) into the cells of the fourth table row but does not bold them.

To bold or not to bold

As shown above, some of the pop-up table rows are bolded and some of them aren't. If there's a pattern to this bolding business, I don't see it; it doesn't seem to depend on the "Years Used" value, the "Last Used" value, or any combination thereof - for example, the Statistical pop-up table contains a bolded SAS | 8 | 1990 row whereas the Graphical pop-up table contains a non-bolded SAS/GRAPH | 8 | 1990 row. Given that the b element is a presentational element, and that the various CSS font properties apply to all elements and are inherited, a better row styling approach would be to
(a) subtract the else block's <b> and </b> tags and
(b) equip its tr element(s) with a class='lowerRow' identifier;
the lowerRow rows could then be given a font-weight: bold style or another style or no style at all, as desired.

Similarly, the b element of the initial display table's inner for loop

if (Text[i][j + 3] == 1) document.write("<b>" + Text[i][j] + "</b>");

can be replaced with a span element

if (Text[i][j + 3] == 1) document.write("<span class='languageStyle'>" + Text[i][j] + "</span>");

for maximum right-hand cell styling flexibility.

We're not quite done with the pop-up tables yet. In the following entry, we'll revisit in greater detail the script's eShow( ) and eHide( ) functions that respectively display and vanish the pop-up tables; we'll also discuss the script's problems with Netscape and how to fix them.

reptile7

Friday, April 18, 2008
 
The Script Tips #92-93 Script, Part 2
Blog Entry #110

Today we begin in earnest a deconstruction of the pop-up tables script of HTML Goodies' JavaScript Script Tips #92-93. The script's table that displays initially and its pop-up tables are coded by separate script elements in the script document body. This post will focus on the initial display table


and its code:

<table border="0" cellspacing="4">
<script language="javascript">
  for (var i = 0; i < Titles.length; ++i) {
    document.write("<tr>\n<td><p align=\"right\">");
    document.write(Titles[i] + ":</p>");
    document.write("</td>\n<td><a onmouseover=\"eShow(&quot;" + Titles[i] + "&quot;)\"");
    document.write("onmouseout=\"eHide(&quot;" + Titles[i] + "&quot;)\">");
    document.write("<font color=\"#0000ff\" size=\"3\" face=\"Arial\">");
    for (var j = 0; j < Text[i].length; j = j + nCols) {
      if (j > 0) { document.write(", "); }
      if (Text[i][j + 3] == 1) { document.write("<b>" + Text[i][j] + "</b>"); }
      else { document.write(Text[i][j]); } }
    document.write("\n</font></a></td></tr>"); }
</script></table>

The border="0" and cellspacing="4" attributes of the initial display table are both presentational attributes, but neither of them is deprecated, so there's no harm in letting them be. Having said this, I've given the above table and its cells a border: 1px solid black style to illuminate the table's structure.

As you can see, the table has ten rows and two cells per row. The text content of the table's cells is taken from the Titles and Text arrays in the document head via a pair of nested for loops (strictly speaking, only the inner loop is 'nested').

Each table row is written by an iteration of the outer loop:

for (var i = 0; i < Titles.length; ++i) {
document.write("<tr> ... </tr>"); }

Here's the Titles array whose length serves as the upper boundary of the loop:

Titles = [ "General Programming",    "Testing",    "Windows",    "Assembly",    "Data Base",    "Statistical",    "Graphical",    "Text",    "Spreadsheet",    "Command" ];

As far as I am aware, this is the first time we've encountered an array literal in HTML Goodies' JavaScript materials. As Joe notes in Script Tip #92, JavaScript automatically indexes the elements of an array literal, i.e., General Programming is Titles[0], Testing is Titles[1], etc.

So, what all do we have in these table rows? First, each row begins with a \n new line, which is unnecessary and can be removed. (In fact, all of the script's \n's can be thrown out. The \n's would serve a purpose if we were using the script to print out the table's markup, but that's not what we're doing.) Next we come to the first table cell:

document.write("<td><p align=\"right\">" + Titles[i] + ":</p></td>");

For each row, the loop writes to this cell a Titles element that serves as a header for the table cell to its right; consequently, the first cell should be coded as a th element. (The browsers on my computer bold the text in a th element; if this would bother you, then you could give the th element(s) a font-weight: normal style.)

The Titles: text is wrapped in a p element bearing a deprecated align="right" attribute; my preference here is to ditch the p element

document.write("<th class='myHeader'>" + Titles[i] + "</th>");

and instead style the th elements with:

.myHeader { text-align: right; }

We now move on to the much more complicated second, right-hand cells of the table rows. The immediate child of each of these cells is an anchor element that doesn't link to anything (there's no href attribute) but merely serves as a carrier for the onmouseover and onmouseout commands that respectively display and vanish the pop-up tables:

document.write("<td><a onmouseover=\"eShow(&quot;" + Titles[i] + "&quot;)\"");
document.write("onmouseout=\"eHide(&quot;" + Titles[i] + "&quot;)\"> ... </a></td>");

We'll have more to say about the onmouseover/onmouseout commands and their unusual quote formatting at a later point.

In turn, the anchor element contains a font element that holds the cell's text; regarding the script's execution by MSIE, for which the script was originally written, the anchor element is unnecessary as MSIE allows the use of the onmouseover and onmouseout event handlers with the font element. For that matter, you can put the onmouseover/onmouseout attributes in the second cell td start-tag if you prefer; the script effect will be a bit different: the pop-up tables will pop up if the mouse cursor is anywhere (and not just over the text) in the right-hand cells.

As you know, HTML 4.0 deprecated the font element and all of its attributes. (Perhaps unsurprisingly, the HTML 4 Index of Attributes shows that the font element is one of the few elements for which the W3C nixes the use of onmouseover and onmouseout.) We can replace the table font element

document.write("<font color=\"#0000ff\" size=\"3\" face=\"Arial\"> ... </font>");

with a span element

document.write("<span class='mySpan'> ... </span>");

and the following style rule set:

.mySpan { color: blue; font-size: 16px; font-family: Arial, sans-serif; }

The above rule set can alternatively be applied to the second cell td element, in which case the span element would be unnecessary; on the other hand, a span element is as good a carrier as any for the onmouseover/onmouseout commands. The span element was introduced by HTML 4.0, and I find it a bit odd that the script doesn't contain any span elements, given that the script begins with a document type declaration having a -//W3C//DTD HTML 4.0 Transitional//EN public identifier.

The font element content is written by the inner for loop:

for (var j = 0; j < Text[i].length; j = j + nCols) {
if (j > 0) document.write(", ");
if (Text[i][j + 3] == 1) document.write("<b>" + Text[i][j] + "</b>");
else document.write(Text[i][j]); }

The inner loop is executed ten times as determined by the Titles.length upper boundary of the outer loop. However, each run of the inner loop has a different number of iterations because its upper boundary is Text[i].length, the number of elements of the ith child array of the Text two-dimensional array, which differs for each value of i.

The inner loop counter variable, j, is initially set to 0 and increases in multiples of 4 - j = 0, 4, 8, 12, ... - according to the loop's j = j + nCols increment-expression. The nCols variable is set to 4 in the document head and represents the number of columns in each Text child array (not the number of columns in the pop-up tables, as stated incorrectly in Script Tip #92).

Perhaps we should discuss the Text 2-D array a bit before going any further. The Text array comprises ten child arrays. Each Text child array provides data for
(a) a right-hand cell of the initial display table and
(b) a pop-up table
that pertain to a given Titles header. Consider the Text[7] array, which pertains to the Text (Titles[7]) header:

//       Language     Years Last Used   Bold //       -----------  ----- ---------   ----     Text[7] = new Array(  "Word", 10, "Current", 1,  "WordPerfect", 15, 1988,      1,  "TPU",          8, 1987,      0,  "EEL",          5, 1971,      0,  "SNOBOL",       5, 1971,      1,  "Postscript",   1, 1995,      0);

As exemplified above, the elements of each Text child array are arranged into four columns. The elements of the first three columns will respectively fill the td cells of the three columns of a corresponding pop-up table. The fourth column provides Boolean 1 or 0 values for respectively bolding or not bolding the elements of a given array row; for example, regarding Text[7], WordPerfect, 15, and 1988 will be bolded, whereas TPU, 8, and 1987 will not be bolded. (Why bolded or not bolded? We'll discuss this in the next post when we take up the pop-up tables.)

The elements of the "Language" column are also loaded into a right-hand cell of the initial display table. Getting back to our deconstruction of the initial display table and its font element, the inner for loop's j = 4n values map onto the "Language" elements: for Text[7], j = 0 maps onto Word, j = 4 maps onto WordPerfect, j = 8 maps onto TPU, etc., as we'll see below.

So let's write the second cell of the eighth row of the initial display table using the inner for loop and the Text[7] array. Here's what happens:

(1) For the loop's first iteration (j = 0):
(a) if (0 > 0) document.write(", ");
The if condition returns false and the browser moves to...
(b) if (Text[7][3] == 1) document.write("<b>" + Text[7][0] + "</b>");
// Text[i][j + 3] generally references the fourth columns of the Text child arrays.
Text[7][3], Text[7]'s fourth-in-source-order element, is indeed 1 and the if condition returns true, so Text[7][0], Word (Text[7]'s first-in-source-order element), is bolded and written to the page, giving us (after the font element attributes are applied): Word.

(2) For the loop's second iteration (j = 4):
(a) if (4 > 0) document.write(", ");
The if condition returns true, so a two-character comma-space string is appended to Word.
(b) if (Text[7][7] == 1) document.write("<b>" + Text[7][4] + "</b>");
Text[7][7] is 1 and the if condition returns true, so Text[7][4], WordPerfect, is bolded and written to the page, giving us: Word, WordPerfect.

(3) For the loop's third iteration (j = 8):
(a) if (8 > 0) document.write(", ") tacks on another comma-space string.
(b) if (Text[7][11] == 1) document.write("<b>" + Text[7][8] + "</b>");
Text[7][11] is 0 and the if condition now returns false, so the browser moves to...
(c) else document.write(Text[7][8]);
Text[7][8], TPU, is written to the page (but not bolded), giving us: Word, WordPerfect, TPU.

(4) For the loop's fourth iteration (j = 12):
(a) if (12 > 0) document.write(", ") tacks on another comma-space string.
(b) if (Text[7][15] == 1) document.write("<b>" + Text[7][12] + "</b>");
Text[7][15] is 0 and the if condition returns false, so the browser moves to...
(c) else document.write(Text[7][12]);
Text[7][12], EEL, is written to the page (but not bolded), giving us: Word, WordPerfect, TPU, EEL.

(5) For the loop's fifth iteration (j = 16):
(a) if (16 > 0) document.write(", ") tacks on another comma-space string.
(b) if (Text[7][19] == 1) document.write("<b>" + Text[7][16] + "</b>");
Text[7][19] is 1 and the if condition returns true, so Text[7][16], SNOBOL, is bolded and written to the page, giving us: Word, WordPerfect, TPU, EEL, SNOBOL.

(6) For the loop's sixth iteration (j = 20):
(a) if (20 > 0) document.write(", ") tacks on another comma-space string.
(b) if (Text[7][23] == 1) document.write("<b>" + Text[7][20] + "</b>");
Text[7][23] is 0 and the if condition returns false, so the browser moves to...
(c) else document.write(Text[7][20]);
Text[7][20], Postscript, is written to the page (but not bolded), giving us: Word, WordPerfect, TPU, EEL, SNOBOL, Postscript.

I trust you can handle the other table rows at this point. For the time being, that'll do it for the initial display table - we'll take on the pop-up tables in the following entry.

reptile7

Tuesday, April 08, 2008
 
The Script Tips #92-93 Script: Intro
Blog Entry #109

Today we begin work on the final script presented by the HTML Goodies JavaScript Script Tips series: the "Pop-Up Tables" script of Script Tips #92 and #93.

The Script Tips #92-93 Script codes a 'mini-résumé'. The script initially displays a table whose rows contain lists of the programming languages that the script's author, Peter Trenholme, has under his belt, e.g.:

Windows: C++, C++ Builder, Java, JavaScript, Delphi, Visual Basic, SAS/AF

When the user mouseovers the blue text, a table providing relevant details pops up:

Pop-up table for the 'Windows' row

When the user mouseouts from the blue text, the table disappears. If this seems familiar, it should: the Script Tips #92-93 Script's effect is similar to that of the "Drop-Down Menu" tutorial script that we analyzed in Blog Entry #96. Nonetheless, the Script Tips #92-93 Script will break some new ground for us in that its tables - both the initial table and the pop-up tables - are assembled via a 'two-dimensional' array, an array type we heretofore have not encountered.

A two-dimensional array is simply an array whose elements are themselves arrays. The child arrays of an arrayName 2-D array are referenced in the usual manner: arrayName[0], arrayName[1], etc. The individual elements of the child arrays are accessed via an arrayName[i][j] syntax; for example, arrayName[5][2] would refer to the third-in-source-order element of arrayName's sixth-in-source-order child array.

The Script Tips #92-93 Script and the xmp element

Mr. Trenholme has formatted his script with whitespace in order to make it easier to read in various ways - for example, the script's Text 2-D array is formatted so that the Text child arrays resemble the pop-up tables that are coded from them - so to preserve this formatting, Joe has wrapped the script in an xmp element on the "Here's the Code" page of Script Tips #92-93. As you may know, the xmp element* is a not-just-deprecated-but-now-obsolete precursor** to the pre element.
*Note from this link that the W3C was warning authors away from the xmp element as far back as HTML 2.0.
**The xmp element appears in the element set of the first version of HTML whereas the pre element doesn't.

Like, say, the title element, the xmp element has (or 'had' - perhaps I should use the past tense here) a #PCDATA(-type) content model, meaning that it could validly contain text and also character references (e.g., &eacute; for é) but no markup, and therefore any markup in an xmp element should be treated by the browser as normal text and not rendered, in the same way that the markup in a

<title>My not-so-<b>bolded</b>-and-<i>italicized</i> title</title>

title is not rendered but printed in the browser window's title bar. So regarding the Script Tips #92-93 Script's display, I suspect that Joe put the script in an xmp element and not a pre element because a pre element, which can legitimately contain most text-level elements including the script element, would have required him to respectively escape the script's < and > characters to &lt; and &gt; (at the least, the < characters would have to be escaped), whereas he could let the < and > characters be with an xmp element.

Of course, all bets are off as to how a modern browser will render an obsolete element. In practice on my computer:
• MSIE 5.1.6 renders the entire Script Tips #92-93 Script, as the content of its xmp element container, without incident.
• Netscape 7.02 only renders the xmp element content that follows the <body bgcolor="#ffffff"> tag.
But as Joe notes, regardless of what your browser does with the xmp element, you can grab the full script from the source of the "Here's the Code" page; alternatively, you can take it from the div below:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head>
<script language="javascript">
//
    Titles = ["General Programming",
             "Testing",
             "Windows",
             "Assembly",
             "Data Base",
             "Statistical",
             "Graphical",
             "Text",
             "Spreadsheet",
             "Command"];
  
    var nCols = 4;              // Number of columns in the tables
    var bgColor = "Yellow";     // Pop-up table background color
    var fgColor = "Black";      // Pop-up table text color
    Text = new Array(10);       // Array of arrays of pop-up table data
//
//       Language     Years Last Used   Bold
//       -----------  ----- ---------   ----
    Text[0] = new Array(
         "C",         13, "Current", 1,
         "C++",        5, "Current", 1,
         "FORTRAN",   30, 1986,      1,
         "BASIC",     20, 1987,      1,
         "PROLOG",     1, 1990,      1,
         "ADA",      1/2, 1985,      0,
         "LISP",       2, 1975,      0,
         "PL/1",       1, 1978,      0,
         "APL",        2, 1971,      0,
         "COBOL",    1/4, 1967,      0);
    Text[1] = new Array(
         "QA Partner (4Test)", 6, "Current", 1,
         "DTM",                3, 1986,      0,
         "WinRunner",        1/4, 1997,      0);
    Text[2] = new Array(
         "C++",          5, "Current", 1,
         "C++ Builder",  2, "Current", 1,
         "Java",       1/2, "Current", 0,
         "JavaScript",0.08,"Current",  0,
         "Delphi",     1/4, 1997,      0,
         "Visual Basic", 1, "Current", 0,
         "SAS/AF",       2, 1991,      0);
    Text[3] = new Array(
         "MASM",      1, 1985,    0,
         "GMAP",      1, 1986,    0,
         "BAL",       1, 1971,    0);
    Text[4] = new Array(
         "SQL*Plus", 12, "Current", 1,
         "SAS/SQL",   1, 1991,      0,
         "Access",    1, "Current", 1,
         "SIR",       3, 1979,      0,
         "dBase",     3, 1985,      0,
         "Rbase",     4, 1987,      0);
    Text[5] = new Array(
         "SAS",      8, 1990,    1,
         "SPSS",     2, 1971,    0,
         "Minitab",  3, 1980,    0,
         "SIR",      1, 1979,    0,
         "P-STAT",   2, 1985,    0,
         "GLIM",     1, 1985,    0);
    Text[6] = new Array(
         "Corel",     1/2, 1997,     0,
         "Tel-A-Graph", 1, 1986,     0,
         "SAS/GRAPH",   8, 1990,     0);
    Text[7] = new Array(
         "Word",        10, "Current", 1,
         "WordPerfect", 15, 1988,      1,
         "TPU",          8, 1987,      0,
         "EEL",          5, 1971,      0,
         "SNOBOL",       5, 1971,      1,
         "Postscript",   1, 1995,      0);
    Text[8] = new Array(
         "Excel",       2, "Current", 1,
         "Lotus 1-2-3", 5, 1986,      0);
    Text[9] =  new Array(
         "MS-DOS",   18, "Current", 1,
         "NDOS",     15, "Current", 1,
         "DCL",      10, 1992,      1,
         "JCL",      10, 1971,      0,
         "UNIX",      5, 1980,      0);
function eShow(name)
{
    document.all(name).style.display = "inline";
}
function eHide(name)
{
    document.all(name).style.display = "none";
}
</script>
</head>

<body bgcolor="white">
<p><b>Pop-up table sample</b></p>

<div style="position:relative">
<script language="javascript">
    for (var j = 0; j < Titles.length; ++j)
    {
        name = Titles[j];
        document.write(
        "<div style=\"position:absolute;top:5px;width:350px\">\n" +
        "    <table id=\"" + name + "\"" +
        " cellpadding=1 cellspacing=4 border=2" +
        " bgColor=" + bgColor + "\n style=" +
        "\"display:none; position:absolute; left:200px\">");
        document.write(
            "<tr bgColor=" + bgColor + ">");
        document.write(
            "  <th bgColor=" + fgColor + " align=center>" +
            " <font color=" + bgColor + ">Language</font>");
        document.write(
            "  <th bgColor=" + fgColor + " align=center>" +
            " <font color=" + bgColor + ">Years Used</font>");
        document.write
            ("  <th bgColor=" + fgColor + " align=center>" +
             " <font color=" + bgColor + ">Last Used</font>");
        for (var i = 0; i < Text[j].length; i = i + nCols)
        {
            if (Text[j][i + 3] == 0)
            {
                document.write(
                "  <tr><td>" + Text[j][i] + 
                "\n    <td align=\"center\">" + Text[j][i+1] + 
                "\n    <td>" + Text[j][i+2] + "\n  </tr>");
            }
            else
            {
                document.write(
                "  <tr><td><b>" + Text[j][i] + 
                "</b>\n    <td align=\"center\"><b>" + Text[j][i+1] + 
                "</b>\n    <td><b>" + Text[j][i+2] + "</b>\n  </tr>");
            }
        }
        document.write("</table>");
        document.write("</div>");
    }
</script>
</div>
  
<table border="0" cellspacing="4">
<script language="javascript">
  for (var i = 0; i < Titles.length; ++i)
  {
    document.write("<tr>\n<td><p align=\"right\">");
    document.write(Titles[i] + ":</p>");

    document.write("</td>\n<td><a onmouseover=\"eShow(&quot;" + Titles[i] + "&quot;)\"");
    document.write("onmouseout=\"eHide(&quot;" + Titles[i] + "&quot;)\"</a>");
    document.write("<font color=\"#0000FF\" size=\"3\" face=\"Arial\">");
    for (var j = 0; j < Text[i].length; j = j + nCols)
    {
      if (j > 0)
      {
        document.write(", ");
      }
      if (Text[i][j + 3] == 1)
      {
        document.write("<b>" + Text[i][j] + "</b>");
      }
      else
      {
        document.write(Text[i][j]);
      }
    }
    document.write("\n</font></a></td></tr>");
  }
</script>
</table></body></html>

Per my standard practice, the above div script has been placed in a pre element, for which the script's < and > characters have been duly escaped, as you can verify from the source of this page. To preserve the script's formatting, I find that the script must be rendered in a monospace font and not in a sans-serif font (my usual choice) nor even a serif font. The W3C suggests, When handling preformatted text, visual user agents...[m]ay render text with a fixed-pitch font, but I've given my pre element a font-family: monospace; style just to be on the safe side.

In the name of completeness, I should mention, before moving on, that:

(1) The browsers on my computer do not convert character references in an xmp element to their respective characters, e.g.,

<xmp>7 &times; 7 = 49</xmp>

outputs 7 &times; 7 = 49 and not 7 × 7 = 49.

(2) Joe places his xmp element in a line break-preventing nobr element, unnecessarily so IMO - none of the script's lines/strings is long enough to warrant the nobr container.

Getting the script to work with MSIE

As you would expect, the script uses tableObject.style.display commands to display and vanish its pop-up tables:

function eShow(name) { document.all(name).style.display = "inline"; }
function eHide(name) { document.all(name).style.display = "none"; }
// name is the id value for the pop-up tables.

In its original form, the script is 'MSIE-only': at the time the script was written, the JavaScript/Netscape 'object model' was not able to access table elements, but MSIE could do so via the all collection. However, at the script's demo page, the script does not work even with MSIE - you'll see the initial display table but the pop-up tables don't pop up. The problem lies with the following line:

document.write("onmouseout=\"eHide(&quot;" + Titles[i] + "&quot;)\"</a>");

The yellow-highlighted anchor element end-tag is 'extra' and shouldn't be there - take it out and the script works fine with MSIE.

Then, to get the script to work with current non-MSIE and MSIE browsers, you'd think that we could merely replace the document.all(name) references in the eShow( )/eHide( ) functions with document.getElementById(name) references. But at least for Netscape 7.02, I find that additional changes are necessary to reproduce the script's effect with MSIE; we'll get to these changes, and a cross-browser demo, in due course.

The lost 'Script Tip #94'

Joe does not finish his deconstruction of the "Pop-Up Tables" script at the HTML Goodies site. In Script Tip #92, he discusses the script element in the document head, and in Script Tip #93, he addresses the document body's code for the initial display table. At the end of Script Tip #93, Joe promises, "Next Week: Those Pop-Up Tables." However, the 'current' Script Tip index and the 'legacy' Script Tip index both end with Script Tip #93. Knowing that some of HTML Goodies' materials appear elsewhere on the Web, I decided to see if a Google search would turn up a lost 'Script Tip #94' or its equivalent.

I am gratified to report that my search bore fruit: here at Developer.com and here at EarthWeb.com is a "Post the Tables" article in which Joe concludes his discussion of the "Pop-Up Tables" script. (HTML Goodies, Developer.com, and EarthWeb.com are all part of the Jupitermedia 'empire', and the 'family ties' that bind these sites are outlined in HTML Goodies' "The Family of HTML Goodies" article.) The "Post the Tables" article is somewhat marred - specifically, it features a pre element-contained block of code that does not display correctly because the < characters thereof are not escaped (it's clear from the source that this is the problem, as there are three other pre-wrapped code blocks on the page that are OK) - so maybe that's why it's not posted at HTML Goodies as a 94th Script Tip.

(July 2016 Update: The aforecited "Post the Tables" pages are no longer live but you can still get the article at the Internet Archive.)

We'll go over the script's initial display table in detail in the next post.

reptile7


Powered by Blogger

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