reptile7's JavaScript blog
Sunday, August 25, 2013
 
A New Order
Blog Entry #300

In today's post, I'll put forward an alternate approach to creating and adjusting the order string of the "So, You Want A Shopping Cart, Huh?" shopping cart.

Here are our starting observations:
(1) As the shopcartindex.html page loads, the itemlist object is stocked with initialized product( ) objects.
(2) When an item is added to or subtracted from the shopping cart, a corresponding product( ) object is created entirely from scratch.
(3) Once an item has been added to the cart, only its product( ) quan value may change in response to user input; its product( ) code, price, desc, and url values do not change.

An Array of item placeholders

As detailed in The order string section of Blog Entry #287, the itemlist construct is an Object object and not an Array object; however, we could code itemlist as the latter if we wanted to, for example:

var itemlist = new Array(maxarray);
for (i = 0; i < itemlist.length; i++) {
    itemlist[i] = new Object( );
    itemlist[i].code = "";
    itemlist[i].price = 0;
    itemlist[i].desc = "";
    itemlist[i].quan = 0;
    itemlist[i].url = ""; }


The preceding formulation allows us to jettison the shopcartindex.html createArray( ), product( ), and initialize_arrays( ) functions. Relatedly, as we threw out the shopcartindex.html remove_nil_items( ) function in the previous post, we can throw out the temp_array object as well at this point.

Indexing the data

It makes a certain amount of semantic sense to lodge the aforementioned code, price, desc, and url data in the Loc_additem( ) and Loc_subitem( ) function calls in the pageone.html, pagetwo.html, and pagethree.html documents. At the same time, however, it is inefficient to send an item's non-quan data to the shopcartindex.html additem( ) or subitem( ) function and then use that data to create a new itemlist[i] object every time the item is added to or subtracted from the shopping cart.

Alternatively, we can in the shopcartindex.html source pre-array the non-quan data

var codeArray = ["p1i1", "p2i1", "p2i2", "p2i3", "p3i1", "p3i2", "p3i3"];
var priceArray = [1.11, 2.22, 3.33, 4.44, 5.55, 6.66, 7.77];
var descArray = ["Page_1_item_1", "Page_2_Item_1", "Page_2_Item_2", "Page_2_Item_3", "Page_3_Item_1", "Page_3_Item_2", "Page_3_Item_3"];
var urlArray = ["pageone.html", "pagetwo.html", "pagetwo.html", "pagetwo.html", "pagethree.html", "pagethree.html", "pagethree.html"];


and then use a corresponding index

<form name="form1" action="">
<button name="addbox" type="button" onclick="Loc_additem(0);">Add This Item To My Order</button><br>
<button name="subbox" type="button" onclick="Loc_subitem(0);">Subtract This Item From My Order</button><br>
<p>You Have Ordered This Many Of This Item:<input type="text" name="p1i1" size="2" readonly></p>
</form>


to access an item's data and permanently load it into an itemlist member when the item is first added to the shopping cart:

function additem(index) {
    loc = check_if_in(codeArray[index]);
    if (loc != -1) { // If the item is in the order string
        if (!itemlist[loc].quan) // If the item's quan is 0
            items_ordered++;
        itemlist[loc].quan++; }
    else { // If the item is not in the order string
        itemlist[items_ordered].code = codeArray[index];
        itemlist[items_ordered].price = priceArray[index];
        itemlist[items_ordered].desc = descArray[index];
        itemlist[items_ordered].quan++;
        itemlist[items_ordered].url = urlArray[index];
        items_ordered++; item_num++; } }
...
function Loc_additem(itemIndex) { parent.additem(itemIndex); write_to_field(itemIndex); }


If the item is added more than once, the additem( ) if (loc != -1) clause is operative: the item's quan value is incremented but its non-quan values are not reset.

We can similarly craft a subitem( ) function that, as necessary, only decrements an item's quan value and the items_ordered counter:

function subitem(index) {
    loc = check_if_in(codeArray[index]);
    if ((loc != -1) && itemlist[loc].quan) { // If the item is in the order string and its quan is not 0
        itemlist[loc].quan--;
        if (!itemlist[loc].quan) // If the item's quan is now 0
            items_ordered--; } }
...
function Loc_subitem(itemIndex) { parent.subitem(itemIndex); write_to_field(itemIndex); }


Other item page changes

