reptile7's JavaScript blog
Tuesday, October 22, 2019
Approaching Excel, Part 1
Blog Entry #402

All right, in today's post we'll begin a look at the CCC sector's College Tuition Chooser, which was created by Brian O'Keefe and went live in October 1997. The College Tuition Chooser codes a simple spreadsheet that stores and sums the various costs of attending 1-3 colleges or other institutions of learning.

The tuition.html page features a demo that works pretty well granted that
a large chunk of the chooser's JavaScript is meant for Netscape 4.0x and
the chooser's on-the-fly onchange addition action is fundamentally different from the =SUM(number1, number2, ...) formula input you'd use with a standard spreadsheet.
The chooser code may be accessed and saved at the corresponding tuition.txt page.

Layout and initial content

The chooser architecture commingles
a table having 11 rows and 41 cells and
a form holding 30 text inputs and a reset button.

<table cellspacing="0" cellpadding="0" width="100%" border="3"> ...
<form method="post" onsubmit="return false;"> ...

A form element can validly contain a table element but the converse is not true, and therefore the above form-in-table nesting should be inverted to a table-in-form nesting.

The cellspacing, cellpadding, and width attributes of the table element are entirely obsolete; the border attribute of the table element can be validly set to "" (the empty string) or 1 but is obsolete if set to any other value.

We won't be submitting any data to a processing agent, so the form element's method and onsubmit attributes should be removable. However, upon subtracting the onsubmit attribute and when using late-1990s versions of Internet Explorer,
clicking the enter/return key
after entering a value into a chooser text field
triggers a form submission attempt* that subsequently throws a The attempt to load 'pathname/tuition.html' has failed.-type error - at least that's what I see with IE 4.5 and IE 5.1.7 in the SheepShaver environment.
(*Our study of HTML Goodies' "Submit the Form Using Enter" tutorial made me suspect that something like this might happen.)
I have no idea if this occurs with Microsoft's recent Edge/IE browsers (I don't see it with Navigator 4.05, Communicator 4.61, or any other browser on my computer): in any case, I reckon there's no harm in keeping the submit cancelation to be on the safe side, but yes, we can at least lose the method setting.

At the top of the table we've got an Institutional Cost of Attendance Worksheet caption.

<table ...>
<caption><h3>Institutional Cost of Attendance Worksheet</h3></caption>

As shown, the caption text is also marked up with an h3 element, which would not have been valid in HTML 3.2 (the current version of HTML in October 1997) but is OK in HTML 5.

Each table row holds four cells except for the last row, which holds one cell. The table's first column contains a preset series of college cost headers (not marked up as such):
Name of Institution, Tuition, Fees, Books/Supplies, Board, Room, Personal/Recreation, Transportation, Other, Total Cost of Attendance

<tr><td>Name of Institution</td> ... </tr>
<tr><td>Tuition</td> ... </tr>
<tr><td>Fees</td> ... </tr> <!-- Etc. -->

The table's second, third, and fourth columns contain text boxes for entering values for the headers to their left.

<!-- 1st row, for the names of the institutions that you're thinking of applying to: -->
<td align="center">1.<input type="text" name="title1" maxlength="20" size="15"></td>
<td align="center">2.<input type="text" name="title2" maxlength="20" size="15"></td>
<td align="center">3.<input type="text" name="title3" maxlength="20" size="15"></td>
<!-- 2nd row, for the tuitions those institutions charge: -->
<td align="center">$<input type="text" name="a1" onchange="calc(this);" size="15"></td>
<td align="center">$<input type="text" name="b1" onchange="calc(this);" size="15"></td>
<td align="center">$<input type="text" name="c1" onchange="calc(this);" size="15"></td>
<!-- 3rd row, for the institutions' miscellaneous fees: -->
<td align="center"> &nbsp;&nbsp;<input type="text" name="a2" onchange="calc(this);" size="15"></td>
<td align="center"> &nbsp;&nbsp;<input type="text" name="b2" onchange="calc(this);" size="15"></td>
<td align="center"> &nbsp;&nbsp;<input type="text" name="c2" onchange="calc(this);" size="15"></td> <!-- Etc. -->

All of the input cells have an align="center" attribute that horizontally centers their contents and is now obsolete. All of the input text boxes have a size="15" attribute that effectively sets the width of the boxes and is still valid.

The table's last row holds the aforementioned reset button.

<tr><td colspan="4"><div align="center"><input type="button" value="RESET" onclick="formClear(this.form);" size="150"></div></td></tr>

