reptile7's JavaScript blog
Wednesday, June 26, 2013
 
I'm a Customer
Blog Entry #293

Having dispatched the running order part of the "So, You Want A Shopping Cart, Huh?" order.html page in the last couple of entries, we turn our attention now to the customer/shipping part of the page.

The tables[3] table

Just below the item detail section of the order.html page is a two-row, two-cell table whose upper cell holds a formatted Comments & Additional Information Can be written in the box below label and whose lower cell holds a textarea field for inputting said comments and additional information.

<table border="0" width="400"><tr><td align="center" colspan="6" bgcolor="#ff9999">
<b>Comments & Additional Information<br><font color="#ffff00">Can be written in the box below</font><br></b>
</td></tr><tr><td colspan="6">
<center><textarea name="comments" rows="10" cols="40"></textarea></center>
</td></tr></table>


Do the colspan="6" attributes serve any purpose? Nope: chuck 'em. Why is the textarea field centered with a center element vis-à-vis an align="center" td attribute? Don't know. Can and should the tables[3] table be recast as a div? Yep:

#commentDiv { text-align: center; width: 400px; }
#commentLabel { background-color: #ff9999; font-weight: bold; display: block; width: 400px; }
#commentSpan { color: yellow; }
...
<div id="commentDiv">
<label id="commentLabel" for="commentValue">Comments & Additional Information<br>
<span id="commentSpan">Can be written in the box below</span></label>
<textarea id="commentValue" name="comments" rows="10" cols="40"></textarea>
</div>


The tables[4] table

The user inputs her/his contact information into the fields of a Customer Information / Details table just below the tables[3] table. The tables[4] table comprises twelve rows and twenty-four cells; rather than burden you with its code, why don't I just show you a picture?

The Customer Information / Details table