The original write_to_field( ) function features a while loop that runs 2-8 times depending on what we've got in the order string. We can cut the loop action to 1-3 iterations if we code the and buttons as button elements (vide supra) and then just iterate over the remaining input elements:

function write_to_field(index) {
    var itemInputs = document.getElementsByTagName("input");
    for (var i = 0; i < itemInputs.length; i++)
        if (itemInputs[i].name == parent.codeArray[index]) {
            itemInputs[i].value = parent.item_quan(index);
            break; } }


In place of the original function's found variable, the above function uses a break statement to stop the loop when a name-code match is found.

The shopcartindex.html update_this_page( ) function, which is called at the loading of each item page, can be rewritten in an analogous manner:

function update_this_page( ) {
    var itemInputs = parent.main.document.getElementsByTagName("input");
    for (var i = 0; i < itemInputs.length; i++) {
        for (var k = 0; k < item_num; k++) {
            if ((itemlist[k].code == itemInputs[i].name))
                itemInputs[i].value = itemlist[k].quan; } } }


Lastly, the You Have Ordered This Many: inputs, being text boxes, have onchange-able values, and we don't want that, needless to say; the easiest way to rectify this situation is to add a readonly attribute to each <input>.

Beginning at 0

Gordon's itemlist indexing begins at 1. I begin my itemlist indexing at 0, which requires that very minor changes be made to
(1-4) the shopcartindex.html all_order_totals( ), update_this_page( ), item_quan( ), and check_if_in( ) functions, and also to
(5) the code that writes out the user's itemlist data at the order.html page;
I trust I don't need to belabor these tweaks for you*. That done, the initial value of the item_num index can and should be lowered to 0.

*OK, here's one of them: it is necessary to change the item_quan( ) function's loc > 0 condition to loc > -1.

function item_quan(index) {
    var loc = check_if_in(codeArray[index]);
    var quantities = loc > -1 ? itemlist[loc].quan : 0;
    return quantities; }


We will have one last shopping cart post in which we briefly run through the shopcartindex.html check_window( ), delCookie( ), display_pic( ), and updatenav_nav( ) functions - don't touch that dial!

Sunday, August 18, 2013
 
Frameset Items Zero
Blog Entry #299

The denouement of our "So, You Want A Shopping Cart, Huh?" discourse will begin with discussions of
(1) the obsolete shopcartindex.html structure and
(2) the shopcartindex.html remove_nil_items( ) function.

Frame retool

In the Frameset/frame notes subsection of Blog Entry #286, we noted that HTML5 is obsoleting the frameset and frame elements - These elements are entirely obsolete, and must not be used by authors, the W3C declares - so it behooves us to come up with an alternate structure for the shopcartindex.html document.

However, we don't have to discard the frame concept completely. HTML5 is holding on to the iframe element, and it is simple enough to recast the right-hand main frame as an iframe. As for the left-hand navigate frame, its navigate.html content stays in place during the shopping cart process and can therefore be brought into a non-frameset parent document. The window.frames collection includes iframes, so we can continue to use the windowObject.frameObject mechanism to pass information between the iframe's documents and the parent document.

As set by the original frameset's cols="25%,*" attribute, the navigate frame's width spans 25% of the viewport width; we can mimic this effect by wrapping the navigate.html content in a div and then setting the div's CSS width to 25%.

#navigateDiv { width: 25%; display: inline-block; }
...
<div id="navigateDiv">
<p>This is the navigation div, and here are links to the order pages:</p>
<p><a href="pageone.html" target="main">Order Page One</a></p>
...
</div>


Normally the div element has a block-level rendering. We want the main iframe to horizontally flank the navigateDiv div and not be below it, which is easily arranged by setting the div's CSS display to inline-block (but not inline, as the div contains <p>s, whose own block-level renderings would then push the iframe below the div).

I find that giving the main iframe a full width="75%" pushes it below the navigateDiv div: a width setting that affords a bit of horizontal breathing room solves this problem. Regarding its height, the main iframe should vertically span the entire height of the viewport and provide a vertical scrollbar for at least the order.html page, whose height exceeds the viewport height. To vertically align the tops of the navigateDiv div and the main iframe, give the iframe a vertical-align:top; styling (otherwise the div will sit at the baseline of the iframe).