Do we really need to put the button in a <div align="center"> in order to horizontally center it in the rows[10].cells[0] cell? I trust y'all know the answer to that one. The size="150" setting has no effect on the button width.

Style matters

My my, look at all of the W3C's recent CSS activity...

The table itself

The cellspacing="0" attribute maps onto a table { border-collapse: collapse; } style rule, which in the present case not only collapses td td and td table interspace but also shrinks the table/td border-widths by a pixel.

The cellpadding="0" attribute maps onto a td { padding: 0px; } style rule. If the cellpadding setting is removed and not replaced by a style rule (the initial padding value is 0), then some browsers will add 1-2px of padding to the table cells (the default cellpadding value is #IMPLIED), which you may be OK with.

The width="100%" attribute maps onto a table { width: 100%; } style rule - straightforward enough, eh? If the width setting is removed and not replaced by a style rule, then the table will have a shrink-to-fit width and much more closely resemble a standard spreadsheet.

As regards the border="3" attribute, a detailed, down-to-the-pixel discussion of my ultimately unsuccessful attempts to exactly replicate the original chooser borders with CSS would take up more space than it's worth, so let me cut to the chase and alternatively say that I like my borders solid and fully black versus the ridge-like and not fully black borders that we initially get, and therefore I'd go with table { border: solid 3px black; } and td { border: solid 2px black; } style rules for this one.

The table caption

The h3 markup bolds the table caption and increases the caption's font size by a few pixels
and it also puts an empty line box between the caption and the table's first row;
if you feel that the h3 markup is redundant or otherwise inappropriate but like its effects, then you can reproduce those effects with a
caption { font-weight: bold; font-size: 19px; margin-bottom: 18px; } style rule.

Header cells

If we mark up the header cells as th elements versus td elements, then the text in those cells will be bolded and horizontally centered: a th { font-weight: normal; text-align: left; } style rule returns us to the original rendering.

Data cells

We don't want all those align="center"s cluttering up the code, do we? Give the last row's cell an id="resetTd" and replace the align attributes with a td, #resetTd { text-align: center; } style rule. (If you keep the first-column headers in td cells, then you can use a tr > td:first-child { text-align: left; } rule to exclude those cells from the preceding rule.)

Something that didn't work:
The author didn't have access to the colgroup and col elements but we do, and I decided to check if a
<colgroup span="1"></colgroup>
<colgroup span="3" style="text-align:center;"></colgroup>

<colgroup><col span="1">
<col span="3" style="text-align:center;"></colgroup>

snippet would horizontally center the data cell content.
In the event(s), neither snippet had any effect at all, as could have been predicted.

We also have a relatively minor vertical alignment issue to sort out.
The first row's text boxes are preceded by 1., 2., and 3. labels, respectively.
The text boxes in the second and tenth rows are preceded by a $ symbol.
The text boxes in the remaining rows are preceded by an ASCII space** (which is ignored by the browser, per the last ¶ of this HTML 4.01 section) followed by two &nbsp; non-breaking spaces that shift the boxes slightly rightward so that they vertically line up with the $-marked boxes*** or not, depending on the browser's display font - for Times and Times New Roman, Arial, and Helvetica.
To the extent that you want to be a perfectionist about this, there are two fail-safe ways to vertically line up all of the text boxes exactly in the second, third, and fourth columns:
(1) Prepend a &nbsp; to each $ symbol so that each box is preceded by two renderable characters, and then set the table's font-family to a monospace font like Courier.
(2) Delete all of the pre-box characters.

**The ASCII space is not present in the rows[3].cells[1] cell.
***They don't quite line up with the #.-labeled boxes, which are 2-3 pixels to the right.

Input value alignment

Modern browsers will apply the text-align property to relevant input elements although this support is deemed experimental - see the last ¶ of this CSS 2.2 section.
Would you like to horizontally center the Name of Institution values and to right-justify the various cost values?
We can effect the former with a tbody > tr:first-child input { text-align: center; } style rule whereas
an input[type="text"] { text-align: right; } rule will handle the latter.

• As intimated above, the first-in-source-order tr element is the first child of an implicit tbody element; it's not a sibling of the caption element and consequently cannot be selected via a caption + tr next-sibling selector.
• I include an attribute selector in the latter rule so as to exclude the resetting push button in the last row.

The reset button

Per the preceding subsection, an input[type="button"] { width: 150px; } styling can be applied to the reset button if you do in fact want it to have a width of 150px for whatever reason.
We'll take on the chooser's JavaScript in the following entry.

Powered by Blogger

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