(I've given the table a border="1" as a means of sorting out its colspan situation - vide infra.)

American users will want to replace the County: field with a State: field. BTW, the Royal Mail doesn't make use of postal county data anymore, so our friends in the UK can throw out the County: field altogether.

The absence of a label for the fifth tables[4] field may confuse some users; this field is meant to be an address field, i.e., it is for continuing the value of the preceding Address: field or for holding a second address, so we should really give it an Address #2: label, wouldn't you say?

Most of the tables[4] fields are 'required': the user must provide values for all of the fields except the Address #2:, Phone:, and Fax: fields in order to submit the order form; however, this information is not conveyed to the user.

Note that the eighth tables[4] row contains four cells. The first tables[4] row contains one cell whose colspan is set to 5 but should be set to 4; ditto for the twelfth tables[4] row. For the remaining rows, the field cell colspan is correctly set to 3. All of the left-hand label cells have a colspan="2" setting, which can be removed as these cells do not span two table columns.

Other presentational notes:
(1) The tables[4] table itself has a bgcolor="#00ffff" attribute, which is overridden by the bgcolor="#ccffff" attribute(s) given to each cell.
(2) All of the labels are bolded and right-justified.

Lastly, the first-row Customer Information / Details header can and probably should be marked up as a caption element:

#userCaption { background-color: #ccffff; font-weight: bold; }
...
<table border="" cellpadding="0" cellspacing="0" width="400">
<caption id="userCaption">Customer Information / Details</caption> ...


The tables[5] table

The recipient's contact details are entered into the fields of a Shipping Address: table just below the tables[4] table.

The Shipping Address table

Most of the above tables[4] table commentary also applies to the tables[5] table: the fourth row needs an Address #2: label, all fields except the Address #2: and Phone: fields are required but are not marked as such, etc.

Upon <caption>-izing the Shipping Address: header, I find that the browsers on my computer will not let me put the caption and the Same as above control in the same line box; in this case the latter must be placed in its own <tr>.

Checking the Same as above checkbox

<td align="center" colspan="3" bgcolor="#ccffff">
<input type="checkbox" name="same_flag" onclick="copyToShipping( );">
<font size="2" color="#ff0000"><blink>Same as above</blink></font></td>


calls the order.html copyToShipping( ) function, which copies the tables[4] table's name, snail-mail address, and phone data to the tables[5] table.

function copyToShipping( ) {
    if (document.order.same_flag.checked) {
        document.order.ship_name.value = document.order.name_first.value + " " + document.order.name_last.value;
        document.order.ship_address1.value = document.order.address1.value;
        document.order.ship_address2.value = document.order.address2.value;
        document.order.ship_city.value = document.order.city.value;
        document.order.ship_state.value = document.order.state.value;
        document.order.ship_zip.value = document.order.zip.value;
        document.order.ship_country.value = document.order.country.value;
        document.order.ship_phone.value = document.order.phone.value; } }


Interestingly, the Same as above string is wrapped in a blink element, which makes text blink on and off, quoting Netscape. The blink element, its text-decoration:blink; CSS equivalent, and its stringObject.blink( ); JavaScript equivalent are today supported by Mozilla's browsers (Firefox, Camino, Netscape 9) and Opera but not by IE, Google Chrome, and Safari. Wikipedia's blink element entry notes that blinking text is an 'accessibility no-no', so the blink markup should probably be removed.

Changing the value of any of the tables[5] fields calls the order.html disableSameFlag( ) function, which sets the checked status of the same_flag checkbox to false irrespective of whether the checkbox is checked or not.

function disableSameFlag( ) { document.order.same_flag.checked = false; }
...
<input type="text" size="30" maxlength="50" name="ship_name" onchange="disableSameFlag( );">


Finally, the tables[5] table has an empty ninth row
<tr><td>&nbsp;</td></tr>
that should be thrown out.

Functional compaction

If we give the tables[4] table an id="userTable" and the tables[5] table an id="shippingTable", then the copyToShipping( ) functionality can be replaced with:

var userInputs = document.getElementById("userTable").getElementsByTagName("input");
var shippingInputs = document.getElementById("shippingTable").getElementsByTagName("input");
shippingInputs[0].onclick = function ( ) {
    shippingInputs[1].value = userInputs[0].value + " " + userInputs[1].value;
    for (i = 2; i < shippingInputs.length; i++) shippingInputs[i].value = userInputs[i + 1].value; }


With the shippingInputs element collection in hand, the disableSameFlag( ) functionality can be recast as:

for (i = 1; i < shippingInputs.length; i++)
    shippingInputs[i].onchange = function ( ) { document.order.same_flag.checked = false; }


The tables[6] table

This table contains a Choose Order Method: header in its first row and a Phone Call: control in its second row

The Choose Order Method table

and at first glance seems pointless - not much of a choice, is it? why don't we just replace it with a phone number for placing an order? - although we'll see later that Joe does put the control to use, namely, he conditions the submission of the order form in part on the radio button's checked status.

The tables[6] table has a third row whose only 'content' is an anchor element start-tag:

<tr><td align="center" colspan="5" bgcolor="#ccffff"><a href="options.htm" target="navigate"></td></tr>

The <a href="options.htm" target="navigate"> tag is a remnant of the Learn about the different ordering methods link in the Choose Order Method: table at Gordon's order.htm page. I'd say we can safely excise the <a href="options.htm" target="navigate"> row from Joe's table, wouldn't you?

Even if we hold onto the Phone Call: control, the tables[6] table should be converted to a div:

#ordermethodDiv { background-color: #ccffff; font-size: large; font-weight: bold; text-align: center; width: 400px; }
#ordermethodLabel { font-size: small; }
...
<div id="ordermethodDiv">Choose Order Method:<br>
<label id="ordermethodLabel">Phone Call: <input type="radio" name="order_type" value="phone"></label></div>


The tables[7] table

Here's what it should look like:

The International Shipping table

Here's how we should code it:

#intlshippingDiv { background-color: #ccffff; font-weight: bold; text-align: center; width: 400px; }
#intlshippingSpan { font-size: large; }
...
<div id="intlshippingDiv"><span id="intlshippingSpan">International Shipping:</span><br>
Prices cover shipment worldwide</div>


'Nuff said.

Perhaps the Customer Information / Details and Shipping Address: tables should also be converted to divs, but these tables at least somewhat resemble grids of data, and therefore I am inclined to let their table architectures be.

One more point before we submit the order form:
If we're going to remove the credit card stuff (the On-line / Credit Card: option in the Choose Order Method: table and the Credit Card Info: table) from the order.html page, then the order form's reset button should be changed to .

In the following entry, we'll detail what happens when we click the order form's submit button.

Sunday, June 16, 2013
 
Order on the Page
Blog Entry #292

Welcome back to our ongoing discussion of the "So, You Want A Shopping Cart, Huh?" shopping cart. In today's post we will detail how the cart tallies up the user's running order.

Suppose we go to the pagetwo.html page and add one p2i2/$3.33 item to the shopping cart. Subsequently we go to the pagethree.html page and add one p3i3/$7.77 item to the cart. Here is our order string so far:

itemlist[1] = {code: "p2i2", price: "3.33", desc: "Page_2_Item_2", quan: 1, url: "pagetwo.html"}
itemlist[2] = {code: "p3i3", price: "7.77", desc: "Page_3_Item_3", quan: 1, url: "pagethree.html"}


Total it

We click the Review updated Order Form link at the bottom of the pagethree.html page and go to the order.html page. Writing the tables[2] table's total text field

document.write("<input type='text' name='total' size='6' value='" + format(parent.all_order_totals( ), 2) + "'>");

to the order.html page initially calls the shopcartindex.html all_order_totals( ) function.

var order_total = 0;
...

function all_order_totals( ) {
    order_total = 0;
    if (item_num > 0) {
        for (i = 1; i < item_num; i++) {
            order_total = order_total + item_tot_price(i); } }
    return order_total; }


An order_total variable is initialized to 0 in the top-level part of the shopcartindex.html script. The all_order_totals( ) function begins by resetting order_total to 0, an operation that is redundant for a first all_order_totals( ) run but is definitely needed if all_order_totals( ) is re-called during the shopping cart session: all_order_totals( ) builds the order total from scratch and thus it is necessary to clear order_total for a subsequent all_order_totals( ) run.

The item_num index for our order string is 3: item_num was incremented from 1 to 3 by both the shopcartindex.html additem( ) function and the shopcartindex.html remove_nil_items( ) function. And because item_num is 3, the all_order_totals( ) function's if statement condition returns true - the if (item_num > 0) { ... } gate is actually excess baggage as item_num never falls below 1 - and its for loop runs for two iterations. The for loop calls on an item_tot_price( ) function to calculate the total price for each item in the cart.

var total_item_price = 0;
...

function item_tot_price(i) {
    total_item_price = eval((itemlist[i].price * itemlist[i].quan));
    return total_item_price; }


The item_tot_price( ) function's eval( ) operation is unnecessary: although itemlist[i].price has a string type, itemlist[i].quan has a number type, and multiplying itemlist[i].price by itemlist[i].quan gives the number product that you would expect. The item_tot_price( ) multiplication operation could just as easily be carried out inside the all_order_totals( ) function, but let's go with what we've got for the time being.

(1) For the all_order_totals( ) loop's first iteration:
The item_tot_price( ) function multiplies itemlist[1].price by itemlist[1].quan to give 3.33, which via a total_item_price variable is returned to the all_order_totals( ) function. The item_tot_price( ) return is added to order_total and the resulting sum, 3.33, is assigned to order_total.

(2) For the all_order_totals( ) loop's second iteration:
The item_tot_price( ) function multiplies itemlist[2].price by itemlist[2].quan to give 7.77, which is returned to the all_order_totals( ) function and added to order_total to give 11.1, which is assigned to order_total.

Finally, order_total itself is returned to the all_order_totals( ) call on the order.html page.

Format it

Now, if you're following along at home, you'll notice that the order.html total field displays 11.10 and not 11.1: 11.1 is converted to 11.10 via the order.html format( ) function.

The total field's document.write( ) command (vide supra) calls the format( ) function and passes it two arguments:
(1) the all_order_totals( ) return, 11.1, and
(2) 2, the desired number of post-decimal point digits.
Here's the format( ) function:

function format(val, post) {
    var decpoint, begin, end, valstr, temp_char;
    valstr = "" + val;
    decpoint = valstr.indexOf(".");
    if (decpoint != -1) {
        begin = valstr.substring(0, decpoint);
        end = valstr.substring(decpoint + 1, valstr.length); }
    else {
        begin = valstr;
        end = ""; }
    if (end.length < post) {
        while (end.length < post) end += "0"; }
    end = end.substring(0, post);
    return (begin + "." + end); }


In brief, here's what happens:
• The all_order_totals( ) return, which has a number type, is assigned to a val variable, which is stringified by concatenating it with an empty string to give a valstr string.
• The pre- and post-decimal point parts of valstr are extracted and respectively assigned to begin and end variables; if valstr doesn't contain a decimal point, then end is set to an empty string.
• If the length of end is less than the function's post = 2 argument, then 0's are iteratively appended to end until end.length is 2.
• Finally, begin, a decimal point, and end are concatenated and the resulting string is returned to the format( ) call and then assigned to the value of the total field.

This is how we had to create a \d+\.\d{2} total value in 1997; thankfully, today we can reach for the toFixed( ) method of the Number object so as to replace the format( ) functionality with a single command:

document.write("<input type='text' name='total' size='6' value='" + parent.all_order_totals( ).toFixed(2) + "'>");

Item detail

If the user accesses the order.html page without adding any items to the cart, then the order.html page prints out a You have not ordered any items so far message below the tables[2] table.

if (parent.items_ordered == 0)
    document.write("<font color='#000080'><b>You have not ordered any items so far</b></font>");


However, if the user adds an item to the cart, subtracts the item from the cart, and then goes to the order.html page, this message does not appear because the shopcartindex.html subitem( ) function does not decrement the items_ordered value, i.e., items_ordered is still 1 after subtracting the item.

If there are any items in the cart, then the order.html page prints out a table of itemlist data for those items below the tables[2] table.

var index = 0;
...

if (parent.item_num > 0) {
    for (i = 1; i < parent.item_num; i++) {
        if (parent.itemlist[i].quan > 0) {
            index = index + 1;
            document.write("<a href='" + parent.itemlist[i].url + "'><i><b> review : </b></i></a>");
            document.write("<input size='10' type='text' name='" + parent.itemlist[i].code + "' value='" + parent.itemlist[i].code + "'>");
            document.write("<input size='6' type='text' name='" + parent.itemlist[i].code + "' value='" + parent.itemlist[i].price + "'>");
            document.write("<input size='20' type='text' name='" + parent.itemlist[i].code + "' value='" + parent.itemlist[i].desc + "'>");
            document.write("<input size='2' type='text' name='" + parent.itemlist[i].desc + "' value='" + parent.itemlist[i].quan + "'><br>"); } } }

/* In the original order.html source, the five document.write( ) commands are written as a single command, which I have broken up for the sake of clarity. */

The for loop writes out a row of data for each item in the cart; each row contains
(1) a review : link to the page at which the item was ordered,
(2) a text field displaying the item's identifier,
(3) a text field displaying the item's price (sans a beginning $ character),
(4) a text field displaying the item's description, and
(5) a text field displaying the item quantity.

Oddly, the names of the identifier, price, and description fields are set to the identifier value (parent.itemlist[i].code) whereas the name of the quantity field is set to the description value (parent.itemlist[i].desc); it would make more sense to use the otherwise-not-used index variable to create a code1, price1, desc1, quan1, code2, ... series of names as follows:

document.write("<input size='10' type='text' name='code" + index + "' value='" + parent.itemlist[i].code + "'>");
document.write("<input size='6' type='text' name='price" + index + "' value='" + parent.itemlist[i].price + "'>"); // Etc.


Here's the loop output for our p2i2 item + p3i3 item order:

The itemlist detail for a p2i2 item + p3i3 item order

If no items have been added to the cart prior to arriving at the order.html page, then the item_num index, which was initialized to 1, is still 1; in this case, the outer if statement's parent.item_num > 0 condition returns true but the for loop doesn't run for any iterations because the loop's i < parent.item_num condition returns false from the get-go.

If one or more items have been added to and then subtracted from the cart so that there are no items in the cart, then item_num will be greater than 1 - like items_ordered, item_num is not decremented by the shopcartindex.html subitem( ) function - in this case, the loop runs for item_num-1 iterations but nothing is printed out because the inner if statement's parent.itemlist[i].quan > 0 condition returns false (parent.itemlist[i].quan is 0) for each of those iterations.

Other code possibilities

Although it is necessary to obtain the total field's value scriptically, there is no reason whatsoever to write the tables[2] table's structure (and presentation) via a script.

#totalRow { background-color: #ff9999; }
#totalLabel { font-size: 24px; text-align: right; }
#messageTd { font-weight: bold; text-align: center; }
#messageSpan { font-style: italic; }
...
window.onload = function( ) { document.order.total.value = parent.all_order_totals( ).toFixed(2); }
...
<table id="orderTable">
<tr id="totalRow">
<td id="totalLabel"><label for="totalValue">Running Total : $</label></td>
<td><input type="text" id="totalValue" name="total" size="6"></td>
</tr><tr>
<td id="messageTd" colspan="2">This is your Order Total so far<br><span id="messageSpan">(Including Shipping Worldwide)</span>.</td>
</tr></table>


The tables[2] content can alternatively be given a div-based structure.

<div id="orderDiv">
<div id="totalDiv"><label>Running Total : $ <input type="text" name="total" size="6"></label></div>
<div id="messageDiv">This is your Order Total so far<br><span id="messageSpan">(Including Shipping Worldwide)</span>.</div>
... </div>


If the shopcartindex.html subitem( ) function decremented the items_ordered value so that items_ordered at all times represented the number of items in the cart, then the you-haven't-ordered-anything vs. here-are-your-items situations discussed in the previous section could be cleanly separated as follows:

<script type="text/javascript">
if (!parent.items_ordered) // If the cart is empty
    document.write("<span style='color:navy;font-weight:bold;'>You have not ordered any items so far</span>");
else { // If there are items in the cart
    for (i = 1; i <= parent.items_ordered; i++) {
        index++;
        ... document.write( ) command(s) ... } }
</script>


The above script element can be appended to the messageDiv div in the orderDiv div.

The here-are-your-items document.write( ) commands look a bit ugly, and I gave some thought to replacing them with corresponding Core DOM commands (createElement( ), setAttribute( ), insertBefore( )) but ultimately decided that it would be too much trouble to do so.

In the following entry, we'll briefly run through the remaining order.html tables and then begin work on the shopping cart's form submission code.

Saturday, June 08, 2013
 
Order in the Cart
Blog Entry #291

In today's post we will begin discussing the order.html page of the e-commerce shopping cart offered by HTML Goodies' "So, You Want A Shopping Cart, Huh?" tutorial. A check of the original Scottish Gifts order.htm page source reveals that Gordon had some help in writing it:
(1) Gordon wrote the page's HTML with the Microsoft FrontPage 2.0 HTML editor;
(2) some of the page's JavaScript was written by Tauren Mills of Groovee Creatives, which is now Groovee Corporation.

Structural overview

The order.html page is based on a set of eight tables that in one way or another relate to the ordering process. None of the tables has an identifier (FYI, both Netscape 4.x and IE 4.x support the id attribute but not the name attribute for the table element) so I will refer to the tables in source order as tables[0], tables[1], tables[2], ... as though we had gotten them via a var tables = document.getElementsByTagName("table"); operation. Intertwined with the order.html tables is a name="order" form whose fields store information for the ordering process.

(0) The tables[0] table frames the Please wait while the scripted order form is generated....... message near the top of the page.

(1) The tables[1] table serves as a container for the tables described below. The order form's submit button and reset button at the bottom of the page lie within the tables[1] table.

(2) The tables[2] table displays the running total ($) for the items that have been added to the shopping cart.

(3) The tables[3] table provides a textarea field for comments and any other information that should be conveyed to the shopping cart proprietor.

(4) The tables[4] table provides text fields for the user's contact information.

(5) The tables[5] table provides text fields for the recipient's contact information if it differs from the user's contact information.

(6) The tables[6] table frames a
Phone Call:
radio button that when checked signals that the user intends to order over the phone.

(7) The tables[7] table frames a brief note on international shipping.

order.html/order.htm table differences

• At the order.htm page the Phone Call: control is part of a larger Choose Order Method menu that also includes On-line / Credit Card: and Cheque: options; the menu is followed by a link to a "Payment Methods" page.

• The order.htm page sports a Credit Card Info table that was removed for the order.html page: Joe explains his reason for doing so in the tutorial's A Word of Warning section.

• Gordon wrapped the post-tables[2] tables in a second container table, which Joe also removed.

Other table notes

The tables of the shopcart.zip order.html page are given a width of 400 whereas the tables of the one-at-a-time order.html page (linked at the top of the post) are given a width of 340; I encourage you to use the former width as the latter tables look a bit scrunched.

Some of the tables have headings that could be marked up with the caption element, which is supported by both Netscape 4.x and IE 4.x. (Netscape's HTML Guide for Netscape Navigator 4.x is no longer hosted by Mozilla but, courtesy of the Internet Archive, can still be viewed here. To the best of my knowledge, Microsoft's early Web development materials are not on the Web.)

The tables[1] container table and the content discussed in the next section are horizontally centered by a center element child of the order.html body element.

Pre-tables[1]

Preceding the tables[1] table are three metainformation-type elements.

(1) At the top of the page is a large, red, and italicized This is the Order Form heading.

<p><font color="#ff0000" size="7"><i>This is the Order Form</i><br></font></p>

Clearly, the heading should be marked up as an h1 element:

h1 { color: red; font-size: 48px; font-style: italic; }
...
<h1>This is the Order Form</h1>


The default font size for h1 text is 32px; as specified above, the size="7" font element attribute maps onto a font-size:48px; style declaration.

(2) Next we have the aforementioned tables[0] Please wait while the scripted order form is generated....... message:

<table border="0" width="400"><tr><td align="center" bgcolor="#ff0000">
<font color="#ffffff"><b>Please wait while the scripted order form is generated....... </b></font>
</td></tr></table>


Methinks the message really belongs on an alert( ) box, but if you're going to have it on the page, then it would be semantically more appropriate to put it in a div element:

#waitDiv { width: 400px; text-align: center; background-color: red; color: white; font-weight: bold; }
...
<div id="waitDiv">Please wait while the scripted order form is generated.......</div>


(3) Lastly we have a paragraph containing another "Order Form" heading followed by a sentence giving an email contact and a phone contact in case the user experience goes sour:

<p><font size="6">Order Form</font><br>
<!-- HEY!!! PUT YOUR EMAIL ADDRESS IN THE LINK BELOW SO THEY CAN WRITE TO YOU -->
<b>In the event of difficulty with this script please email us direct on <a href="mailto:YOUR EMAIL HERE>Email@server.com"</a> or call us on (+44) 01569 763153</b></p>


I myself would throw out the Order Form heading - the size="6" font element attribute maps onto a font-size:32px; style declaration if you want to hold onto it - a font-weight:bold; declaration (vis-à-vis the b element) can be used to bold the remaining text.

The tables[1] table

The tables[1] table contains a single row with a single cell that holds the tables[2]-tables[7] tables, as intimated earlier. Strangely, the tables[1] table and td element start-tags are written scriptically whereas the corresponding end-tags are written as normal markup:

<script language="javascript"><!-- hide from Browsers
document.write("<table width='400'><td align='center'>");
...
</script>
...
</td></table></center></body></html>


Moreover, the tables[1] row markup is missing; the HTML tr element requires a start-tag (its end-tag is optional).

In addition to the order form's submit and reset buttons (vide supra), the tables[1] cell contains a small amount of non-table content situated between the tables[2] and tables[3] tables; this content is horizontally centered by the cell's align='center' attribute. The align='center' attribute would also horizontally center the tables[2]-tables[7] tables if the width of the tables[1] table were larger than that of the tables[2]-tables[7] tables. However, all of the tables[1] cell content would still be horizontally centered by the aforenoted <body><center> element in the absence of the tables[1] table, which is consequently excess baggage and can be thrown out.

The tables[2] table

The above tables[1] document.write( ) command is followed by two document.write( ) commands that write out the tables[2] table.

document.write("<table width='400'><tr><tr><td align='right' colspan='3' bgcolor='#ff9999'><font size='+2'>Running Total : $ </td><td colspan='3' bgcolor='#ff9999'> <input type='text' name='total' size='6' value=" + format(parent.all_order_totals( ), 2) + "></font></td><tr>");

document.write("<td colspan='6' align='center'><b>This is your Order Total so far<br><i>(Including Shipping Worldwide)</i>.</td></tr><tr></table>");


Technically, the tables[2] table contains four rows, but the first and fourth rows are empty (their innerHTML returns are an empty string, their firstChild returns are null). The table's second row contains two cells: the first cell holds a large Running Order : $ label and the second cell holds a name='total' text field that displays the user's order total. The table's third row contains one cell that holds a formatted This is your Order Total so far (Including Shipping Worldwide) message.

The second-row cells' colspan='3' attribute serves no purpose and should be removed; subsequently the third-row cell's colspan attribute should be set to 2. (BTW, the content widths of the first and second cells of the second row are 291px and 103px, respectively. How does the browser determine these widths? Your guess is as good as mine.)

The second-row cells' #ff9999 background color has a nonstandard-but-recognized name: it's called "light salmon pink".

Note that the second-row font element is improperly nested. If the browser's default font size is 16px, then the size='+2' font element attribute will give the Running Order : $ label a font size of 24px; the size='+2' attribute has no effect on the font size of the value of the total field.

The (required) end-tag of the third-row b element is missing; as a result, the b element bolds all of the third-row message, which is probably what Gordon wanted but I don't know for sure.

To generate the user's order total, the total field calls on the shopcartindex.html all_order_totals( ) function and then the order.html format( ) function: we'll go through these functions in the following entry.


Powered by Blogger

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