#orderIframe { vertical-align: top; }
...
<iframe id="orderIframe" name="main" width="70%" height="100%" src="welcome.html" frameborder="1" scrolling="auto">Your browser does not support iframes. Please call us at 123-456-7890 for a mail-order catalog.</iframe>


Cleaning up the order string, or not

This section will provide an overview of what the remove_nil_items( ) function will and will not do, as a complete treatment would take up more space than it's worth.

A visitor goes to the pagetwo.html page and adds, in order, one p2i1 ($2.22) item, one p2i2 ($3.33) item, and one p2i3 ($4.44) item to the shopping cart. Per the shopcartindex.html additem( ) function

function additem(codes, prices, descrip, url) {
    loc = check_if_in(codes);
    if (loc != -1) { // Update existing item
        olditem = itemlist[loc].quan;
        itemlist[loc] = new product(codes, prices, descrip, olditem + 1, url); }
    else { // New item
        olditem = itemlist[item_num].quan;
        itemlist[item_num] = new product(codes, prices, descrip, olditem + 1, url);
        items_ordered = item_num;
        item_num = item_num + 1; }
    remove_nil_items(itemlist); }


and the shopcartindex.html remove_nil_items( ) function

function remove_nil_items(inputlist) {
    var i = 0, j = 1;
    for (i = 1; i < item_num; i++) {
        if (itemlist[i].quan != 0) {
            temp_array[j] = itemlist[i];
            items_ordered = j;
            j = j + 1; } }
    itemlist = temp_array;
    item_num = items_ordered + 1; }


the visitor's cart additions create the following order string:

itemlist[1] = temp_array[1] =
    {code: "p2i1", price: "2.22", desc: "Page_2_Item_1", quan: 1, url: "pagetwo.html"}
itemlist[2] = temp_array[2] =
    {code: "p2i2", price: "3.33", desc: "Page_2_Item_2", quan: 1, url: "pagetwo.html"}
itemlist[3] = temp_array[3] =
    {code: "p2i3", price: "4.44", desc: "Page_2_Item_3", quan: 1, url: "pagetwo.html"}


At this point, the itemlist[1]-itemlist[3] and temp_array[1]-temp_array[3] members are identical, the items_ordered counter is 3, and the item_num index is 4.

Suppose the visitor subtracts the p2i2 item and adds a second p2i1 item.

