Step 2: Displaying Products

With the application loaded, one of the first things the user will want to do is view the inventory. The user can navigate from category to category with the “Previous Category” and “Next Category” links or from product to product with the “Previous Product” and “Next Product” links. Here’s how it works. Recall lines 235-248 in inventory.js:

categorySet = new Array(
    new category("Appliances", "Kitchen machines to make life easier"),
    new category("Buildings", "Architectural structures you can't " +
       "resist"),
    new category("Clothing", "Fashionably questionable apparel for " +
       "the 21st century"),
    new category("Electronics", "Nifty gizmos that drain your wallet"),
    new category("Food", "The best product to order over the Net"),
    new category("Hardware", "All kinds of general purpose " +
       "construction tools"),
    new category("Music", "The hottest new instruments from places " +
       "you've never heard of")
       );

            

categorySethas seven category objects. The first one is referenced as categorySet[0], the next categorySet[1], and so forth. No matter what product a user is viewing, Shopping Bag knows the number (in this case, 0-6) of the category to which it belongs. If the user decides to move to the previous category, Shopping Bag subtracts 1 from the current category number, and shows the first product in that category. If Shopping Bag is in category and the user wants to move to the previous category, Shopping Bag starts back at the top category number (in this case, 6).

If the user wants to view the next category, Shopping Bag simply adds 1 to the current category number. If the user is already in the last category, Shopping Bag starts at again.

The same holds true for the products. Each category has a certain number of products. Shopping Bag knows the number to reference the current product in view, so choosing “Previous Product” or “Next Product” will cause the next or previous product to be displayed simply by subtracting or adding one, depending on what the user wants to do.

When the user reaches the last product in a category (going forwards), Shopping Bag realizes this and begins with product of the next category. When the user reaches the first product in a category (going backwards), Shopping Bag realizes this as well, and begins with the last product of the previous category.

If I’ve confused you with that last explanation, the next diagram should help. Figure 8.10 shows how Shopping Bag takes the user through the categories. It works the same way with navigating through the products. When you reach the last product in one category, you move to the first product in the following category.

Navigating through the categories

Figure 8-10. Navigating through the categories

manager.html

All this functionality comes from the file manager.html. Example 8.4 shows the code.