(1) The remove_nil_items( ) for loop runs for three iterations.
(a) In the first iteration, itemlist[1] is assigned to temp_array[1].
(b) In the second iteration, itemlist[2].quan is 0 and therefore itemlist[2] is not assigned to temp_array[2].
(c) In the third iteration, itemlist[3] is assigned to temp_array[2] (j was not incremented in the loop's second iteration because the if condition was false).

(2) After the loop, the itemlist = temp_array; statement copies the temp_array object to the itemlist object, i.e., each itemlist member is overwritten by its corresponding temp_array member: temp_array[1] is assigned to itemlist[1], temp_array[2] is assigned to itemlist[2], etc. Subsequently item_num is reset (effectively decremented) to 3 by the item_num = items_ordered + 1; statement.

When remove_nil_items( ) has finished executing, the order string is:

itemlist[1] = temp_array[1] =
    {code: "p2i1", price: "2.22", desc: "Page_2_Item_1", quan: 2, url: "pagetwo.html"}
itemlist[2] = temp_array[2] =
    {code: "p2i3", price: "4.44", desc: "Page_2_Item_3", quan: 1, url: "pagetwo.html"}
itemlist[3] = temp_array[3] =
    {code: "p2i3", price: "4.44", desc: "Page_2_Item_3", quan: 1, url: "pagetwo.html"}


Net effect: The original p2i2 item has been removed but now we have a duplicate p2i3 item in the order string.

Suppose the visitor subtracts the p2i3 item and adds a second p2i1 item. In this case, nothing is removed from the order string: the p2i3 item would seem to be left behind by the third iteration of the remove_nil_items( ) for loop but it reappears when temp_array[3] is assigned to itemlist[3] after the loop.

As noted in the Subtract it section of Blog Entry #290, the shopcartindex.html subitem( ) function does not call the remove_nil_items( ) function; consequently, subtracting the p2i1 or p2i2 item without adding another item has no effect on the order string (other than decrementing the quan value of the p2i1 or p2i2 item).

Fortunately, the aforedescribed remove_nil_items( ) problems do not interfere with the normal operation of the shopping cart. At the order.html page, the visitor's order is tallied and displayed via script code with itemlist[i].quan operations that directly or indirectly weed out nil items anyway, more specifically:
(1) the shopcartindex.html all_order_totals( ) function doesn't add anything to the order_total if itemlist[i].quan is 0; and
(2) writing the visitor's itemlist data to the order.html page requires us to go through an if (parent.itemlist[i].quan > 0) { ... } gate.
It follows that the remove_nil_items( ) function is excess baggage, and should be thrown out.

We'll overhaul the item addition/subtraction process in the next entry.

Saturday, August 10, 2013
 
Cracking the Frameset Cookie
Blog Entry #298

We return now to our deconstruction of the cookie functionality of the "So, You Want A Shopping Cart, Huh?" shopping cart. At the end of the previous post, we respectively stored the values of the first nine inputs of the order.html Customer Information / Details table as cookie values in the shopcartindex.html document.cookie string. In today's post we'll go through the get-cookies part of the cookie functionality, which sees to it that those values are ready to load into the Customer Information / Details table if our visitor returns to the cart.

The value-extraction process begins with a get_that_cookie( ) function, which is called when the shopcartindex.html frameset has finished loading.

<frameset cols="25%,*" onload="parent.get_that_cookie( );">

The get_that_cookie( ) function first declares an i counter for a for loop (vide infra). Subsequently, get_that_cookie( ) calls and passes the gifttails string to a getCookieArray( ) function.

function get_that_cookie( ) {
    var i;
    getCookieArray("gifttails"); ... }


The getCookieArray( ) function initially initializes an i counter for a while loop to 0. Next, getCookieArray( ) iteratively sends gifttails+i to a getCookie( ) function.

function getCookieArray(name) {
    var i = 0;
    while (getCookie(name + i) != null) { ... } }


The getCookie( ) function gets the value of each gifttails+i-named cookie in the shopcartindex.html document.cookie string and then returns the value to the getCookieArray( ) function.

function getCookie(name) {
    var dcookie = document.cookie;
    var cname = name + "=";
    var clen = dcookie.length;
    var cbegin = 0;
    while (cbegin < clen) {
        var vbegin = cbegin + cname.length;
        if (dcookie.substring(cbegin, vbegin) == cname) {
            var vend = dcookie.indexOf (";", vbegin);
            if (vend == -1) vend = clen;
            return unescape(dcookie.substring(vbegin, vend)); }
        cbegin = dcookie.indexOf(" ", cbegin) + 1;
        if (cbegin == 0) break; }
    return null; }


If this code looks familiar, it should: its different variabilization notwithstanding, the getCookie( ) function is identical to the GetCookie( ) + getCookieVal( ) functionality appearing in HTML Goodies' "How Can I Set A Cookie Based On A User's Selection On A Form?" tutorial, which we dissected in Blog Entry #250. BTW, the unescape( ) function is deprecated: use the decodeURIComponent( ) function instead.

Let's get back to that while loop in the getCookieArray( ) function:

while (getCookie(name + i) != null) {
    shiparray[i + 1] = getCookie(name + i);
    i++;
    shiparray.length = i; }


For the document.cookie string we assembled in the previous post, the i counter increases to 9 before the while action ends. The getCookie( ) function is called 10 times; in the tenth getCookie( ) run:
(a) the gifttails9 cname string is not found in document.cookie;
(b) the cbegin = dcookie.indexOf(" ", cbegin) + 1; statement resets the cbegin index to 0;
(c) a break statement terminates the getCookie( ) while loop; and
(d) null is returned to the getCookieArray( ) while condition;
getCookie(name + i) != null now returns false and therefore the loop stops at the beginning of (what would be) its tenth iteration.

In The cookie jar section of Blog Entry #287, we created a 10-member shiparray Object object.

shiparray[1] = null;
shiparray[2] = null;
...
shiparray[9] = null;
shiparray.length = 10;


The i <= 8 getCookieArray( ) while loop iterations assign the getCookie(name + i) values to the non-length members of the shiparray object:

shiparray[1] = "Joe"; // getCookie("gifttails0");
shiparray[2] = "Blow"; // getCookie("gifttails1");
shiparray[3] = "username@gmail.com"; // getCookie("gifttails2");
shiparray[4] = "1234 Main Street"; // getCookie("gifttails3");
shiparray[5] = ""; // getCookie("gifttails4");
shiparray[6] = "New Orleans"; // getCookie("gifttails5");
shiparray[7] = "LA"; // getCookie("gifttails6");
shiparray[8] = "USA"; // getCookie("gifttails7");
shiparray[9] = "70118"; // getCookie("gifttails8");


Joe Blow left the Address #2 field blank and the value of the gifttails4 cookie is an empty string. Although the empty string and null separately convert to false in a boolean context, the "" != null comparison returns true and therefore the getCookie("gifttails4") return does not stop the getCookieArray( ) while loop.

The getCookieArray( ) function lastly 're-lengths' the shiparray object via a shiparray.length = i; statement; per the i counter, shiparray.length maxes out at 9 in the while loop's ninth iteration.

After the getCookieArray( ) function has finished executing, the get_that_cookie( ) function iteratively copies the shiparray[1]-shiparray[9] data to the ship_details object.

for (i = 0; i < shiparray.length + 1; i++) {
    if (shiparray[i])
        ship_details[i] = shiparray[i];
    else
        ship_details[i] = ""; }


The ship_details object was not initially equipped with 0-9 members, i.e., these properties are being added to the ship_details object on the fly. The for loop runs for 10 iterations: for the i = 0 and i = 5 iterations the else clause is operative and for the other iterations the if clause is operative.

The get_that_cookie( ) function finally copies the ship_details[1]-ship_details[9] data to the ship_details object properties corresponding to the first nine fields of the Customer Information / Details table

parent.ship_details.f_namea = ship_details[1];
parent.ship_details.l_namea = ship_details[2];
parent.ship_details.email = ship_details[3];
parent.ship_details.ad_onea = ship_details[4];
parent.ship_details.ad_twoa = ship_details[5];
parent.ship_details.citya = ship_details[6];
parent.ship_details.statea = ship_details[7];
parent.ship_details.countrya = ship_details[8];
parent.ship_details.zipa = ship_details[9];


so that the data will be loaded into the table by the refresh_ship_details( ) function if the visitor goes to the order.html page.

First-time visitors

The get-cookies functionality is operative for a first-time shopcartindex.html visitor; in brief, here's what happens:

• Loading the shopcartindex.html frameset calls the get_that_cookie( ) function, which calls the getCookieArray( ) function and passes it gifttails.

• The getCookieArray( ) while loop calls the getCookie( ) function and passes it gifttails0. Assuming that the document.cookie string does not contain a gifttails0 cookie, getCookie( ) returns null to the getCookieArray( ) while loop, shutting it down.

• The get_that_cookie( ) for loop runs for 11 iterations (shiparray.length = 10); in each iteration the else ship_details = ""; clause is operative (shiparray[i] is either null or undefined) and empty strings are assigned to ship_details[0]-ship_details[10]. After the loop, ship_details[1]-ship_details[9] is copied to
ship_details.f_namea-ship_details.zipa; the latter is written to the Customer Information / Details table if the visitor goes to the order.html page.

Other code possibilities

In the Functional compaction subsection of Blog Entry #293, we collected the input element descendants of the Customer Information / Details and Shipping Address table elements via:

var userInputs = document.getElementById("userTable").getElementsByTagName("input");
var shippingInputs = document.getElementById("shippingTable").getElementsByTagName("input");


We can use the userInputs and shippingInputs collections to
(1) dramatically simplify the shopping cart's cookie functionality and
(2) bring the omitted Customer Information / Details and Shipping Address text inputs into the cookie process.

Setting the cookies, take two

There are 19 text boxes in the Customer Information / Details and Shipping Address tables. The code below sets cookies for the values of all 19 boxes in one go:

/* Declare textInputValues globally, put the loop in a function: */
var textInputValues = new Array(19);
for (i = 0; i < textInputValues.length; i++) {
    if (i < 11) textInputValues[i] = userInputs[i].value;
    else textInputValues[i] = shippingInputs[i - 10].value;
    document.cookie = "gifttails" + i + "=" + encodeURIComponent(textInputValues[i]) + "; expires=" + parent.expdate.toUTCString( ) + "; path=/"; }


The for loop can be tied to the order.html unload event or perhaps to the submission of the order form:

document.order.onsubmit = function ( ) { ... }

value retrieval

The loop below returns the cookie values to the Customer Information / Details and Shipping Address tables:

for (i = 0; i < textInputValues.length; i++) {
    var nameIndex = document.cookie.indexOf("gifttails" + i);
    if (nameIndex != -1) {
        var valueIndex = document.cookie.indexOf("=", nameIndex) + 1;
        var endstr = document.cookie.indexOf(";", valueIndex);
        if (endstr == -1) endstr = document.cookie.length;
        if (i < 11) userInputs[i].value = decodeURIComponent(document.cookie.substring(valueIndex, endstr));
        else shippingInputs[i - 10].value = decodeURIComponent(document.cookie.substring(valueIndex, endstr)); }
    else {
        if (i < 11) userInputs[i].value = "";
        else shippingInputs[i - 10].value = ""; } }


This code can be tied to either the shopcartindex.html load event or the order.html load event. The original getCookie( ) procedure for locating the first characters of the cookies' names and values is more complicated than it needs to be, and has been replaced by a simpler approach taken from the getCookieVal( ) function in the Getting the cookie subsection of Blog Entry #251.

That's it - there's no need to use six separate functions or to involve the ship_details and shiparray objects in any way.

Excluding four other not-called shopcartindex.html functions and the shopcartindex.html remove_nil_items( ) function, we have at this point covered the "So, You Want A Shopping Cart, Huh?" shopping cart in its entirety. We will complete our shopping cart odyssey by mopping up some sections of the running order part of the cart over the next 2-3 posts.

Saturday, August 03, 2013
 
Nuts, Berries, and Input Values
Blog Entry #297

Welcome back to our ongoing discussion of the customer/shipping part of the "So, You Want A Shopping Cart, Huh?" order.html page. We have one more order.html issue to address: storage of the Customer Information / Details, Shipping Address, and Comments & Additional Information table data.

Holding on to the customer

A shopping cart visitor adds two pagetwo.html items to the cart, proceeds to the order.html page, and fills out the various order.html data tables. If the visitor submits the order form right away, then there is no need to hold onto the visitor's order.html data. But suppose the visitor goes back to pagetwo.html for whatever reason prior to submitting the form. Upon returning to order.html, the visitor should not have to reenter data into the order form fields: the original data should still be sitting in those fields, ready to go.

In The customer contact section of Blog Entry #287, we defined a ship_details Object object for holding the order.html table data. Replacing order.html with pagetwo.html in the main frame of the shopcartindex.html frameset gives rise to an order.html unload event; the order.html body element has an onunload attribute that calls an add_ship_details( ) function in the shopcartindex.html source and passes thereto the ship_details object.

<body ... onunload="parent.add_ship_details(parent.ship_details);">

The add_ship_details( ) function gives the ship_details object a shipform identifier and then individually assigns the values of the 22 inputs in the Customer Information / Details, Shipping Address, and Comments & Additional Information tables to the values of the corresponding shipform object properties.

function add_ship_details(shipform) {
    shipform.comments = parent.main.document.order.comments.value;
    shipform.f_namea = parent.main.document.order.name_first.value;
    shipform.l_namea = parent.main.document.order.name_last.value;
    shipform.email = parent.main.document.order.email.value;
    ...
    shipform.sameflag = parent.main.document.order.same_flag.value;
    shipform.shipname = parent.main.document.order.ship_name.value;
    shipform.ad_oneb = parent.main.document.order.ship_address1.value;
    ... }


Do we really need to pass the ship_details object to the add_ship_details( ) function and give it a new name in order to assign values to its properties? Nope, not at all. Moreover, the parent references are unnecessary as we are working in the shopcartindex.html document, although there's no harm in having them there; indeed, you might want to keep them as a sign that data is being passed from a frame document to a frameset document.

Complementarily, returning to order.html causes an order.html load event; the order.html body element has an onload attribute that calls a shopcartindex.html refresh_ship_details( ) function and passes thereto the ship_details object.

<body ... onload="parent.refresh_ship_details(parent.ship_details);">

The refresh_ship_details( ) function also gives the ship_details object a shipform identifier and then individually assigns the values of shipform's properties to the values of the corresponding order form fields.

function refresh_ship_details(shipform) {
    parent.main.document.order.comments.value = shipform.comments;
    parent.main.document.order.name_first.value = shipform.f_namea;
    parent.main.document.order.name_last.value = shipform.l_namea;
    parent.main.document.order.email.value = shipform.email;
    ...
    parent.main.document.order.same_flag.value = shipform.sameflag;
    parent.main.document.order.ship_name.value = shipform.shipname;
    parent.main.document.order.ship_address1.value = shipform.ad_oneb;
    ... }


In sum, the add_ship_details( ) function scoops up the visitor's data upon leaving the order.html page and the refresh_ship_details( ) function reloads the visitor's data upon returning to the order.html page. We're all set.

After the add_ship_details( ) function fires, the ship_details/shipform object holds onto the order.html data for as long as the visitor is at the shopping cart. If the visitor leaves and later returns to the cart, then the ship_details object is built from scratch as detailed in Blog Entry #287 (vide supra).

BTW, the Customer Information / Details table's Country field has an initial value of UK (all of the other customer/shipping fields are initially empty), but the visitor does not see this value upon arriving at the order.html page as it is cleared by the refresh_ship_details( ) function.

Filling the cookie jar

The order.html unload event is the right point at which to set in motion the otherwise-inactive* cookie functionality of the shopping cart as that functionality acts on data written to the ship_details object by the add_ship_details( ) function. The set-cookies part of the functionality (vis-à-vis the get-cookies part*) begins with the shopcartindex.html go_with_cookie( ) function. My preferred way to register the add_ship_details( ) and go_with_cookie( ) listeners on the order.html document is to put a

window.onunload = function ( ) {
    parent.add_ship_details( );
    parent.go_with_cookie( ); }


function in order.html's first script element. (*We'll see in the following entry that the get-cookies part is actually not 'inactive': it just doesn't have any cart cookies to work with.)

Here's the go_with_cookie( ) function:

function go_with_cookie( ) {
    setCookieArray("gifttails",
    parent.ship_details.f_namea,
    parent.ship_details.l_namea,
    parent.ship_details.email,
    parent.ship_details.ad_onea,
    parent.ship_details.ad_twoa,
    parent.ship_details.citya,
    parent.ship_details.statea,
    parent.ship_details.countrya,
    parent.ship_details.zipa); }


The go_with_cookie( ) function calls a setCookieArray( ) function and passes it 10 arguments:
(0) a gifttails string and
(1-9) the values of the first nine fields of the Customer Information / Details table (which have just been loaded into the ship_details object by the add_ship_details( ) function, as described above).

The setCookieArray( ) function is preceded by two lines of top-level code that create a one-year-into-the-future expdate date that we'll use to set an expiration date for our cookies.

var expdate = new Date( );
expdate.setTime(expdate.getTime( ) + (24 * 60 * 60 * 1000 * 365));


It is not necessary to postdate expdate via a millisecond-based calculation: expdate.setFullYear(expdate.getFullYear( ) + 1); will do the trick.

Via a for loop whose i counter runs from 0 to 8, the setCookieArray( ) function iteratively sends gifttails+i, setCookieArray.arguments[i+1], and expdate to a setCookie( ) function.

function setCookieArray(name) {
    temp_length = setCookieArray.arguments.length - 1;
    for (var i = 0; i < temp_length; i++) {
        data = setCookieArray.arguments[i + 1];
        setCookie(name + i, data, expdate); } }


FYI: The use of arguments as a property of a Function object is deprecated.

The setCookie( ) function is called nine times: each run adds a
gifttails+i=setCookieArray.arguments[i+1]
cookie to the shopcartindex.html document.cookie string.

function setCookie(name, value, expires) {
    if (!expires) expires = new Date( );
    document.cookie = name + "=" + escape(value) + "; expires=" + expires.toGMTString( ) + "; path=/"; }


• The escape( ) function is deprecated: use the encodeURIComponent( ) function instead.
• The toGMTString( ) method is deprecated: use the toUTCString( ) method instead.

So, if our visitor enters

Joe Blow's sample cookie info

into the Customer Information / Details table, then after unloading the order.html page, the shopcartindex.html document.cookie string will read:

gifttails0=Joe; gifttails1=Blow; gifttails2=username%40gmail.com; gifttails3=1234%20Main%20Street; gifttails4=; gifttails5=New%20Orleans; gifttails6=LA; gifttails7=USA; gifttails8=70118

This output assumes that there are no other cookies associated with the shopcartindex.html page.

Cookie retrieval

Let's do this next time.


Powered by Blogger

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