Example 8-4. manager.html

     1  <HTML>
     2  <HEAD>
     3  <TITLE>Shopping Bag Manager</TITLE>
     4  <STYLE TYPE="text/css">
     5  <!--
     6  TD {font-weight: bold; margin-left: 20; margin-right: 20; padding: 10}
     7  //-->
     8  </STYLE>
     9  </HEAD>
    10  <BODY onLoad="freshStart(); makeProducts();" 
    11    LINK=BLUE ALINK=BLUE VLINK=BLUE>
    12  <SCRIPT LANGUAGE="JavaScript1.2" SRC="inventory.js"></SCRIPT>
    13  <SCRIPT LANGUAGE="JavaScript1.2">
    14  <!--
    15  var gimmeControl = false;
    16  var browseControl = false;
    17  var curCLoc = -1;
    18  var curPLoc = -1;
    19  var infoStr = '';
    20  var shoppingBag;
    21  function Bag() {
    22    this.taxRate   = .06;
    23    this.taxTotal   = 0;
    24    this.shipRate   = .02;
    25    this.shipTotal  = 0;
    26    this.subTotal   = 0;
    27    this.bagTotal   = 0;
    28    this.things   = new Array();
    29    }
    30  
    31  shoppingBag = new Bag();
    32  
    33  function showStore() {
    34    gimmeControl = false;
    35    var header = '<HTML><TITLE>Category</TITLE><BODY BGCOLOR=FFFFFF>';
    36    var intro = '<H2>Shopping Bag Product Categories</H2><B>';
    37    var footer = '</DL></BLOCKQUOTE></BODY></HTML>';
    38    var storeStr = '<BLOCKQUOTE><DL>';
    39    for (var i = 0; i < categorySet.length; i++) {
    40      storeStr += '<DT><A HREF="javascript: parent.frames[1].reCall(' + 
    41        i + ', 0);">' + categorySet[i].name + '</A><DD>' + 
    42        categorySet[i].description + '<BR><BR>';
    43      }
    44    infoStr = header + intro + storeStr + footer;
    45    parent.frames[0].location.replace('javascript: 
    46  parent.frames[1].infoStr'),
    47    }
    48  
    49  function portal() {
    50    gimmeControl = false;
    51    parent.frames[0].location.href = "search/index.html";
    52    }
    53  function display(cOffset, pOffset) {
    54    if(!browseControl) {
    55      alert("Start shopping by selecting a product category from " + 
    56        "Show All Categories or searching products from Product Search.");
    57      return;
    58      }
    59    gimmeControl = true;
    60    if (curPLoc + pOffset < 0 || curPLoc + pOffset == 
    61      categorySet[curCLoc].prodLine.length) {
    62      if (curPLoc + pOffset < 0) {     
    63        if (curCLoc - 1 < 0) { curCLoc = categorySet.length - 1; }
    64        else { curCLoc--; }
    65        curPLoc = categorySet[curCLoc].prodLine.length - 1;    
    66        }
    67      else if (curPLoc + pOffset == categorySet[curCLoc].prodLine.length) {
    68        if (curCLoc + 1 == categorySet.length) { curCLoc = 0; }
    69        else { curCLoc++; }
    70        curPLoc = 0;
    71        }
    72      }
    73    else {
    74      if (curCLoc + cOffset < 0 || curCLoc + cOffset == 
    75        categorySet.length) {
    76        curCLoc = (curCLoc + cOffset < 0 ? categorySet.length - 1 : 0);
    77        }
    78      else { curCLoc += cOffset; }
    79      if (cOffset == -1 || cOffset == 1) { curPLoc = 0; }
    80      else if (pOffset == 0) {
    81        curPLoc = (curPLoc >= categorySet[curCLoc].prodLine.length ? 0 : 
    82          curPLoc)
    83        }
    84      else { curPLoc = curPLoc + pOffset; }
    85      }
    86    infoStr = '<HTML><HEAD><TITLE>Product Name</TITLE></HEAD>' +
    87      '<BODY><TABLE CELLPADDING=3><TR><TD VALIGN=TOP COLSPAN=2>' + 
    88      '<FONT FACE=Tahoma><H2>Shopping Bag: <I>' + 
    89      categorySet[curCLoc].name + '</I></H2><TR>' + 
    90      '<TD VALIGN=TOP><IMG SRC="' + 
    91      categorySet[curCLoc].prodLine[curPLoc].icon.src +  
    92      '"></TD><TD VALIGN=TOP><FONT FACE=Tahoma>' + 
    93      '<B>Name: </B>' +  categorySet[curCLoc].prodLine[curPLoc].name + 
    94      '<BR><B>Description: </B>' +  
    95      categorySet[curCLoc].prodLine[curPLoc].description + '<BR>' +
    96      '<B>Price: </B> $' + 
    97      numberFormat(categorySet[curCLoc].prodLine[curPLoc].price) + '/' + 
    98      categorySet[curCLoc].prodLine[curPLoc].unit + '<BR>' + 
    99      '<B>PLU: </B>' + categorySet[curCLoc].prodLine[curPLoc].plu + 
   100      '</TD></TR></TABLE></BODY></HTML>';
   101    parent.frames[0].location.href = 'javascript: 
   102  parent.frames[1].infoStr';
   103    }
   104  
   105  function reCall(cReset, pReset) {
   106    browseControl = true; 
   107    curCLoc = cReset;
   108    curPLoc = pReset;
   109    display(0, 0);
   110    }
   111   
   112  function gimmeOne() {
   113    if (!gimmeControl) { 
   114      alert("Nothing on this screen to give you.");
   115      return;
   116      }
   117    for (var i = 0; i < shoppingBag.things.length; i++) { 
   118      if (categorySet[curCLoc].prodLine[curPLoc].plu == 
   119        shoppingBag.things[i].plu) {
   120        alert("That's already in your bag. You can change the quantity " + 
   121          "by choosing View/Change Bag.");
   122        return;
   123        } 
   124      }
   125    shoppingBag.things[shoppingBag.things.length] = 
   126      categorySet[curCLoc].prodLine[curPLoc];
   127    shoppingBag.things[shoppingBag.things.length - 1].itemQty = 1;
   128    shoppingBag.things[shoppingBag.things.length - 1].category = 
   129      categorySet[curCLoc].name;
   130    alert("OK. You put the " + 
   131       shoppingBag.things[shoppingBag.things.length - 1].name + 
   132      " in your bag.");
   133    }
   134  
   135  function showBag() {
   136    if (shoppingBag.things.length == 0) { 
   137      alert("Your bag is currently empty. Put some stuff in.");
   138      return;
   139      }
   140    gimmeControl = false;
   141    var header = '<HTML><HEAD><TITLE>Your Shopping Bag</TITLE>' +
   142      '</HEAD><BODY BGCOLOR=FFFFFF ' + 
   143      'onLoad="parent.frames[1].runningTab(document.forms[0]);">';
   144    var intro = '<H2>Your Shopping Bag!!!</H2>' + 
   145      '<FORM onReset="' + 
   146      'setTimeout('parent.frames[1].runningTab(document.forms[0])', ' + 
   147      '25);">';
   148    var tableTop = '<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=5>' + 
   149      '<TR><TH><B>Index' + 
   150      '<TH><B>Product<TH><B>Category' + 
   151      '<TH><B>PLU<TH><B>Unit Price' + 
   152      '<TH><B>Quantity<TH><B>Product Total' + 
   153      '<TH><B>Remove' + 
   154      '</TR>';
   155    var itemStr = '';
   156    for (var i = 0; i < shoppingBag.things.length; i++) {
   157      itemStr += '<TR>' + 
   158        '<TD ALIGN=CENTER>' + (i + 1) + '</TD>' + 
   159        '<TD>' + shoppingBag.things[i].name + '</TD>' + 
   160        '<TD>' + shoppingBag.things[i].category + '</TD>' + 
   161        '<TD>' + shoppingBag.things[i].plu + '</TD>' + 
   162        '<TD ALIGN=RIGHT>$' + 
   163          parent.frames[1].numberFormat(shoppingBag.things[i].price) + 
   164        '</TD>' + 
   165        '<TD ALIGN=CENTER>' + 
   166        parent.frames[1].genSelect(shoppingBag.things[i].price, 
   167          shoppingBag.things[i].itemQty, i) + '</TD>' + 
   168        '<TD ALIGN=CENTER><INPUT TYPE=TEXT SIZE=10 VALUE="' + 
   169        parent.frames[1].numberFormat(shoppingBag.things[i].price * 
   170          shoppingBag.things[i].itemQty) + 
   171        '" onFocus="this.blur();"></TD>' +
   172        '<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX></TD>' + 
   173        '</TR>';
   174      }
   175    var tableBottom = '<TR>' + 
   176      '<TD ALIGN=RIGHT COLSPAN=6>SubTotal:</TD>' + 
   177      '<TD ALIGN=CENTER><INPUT TYPE=TEXT SIZE=10 NAME="subtotal" ' + 
   178      onFocus="this.blur();"></TD></TR>' +
   179      '<TR><TD ALIGN=RIGHT COLSPAN=6> + 6% Tax:</TD>' + 
   180      '<TD ALIGN=CENTER><INPUT TYPE=TEXT SIZE=10 NAME="tax" ' + 
   181      'onFocus="this.blur();"></TD></TR><TR><TD ALIGN=RIGHT COLSPAN=6>' + 
   182      '2% Shipping:</TD><TD ALIGN=CENTER><INPUT TYPE=TEXT ' + 
   183      'SIZE=10 NAME="ship" onFocus="this.blur();"></TD></TR>' + 
   184      '<TR>' +
   185      '<TD ALIGN=RIGHT COLSPAN=3><INPUT TYPE=BUTTON VALUE="Check Out" ' + 
   186      'onClick="parent.frames[1].checkOut(this.form);"></TD>' +  
   187      '<TD ALIGN=RIGHT><INPUT TYPE=RESET VALUE="Reset Qtys"></TD>' + 
   188      '<TD ALIGN=RIGHT><INPUT TYPE=BUTTON VALUE="Change Bag" ' + 
   189      'onClick="parent.frames[1].changeBag(this.form, true);"></TD>' + 
   190      '<TD ALIGN=RIGHT>Total:</TD><TD ALIGN=CENTER>' + 
   191      '<INPUT TYPE=TEXT NAME="total" SIZE=10 onFocus="this.blur();">' + 
   192      '</TD></TR>';
   193  
   194    var footer = '</TABLE></FORM></BODY></HTML>';
   195    infoStr = header + intro + tableTop + itemStr + tableBottom + footer;
   196    parent.frames[0].location.replace('javascript: 
   197       parent.frames[1].infoStr'),
   198    }
   199  
   200  function genSelect(priceAgr, qty, idx) {
   201    var selStr = '<SELECT onChange="this.form.elements[' + (idx * 3 + 1) + 
   202        '].value = this.options[this.selectedIndex].value; 
   203    parent.frames[1].runningTab(this.form);">';
   204    for (var i = 1; i <= 10; i++) {
   205      selStr += '<OPTION VALUE="' + numberFormat(i * priceAgr) + '"' + 
   206        (i == qty ? ' SELECTED' : '') + '>' + i; 
   207      }
   208    selStr += '</SELECT>';
   209    return selStr;
   210    }
   211  
   212  function runningTab(formObj) {
   213    var subTotal = 0;
   214    for (var i = 0; i < shoppingBag.things.length; i++) {
   215      subTotal += parseFloat(formObj.elements[(i * 3) + 1].value); 
   216      }
   217    formObj.subtotal.value = numberFormat(subTotal);
   218    formObj.tax.value = numberFormat(subTotal * shoppingBag.taxRate);
   219    formObj.ship.value = numberFormat(subTotal * shoppingBag.shipRate); 
   220    formObj.total.value = numberFormat(subTotal + 
   221        round(subTotal * shoppingBag.taxRate) + 
   222        round(subTotal * shoppingBag.shipRate));
   223    shoppingBag.subTotal = formObj.subtotal.value;
   224    shoppingBag.taxTotal = formObj.tax.value;
   225    shoppingBag.shipTotal = formObj.ship.value;
   226    shoppingBag.bagTotal = formObj.total.value;
   227    }
   228  
   229  function numberFormat(amount) {
   230    var rawNumStr = round(amount) + '';
   231    rawNumStr = (rawNumStr.charAt(0) == '.' ? '0' + rawNumStr : rawNumStr);
   232    if (rawNumStr.charAt(rawNumStr.length - 3) == '.') {
   233      return rawNumStr
   234      }
   235    else if (rawNumStr.charAt(rawNumStr.length - 2) == '.') {
   236      return rawNumStr + '0';
   237      }
   238    else { return rawNumStr + '.00'; }
   239    }
   240  function round(number,decPlace) {
   241    decPlace = (!decPlace ? 2 : decPlace);
   242    return Math.round(number * Math.pow(10,decPlace)) / 
   243      Math.pow(10,decPlace);
   244    }
   245   
   246  function changeBag(formObj, showAgain) {
   247    var tempBagArray = new Array();
   248    for (var i = 0; i < shoppingBag.things.length; i++) {
   249      if (!formObj.elements[(i * 3) + 2].checked) {
   250        tempBagArray[tempBagArray.length] = shoppingBag.things[i];
   251        tempBagArray[tempBagArray.length - 1].itemQty = 
   252          formObj.elements[i * 3].selectedIndex + 1;
   253        }
   254      }
   255    shoppingBag.things = tempBagArray;
   256    if(shoppingBag.things.length == 0) { 
   257      alert("You've emptied your bag. Put some stuff in.");
   258      parent.frames[1].showStore();
   259      }
   260    else { showBag(); }
   261    }
   262  
   263  function checkOut(formObj) {
   264    gimmeControl = false;
   265    if(!confirm("Do you have every product in the right quantity " + 
   266      "you need? Remember that you have to choose Change Bag to " + 
   267      "remove products or change quantities. If so, choose OK to check " + 
   268      "out.")) { 
   269      return; 
   270      }
   271    if(shoppingBag.things.length == 0) { 
   272      showStore(); 
   273      return;
   274      }
   275    var header = '<HTML><TITLE>Shopping Bag Check Out</TITLE>' + 
   276      '<BODY BGCOLOR=FFFFFF>';
   277  
   278    var intro = '<H2>Shopping Bag Check Out</H2><FORM METHOD=POST ' + 
   279      'ACTION="http://your.webserver.com/cgi-bin/bag.cgi" ' + 
   280      'onSubmit="return parent.frames[1].cheapCheck(this);">';
   281  
   282    var shipInfo = '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=5>' + 
   283      '<TR><TD><B>Shipping Information</TD></TR>'+
   284      '<TR><TD>First Name</TD><TD><INPUT TYPE=TEXT NAME="fname"></TD>' + 
   285      '</TR><TR><TD>Last Name</TD><TD>' + 
   286      '<INPUT TYPE=TEXT NAME="lname"></TD></TR><TR><TD>Company Name</TD>' + 
   287      '<TD><INPUT TYPE=TEXT NAME="cname"></TD></TR><TR>' + 
   288      '<TD>Street Address1</TD><TD><INPUT TYPE=TEXT NAME="saddress1">' + 
   289      '</TD></TR><TR><TD>Street Address2</TD>' + 
   290      '<TD><INPUT TYPE=TEXT NAME="saddress2"></TD></TR><TR>' + 
   291      '<TD>City</TD><TD><INPUT TYPE=TEXT NAME="city"></TD></TR>' +
   292      '<TR><TD>State/Province</TD>' + 
   293      '<TD><INPUT TYPE=TEXT NAME="stpro"></TD></TR><TR>' + 
   294      '<TD>Country</TD><TD><INPUT TYPE=TEXT NAME="country"></TD></TR>' +
   295      '<TR><TD>Zip/Mail Code</TD><TD><INPUT TYPE=TEXT NAME="zip"></TD>' + 
   296      '</TR><TR><TD><BR><BR></TD></TR></TABLE>';
   297  
   298    var payInfo = '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=5>' + 
   299      '<TR><TD><B>Payment Information</TD></TR>'+
   300      '<TR><TD>Credit Card Type: &nbsp; &nbsp; &nbsp; </TD>' + 
   301      '<TD>Visa <INPUT TYPE=RADIO NAME="ctype" VALUE="visa" CHECKED> ' + 
   302      '&nbsp; &nbsp; &nbsp; ' + 
   303      'Amex <INPUT TYPE=RADIO NAME="ctype" VALUE="amex"> ' + 
   304      '&nbsp; &nbsp; &nbsp; ' + 
   305      'Discover <INPUT TYPE=RADIO NAME="ctype" VALUE="disc"> ' + 
   306      '&nbsp; &nbsp; &nbsp; </TD></TR>' +
   307      '<TR><TD>Credit Card Number</TD>' + 
   308      '<TD><INPUT TYPE=TEXT NAME="cnumb"></TD></TR><TR>' + 
   309      '<TD>Expiration Date</TD><TD><INPUT TYPE=TEXT NAME="edate"></TD>' + 
   310      '</TR><TR><TD><INPUT TYPE=SUBMIT VALUE="Send Order"></TD>' + 
   311      '<TD><INPUT TYPE=RESET VALUE="Clear Info"></TD></TR>' +
   312      '</TABLE>';
   313  
   314    var itemInfo = '';
   315    for (var i = 0; i < shoppingBag.things.length; i++) {
   316      itemInfo += '<INPUT TYPE=HIDDEN NAME="prod' + i + 
   317        '" VALUE="' + shoppingBag.things[i].plu + '-' + 
   318        shoppingBag.things[i].itemQty + '">';
   319      }
   320    var totalInfo = '<INPUT TYPE=HIDDEN NAME="subtotal" VALUE="' + 
   321      shoppingBag.subTotal + '">' + 
   322      '<INPUT TYPE=HIDDEN NAME="taxtotal" VALUE="' + 
   323      shoppingBag.taxTotal + '">' + 
   324      '<INPUT TYPE=HIDDEN NAME="shiptotal" VALUE="' + 
   325      shoppingBag.shipTotal + '">' + 
   326      '<INPUT TYPE=HIDDEN NAME="bagtotal" VALUE="' + 
   327      shoppingBag.bagTotal + '">';
   328  
   329    var footer = '</FORM></BODY></HTML>';
   330  
   331    infoStr = header + intro + shipInfo + payInfo + itemInfo + 
   332      totalInfo + footer;
   333      parent.frames[0].location.replace('javascript: 
   334         parent.frames[1].infoStr'),    
   335    }
   336  
   337  function cheapCheck(formObj) {
   338    for (var i = 0; i < formObj.length; i++) {
   339      if (formObj[i].type == "text" && formObj.elements[i].value == "") {
   340        alert ("You must complete all fields.");
   341        return false;
   342        }
   343      }
   344    if(!confirm("If all your information is correct, " + 
   345      "choose OK to send your order, or choose Cancel to make changes.")) { 
   346      return false; 
   347      }
   348    alert("Thank you. We'll be living off your hard-earned money soon.");
   349    shoppingBag = new Bag();
   350    showStore();
   351    return true;  
   352    }
   353  
   354  function help() {
   355    gimmeControl = false;
   356    parent.frames[0].location.href = "intro.html";
   357    }
   358  
   359  function freshStart() {
   360    if(parent.frames[0].location.href != "intro.html") { help(); }
   361    }
   362  
   363  //-->
   364  </SCRIPT>
   365  <TABLE ALIGN=CENTER BORDER=0>
   366    <TR>
   367      <TD>
   368      <A HREF="javascript: gimmeOne();">Gimme One<A>
   369      </TD>
   370      <TD>
   371      <A HREF="javascript: showBag();">View/Change Bag<A>
   372      </TD>
   373      <TD>
   374      <A HREF="javascript: showStore();">Show All Categories<A>
   375      </TD>
   376      <TD>
   377      <A HREF="javascript: portal();">Product Search<A>
   378      </TD>
   379      <TD>
   380      <A HREF="javascript: help();">Help<A>
   381      </TD>
   382    </TR>
   383  </TABLE>
   384  <TABLE ALIGN=CENTER BORDER=0>
   385    <TR>
   386      <TD>
   387      <A HREF="javascript: display(-1,0);">Previous Category<A>
   388      </TD>
   389      <TD>
   390      <A HREF="javascript: display(0,-1);">Previous Product<A>
   391      </TD>
   392      <TD>
   393      <A HREF="javascript: display(0,1);">Next Product<A>
   394      </TD>
   395      <TD>
   396      <A HREF="javascript: display(1,0);">Next Category<A>
   397      </TD>
   398    </TR>
   399  </TABLE>
   400  </BODY>
   401  </HTML>

Just a quick note. Did you see that all the JavaScript is embedded after the BODY tag? Since there is a lot of image preloading and object creation at the beginning, Netscape Navigator will display that dull gray background in the window (or the frame in this case) until all that work is done. Only then will it parse the rest of the contents. As it stands, the browser will parse the BODY tag, and hence, the BGCOLOR attribute, before going about all the work.

Variables

Following is the code that makes the product display happen. Lines 15-18 set up four variables, and lines 53-103 define function display(). Variable gimmeControl indicates to Shopping Bag whether there is something on the screen (a product) that can be added to the shopping bag. Variable browseControl enforces the rule that the user must start browsing by clicking on “Show All Categories” or “Product Search.” (See Rule 1.) You’ll see both of these variables throughout the application, but display() deals with them first, so let’s introduce them:

var gimmeControl = false;
var browseControl = false;
var curCLoc = -1;
var curPLoc = -1;

Variables curCLoc and curPLoc hold the respective index numbers of the category and product in view. These are the numbers I mentioned earlier in the section. Though both are set arbitrarily to -1, they change the moment the user chooses a category or a product. More on these two in a moment. Now let’s see how it all happens. Here are lines 53-103:

function display(cOffset, pOffset) {  
  if(!browseControl) {    
    alert("Start shopping by selecting a product category from Show " +       
      "All Categories or searching products from Product Search.");    
    return;    
    }
  gimmeControl = true;
  if (curPLoc + pOffset < 0 || curPLoc + pOffset ==
     categorySet[curCLoc].prodLine.length) {
    if (curPLoc + pOffset < 0) {
           if (curCLoc - 1 < 0) { curCLoc = categorySet.length - 1; }
      else { curCLoc--; }
      curPLoc = categorySet[curCLoc].prodLine.length - 1;
          }
    else if (curPLoc + pOffset == categorySet[curCLoc].prodLine.length) { 
     if (curCLoc + 1 == categorySet.length) { curCLoc = 0; }
      else { curCLoc++; }
      curPLoc = 0;
      }
    }
  else {
    if (curCLoc + cOffset < 0 || curCLoc + cOffset ==
       categorySet.length) {
      curCLoc = (curCLoc + cOffset < 0 ? categorySet.length - 1 : 0);
      }
    else { curCLoc += cOffset; }
    if (cOffset == -1 || cOffset == 1) { curPLoc = 0; }
    else if (pOffset == 0) {
      curPLoc = (curPLoc >= categorySet[curCLoc].prodLine.length ? 0 :
         curPLoc)
      }
    else { curPLoc = curPLoc + pOffset; }
    }  infoStr = '<HTML><HEAD><TITLE>Product Name</TITLE></HEAD>' +
    '<BODY><TABLE CELLPADDING=3><TR><TD VALIGN=TOP COLSPAN=2>' +
     '<FONT FACE=Tahoma><H2>Shopping Bag: <I>' +
       categorySet[curCLoc].name + '</I></H2><TR>' +
     '<TD VALIGN=TOP><IMG SRC="' +
     categorySet[curCLoc].prodLine[curPLoc].icon.src +
      '"></TD><TD VALIGN=TOP><FONT FACE=Tahoma>' +
     '<B>Name: </B>' +  categorySet[curCLoc].prodLine[curPLoc].name +
     '<BR><B>Description: </B>' +
      categorySet[curCLoc].prodLine[curPLoc].description + '<BR>' +
    '<B>Price: </B> $' +
     numberFormat(categorySet[curCLoc].prodLine[curPLoc].price) + '/' +
     categorySet[curCLoc].prodLine[curPLoc].unit + '<BR>' +
     '<B>PLU: </B>' + categorySet[curCLoc].prodLine[curPLoc].plu +
      '</TD></TR></TABLE></BODY></HTML>';

  parent.frames[0].location.href = 'javascript:parent.frames[1].infoStr';
  }

                  

display( )

display() has three jobs:

  1. Determine whether it is allowed to display a product.

  2. Determine which category/product the user wants to view.

  3. Display that product.

Job 1 is pretty simple. If browseControl is true, the answer is yes. browseControl is originally set to false. Once the user chooses a product from “Product Search” or chooses a category from “Show All Categories,” browseControl is set to true. Now display() can carry out jobs 2 and 3. Since a product will be displayed, gimmeControl is then set to true.

Notice that display() expects two arguments, cOffset and pOffset . One holds a value to determine how far to move from the current category number. The other does the same for the product number. cOffset and pOffset can be positive, negative, or zero. To make things simpler, let’s assume that shopper Daisy Deep Pockets has already satisfied Rule 1 and can now use the “Next” and “Previous” links to navigate through the inventory. Look at the code for each of these links in lines 386-397:

<TD>
<A HREF="javascript: display(-1,0);">Previous Category<A>
</TD>
<TD>
<A HREF="javascript: display(0,-1);">Previous Product<A>
</TD>
<TD>
<A HREF="javascript: display(0,1);">Next Product<A>
</TD>
<TD>
<A HREF="javascript: display(1,0);">Next Category<A>
</TD>

Each of these links calls display() and passes in a pair of integers. Table 8.1 explains what each function call represents. Remember that curCLoc is the category number, and curPLoc is the product number.

Table 8-1. Determining the Value of curCLoc and curCPloc

Link

Arguments Passed

Explanation

Previous Category

-1, 0

Add -1 to curCLoc; add to curPLoc.

Previous Product

0, -1

Add to curCLoc; add -1 to curPLoc.

Next Product

0, 1

Add to curCLoc; add 1 to curPLoc.

Next Category

1, 0

Add 1 to curCLoc; add to curPLoc.

Exceptions to the Rule

This makes sense. If you want to go back one category, subtract 1 from the category number. If you want to view the next product, add 1 to the category number. There are three exceptions, however, that require additional logic:

  1. There is no category or product with the number -1. If either the category number or product number is 0, and the user chooses “Previous Category” or “Previous Product,” Shopping Bag is headed straight for an error.

  2. There is no category with the number categorySet[categorySet.length]. Since there are only categorySet.length categories, the category number can never be higher than categorySet.length -1. If the category number is categorySet.length -1, and the user chooses “Next Product” or “Next Category,” we get a JavaScript error. The same holds true for the products.

  3. Navigating from category to category always displays the first product in the category no matter what the product number of the product the user is currently viewing.

Lines 60-85 provide the desired functionality and accommodate these three exceptions. This is a fairly extensive use of nested if-else statements, so you might want to review it for a while.

if (curPLoc + pOffset < 0 || curPLoc + pOffset ==
   categorySet[curCLoc].prodLine.length) {
  if (curPLoc + pOffset < 0) {
         if (curCLoc - 1 < 0) { curCLoc = categorySet.length - 1; }
    else { curCLoc--; }
    curPLoc = categorySet[curCLoc].prodLine.length - 1;
        }
  else if (curPLoc + pOffset == categorySet[curCLoc].prodLine.length) {
    if (curCLoc + 1 == categorySet.length) { curCLoc = 0; }
    else { curCLoc++; }
    curPLoc = 0;
    }
  }
else {
  if (curCLoc + cOffset < 0 || curCLoc + cOffset == categorySet.length) {
    curCLoc = (curCLoc + cOffset < 0 ? categorySet.length - 1 : 0);
    }
  else { curCLoc += cOffset; }
  if (cOffset == -1 || cOffset == 1) { curPLoc = 0; }
  else if (pOffset == 0) {
    curPLoc = (curPLoc >= categorySet[curCLoc].prodLine.length ? 0 :
       curPLoc)
    }
  else { curPLoc = curPLoc + pOffset; }
  }

The following pseudo-code rendition should clear up how this block works. The line numbers of the actual code follow each line of our translation:

IF the product number will be too small or too big THEN (73)
    IF the product number will be too small THEN (74)
        IF the category number will be too small THEN the category number
           equals the number of categories minus 1 (75)
        ELSE The category number equals itself minus 1 (76)
        The product number equals the number of products in the category
           number minus 1 (77)
ELSE IF the product number will be too big THEN (79)
        IF the category number will be too big THEN the category number
           equals 0 (80)
        ELSE the category number equals itself plus 1 (81)
        The product number equals 0 (82)
ELSE (85)
    IF the category number will be too small OR too big THEN (86)
        IF the category number is too small THEN category number equals
           the number of categories minus 1 (87)
        ELSE the category number equals 0 (88)
    ELSE the category number equals itself plus the category offset (89)
    IF the category offset equals -1 OR 1 THEN the product number
        equals 0 (90)
    ELSE IF the product offset equals 0 THEN (91)
        IF the product number is greater than or equal to the number of
            products in the category number THEN the product number
            equals 0 (92)
    ELSE the product number equals itself plus the product offset (94)

The outermost if block handles the variables if the product number falls under either of the first two exceptions. The outermost else block handles the variables if the category number falls under either of the first two exceptions. To accommodate the third exception, line 80 sets the product number equal to 0 if the category offset moves up or down by 1.

Building the display page

Knowing the category and product number, Shopping Bag can now build the HTML to display the correct product. Nearly all of the remaining code in display() is dedicated to getting that product on the screen. Look at lines 86-102:

infoStr = '<HTML><HEAD><TITLE>Product Name</TITLE></HEAD>' +
  '<BODY><TABLE CELLPADDING=3><TR><TD VALIGN=TOP COLSPAN=2>' +
   '<FONT FACE=Tahoma><H2>Shopping Bag: <I>' +
 categorySet[curCLoc].name +   '</I></H2><TR><TD VALIGN=TOP><IMG SRC="' +
   categorySet[curCLoc].prodLine[curPLoc].icon.src +
    '"></TD><TD VALIGN=TOP><FONT FACE=Tahoma><B>Name: </B>' +
     categorySet[curCLoc].prodLine[curPLoc].name + '<BR>' +
  '<B>Description: </B>' +
    categorySet[curCLoc].prodLine[curPLoc].description + '<BR>' +
  '<B>Price: </B> $' +
   numberFormat(categorySet[curCLoc].prodLine[curPLoc].price) + '/' +
   categorySet[curCLoc].prodLine[curPLoc].unit + '<BR>' +
   '<B>PLU: </B>' + categorySet[curCLoc].prodLine[curPLoc].plu +
     '</TD></TR></TABLE></BODY></HTML>';
parent.frames[0].location.href = 'javascript: parent.frames[1].infoStr';

As you can see, everything is based on one large concatenation of HTML to the initially empty string value of variable infoStr. Notice that the values of curPLoc and curCLoc are vital in referencing all the correct product information. categorySet[curCLoc] refers to the correct category, while categorySet[curCLoc].prodLine[curPLoc] refers to the correct product. Once the values of curCLoc and curPLoc have been determined, you can display the product information any way you like.

After infoStr has all the HTML it needs to display the product, the href property of the top frame is set to its value by way of a javascript:protocol. Remember that because of the scope of this protocol, you must provide an absolute reference to it (i.e., parent.frames[1].infoStr instead of just infoStr). See the JavaScript technique in Chapter 2 , for the details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.182.96