Step 1: Loading Shopping Bag

JavaScript and the resident browser take care of most of the work here, although the user plays a small part. Consider the first page loaded—index.html. You can see what it looks like in Example 8.1.

Example 8-1. index.html

     1  <HTML>
     2  <HEAD>
     3  <TITLE>Shopping Bag</TITLE>
     4  <STYLE TYPE="text/css">
     5  <!--
     6  #welcome { text-align: center; margin-top: 150}
     7  //-->
     8  </STYLE>
     9  <SCRIPT LANGUAGE="JavaScript">
    10  <!--
    11  var shopWin = null;
    12  var positionStr = '';
    13  function whichBrowser() {
    14    if(navigator.appVersion < 4) { 
    15      alert("You need MSIE 4.x or Netscape Navigator 4.x to use " + 
    16        "Shopping Bag.")
    17      return false;
    18      }
    19    return true;
    20    }
    21  
    22  function launch() {
    23    if(!whichBrowser()) { return; }
    24    if(navigator.appName == "Netscape") 
    25      { positionStr = ",screenX=0,screenY=0"; }
    26    else { positionStr = ",fullscreen=yes"; }
    27    if(shopWin == null) {
    28      shopWin = open("shopset.html", "", "width=" + screen.width + 
    29        ",height=" + screen.height + positionStr);
    30      }
    31    }
    32  function closeUpShop() {
    33    if (shopWin != null) {
    34      if (typeof(shopWin) == "object") {
    35        shopWin.close();
    36        }
    37      }
    38    }
    39  window.onunload = closeUpShop;
    40  //-->
    41  </SCRIPT>
    42  </HEAD>
    43  <BODY>
    44  <DIV ID="welcome"> 
    45    <H1>Welcome to Shopping Bag!!!</H1>
    46    <A HREF="javascript: launch();">Begin</A>
    47  </DIV>
    48  </BODY>
    49  </HTML>

That might seem like a lot of JavaScript for a page that prints only five words on the screen; however, the additional code makes for a slightly better application. JavaScript defines and initializes a top-level member for multiple window management and identifies the browser type to provide cross-platform code when the remote window opens.

Top-Level Members

The variables and function in lines 11 and 32-38 exist to enforce one rule: if the main window closes, close the remote window too. Otherwise, Shopping Bag might experience a violent JavaScript-error death if the user decides, say, to reload the remote window.

Here’s line 11:

var shopWin = null;

And lines 32-38:

function closeUpShop() {
  if (shopWin != null) {
    if (typeof(shopWin) == "object") {
      shopWin.close();
      }
    }
  }
window.onunload = closeUpShop;

Variable shopWin, originally set to null, is later set to the remote window object (I’m jumping the gun, but see line 27). Function closeUpShop() is called when this window closes. This function determines whether the user still has the remote Shopping Bag open, and if so, closes it. If shopWin does not equal null and is of the type object, the remote window must be open. closeUpShop() closes the remote window just prior to unloading.

The only thing that concerns the user at this point is clicking the “Begin” link to open the remote window. That opens shopset.html, a frameset. You’ll find the code in Example 8.2.

Example 8-2. shopset.html

     1  <HTML>
     2  <HEAD>
     3  <TITLE>Shopping Bag Frameset</TITLE>
     4  <SCRIPT LANGUAGE="JavaScript1.2">
     5  <!--
     6  function resetOpener() {
     7    opener.shopWin = null;
     8    }
     9  //-->
    10  </SCRIPT>
    11  </HEAD>
    12  <FRAMESET ROWS="80%,20%" FRAMEBORDER=0 BORDER=0 onLoad="self.focus();" 
    13    onUnLoad="resetOpener();">
    14  <FRAME SRC="intro.html" NORESIZE>
    15  <FRAME SRC="manager.html" NORESIZE>
    16  </FRAMESET>
    17  </HTML>

This is your basic frameset with two rows. One is assigned a source of intro.html; the other gets manager.html. Not much JavaScript here, but let’s see what there is:

function resetOpener() {
  opener.shopWin = null;
  }

Lines 6-8 have a function named resetOpener() called whenever the document in the parent window (in this case, the frameset) is unloaded. By setting opener.shopWin to null, resetOpener() allows the user to close the remote Shopping Bag window and reopen it again with the same “Begin” link.

That might seem trivial, even unnecessary. Notice, however, that in index.html (line 27), the extra window is opened only if shopWin equals null. Closing the window does not set shopWin equal to null, so resetOpener() steps in to help. Notice also that the onLoad event handler in the FRAMESET tag is set to self.focus(). This assures that the remote window doesn’t open and load behind the main window, leaving the user wondering what happened.

That basically takes care of this frameset loading. There are still three pages that still need to load—intro.html, manager.html, and inventory.js. intro.html is a static help file. As manager.html loads, the embedded source file inventory.js comes with it. manager.html is worthy of a little bit of discussion later in this section, but inventory.js has the code we need to examine now. It’s fairly long, but you’ll get a good idea of the structure used to build the inventory.

inventory.js

inventory.js contains three functions. The first two are constructor functions. One defines a product; the other defines a product category. The last function creates arrays of objects created by those constructors. See for yourself in Example 8.3.

Example 8-3. inventory.js

     1  function product(name, description, price, unit) {
     2    this.name = name;
     3    this.description = description;
     4    this.price = price;
     5    this.unit = unit;
     6    this.plu = name.substring(0, 3).toUpperCase() + 
     7      parseInt(price).toString();
     8    this.icon = new Image();
     9    return this;
    10    }
    11  function category(name, description) {
    12    this.name = name;
    13    this.description = description;
    14    this.prodLine = eval(name);
    15    var imgDir = "images/" + name.toLowerCase() + "/";
    16    for (var i = 0; i < this.prodLine.length; i++) {
    17      this.prodLine[i].icon.src = imgDir + 
    18        this.prodLine[i].name.toLowerCase() + ".gif";
    19      }
    20    return this; 
    21    }
    22  function makeProducts() {
    23    Appliances = new Array(
    24      new product("Dryer", 
    25        "Stylish pastel design, contemporary two-button engineering.", 
    26        263.37  , 
    27        "each"), 
    28      new product("Hairdryer", 
    29        "Fancy yellowish blast, and durable cord. No expense spared.", 
    30        1.15, 
    31        "pair"), 
    32      new product("Oven", 
    33        "Made in the 1850's, this coal-powered unit quickly blackens any" + 
    34          "favorite dish.", 
    35        865.78, 
    36        "each"), 
    37      new product("Radio", 
    38        "Revolutionary one-channel technology. White noise and static" + 
    39          "included.", 
    40          15.43, 
    41          "each"), 
    42      new product("Toaster", 
    43        "BBQ-style toaster. Only a moderate shock hazard.", 
    44        25.78, 
    45        "each"),
    46      new product("Washer", 
    47        "Does a great job on partially everything.", 
    48        345.61, 
    49        "each")
    50       );
    51  
    52    Buildings = new Array(
    53      new product("Barn", 
    54        "Complete with rusty silo and rotting doors. Pig sty sold" + 
    55        "separately.", 
    56        6350.57, 
    57        "each"), 
    58      new product("Lighthouse", 
    59        "Made of cement. Assorted light bulbs. Three AA batteries " + 
    60        "not included.", 
    61        12351.15, 
    62        "each"), 
    63      new product("Igloo", 
    64        "Made from top grade snow blocks, and includes a chimney and " + 
    65          "5-ton air conditioning unit.", 
    66        954.76, 
    67        "each"), 
    68      new product("City", 
    69        "Buildings, streets, lights, skyline. Excellent volume purchase.", 
    70        334165.95, 
    71        "each"), 
    72      new product("Castle", 
    73        "Sturdy medieval design, complete with alligators in moat, and " + 
    74          "remote control drawbridge.", 
    75        93245.59, 
    76        "each"),
    77      new product("Tower", 
    78        "Really tall. Ideal for winning friends and spotting forest " + 
    79          "fires.", 
    80          24345.87, 
    81         "pair")
    82       );
    83  
    84    Clothing = new Array(
    85      new product("Bowtie", 
    86        "Swell red fabric. Doubles a bow for Christmas wreaths or " + 
    87          "birthday gifts.", 
    88        5.41, 
    89        "five"), 
    90      new product("Necktie", 
    91        "Be the first (and probably only) one (ever) on your block. " + 
    92          "Made of genuine burlap.", 
    93        1.15, 
    94        "each"), 
    95      new product("Purse", 
    96        "Attractive green material. Wards off most mammals.", 
    97        18.97, 
    98        "each"), 
    99      new product("Jacket", 
   100        "Plush fake fur with fiberglass lining. Washer safe.", 
   101        180.72, 
   102        "each"), 
   103      new product("Glove", 
   104        "Covers all four fingers and one thumb. Fancy latex design.", 
   105        6.59, 
   106        "three"),
   107      new product("Dress", 
   108        "Found at a garage sale. Also doubles as a picnic table cover.", 
   109        7.99, 
   110        "each"), 
   111      new product("Watch", 
   112        "Geuine replica. Doesn't tell time. You have to look at it.", 
   113        6.19, 
   114        "each")
   115      );
   116  
   117    Electronics = new Array(
   118      new product("Camcorder", 
   119        "Solar-powered. Free microphone. Custom-built for blackmailing " + 
   120          "close relatives.", 
   121        60.45, 
   122        "each"), 
   123      new product("Stereo", 
   124        "Quadraphonic, pre 8-track sound. Leisure suit and roach killer " + 
   125           "shoes are optional", 
   126        54.91, 
   127        "each"), 
   128      new product("Speaker", 
   129        "Extra piece of hi-fi junk. Works best if discarded.", 
   130        1.90, 
   131        "each"), 
   132      new product("Remote", 
   133        "Dozens of buttons. Controls everything- TV, VCR, stereo, " + 
   134          "pets, local government.", 
   135        465.51, 
   136        "each"), 
   137      new product("Cellphone", 
   138        "Product of tin can technology. 35-ft calling area. Dandy " + 
   139          "lavender plastic.", 
   140        64.33, 
   141        "each"),
   142      new product("Camera", 
   143        "Takes brilliant one-color photos. Landfill safe.", 
   144        2.95, 
   145       "each"), 
   146      new product("Television", 
   147        "Two-channel UHF only model. Wow.", 
   148        22.57, 
   149        "each")
   150      );
   151  
   152    Food = new Array(
   153      new product("Cheese", 
   154        "Wait 'til you get a wiff. Puts bleu cheese to shame.", 
   155        3.05, 
   156        "chunk"), 
   157      new product("Fries", 
   158        "More grease than the local car garage. You can't beat the " + 
   159          "taste, though.", 
   160        1.15, 
   161        "box"), 
   162      new product("Eggs", 
   163        "The standard breakfast staple.", 
   164        1.07, 
   165        "dozen"), 
   166      new product("Drumstick", 
   167        "This leg of pterodactyl is a sure crowd pleaser.", 
   168        100.00, 
   169        "half ton"), 
   170      new product("Chips", 
   171        "Opened-bag flavor. Guaranteed stale, or your money back.", 
   172        1.59, 
   173        "bag"),
   174      new product("Shrimp", 
   175        "Great raw, served above room temperature.", 
   176        2.95, 
   177        "each")
   178      );
   179  
   180    Hardware = new Array(
   181      new product("Chainsaw", 
   182        "Be your own eager beaver with this tree-cutting machine.", 
   183        226.41, 
   184        "each"), 
   185      new product("Cycle", 
   186        "Mow down the wheat field with a few swipes. Just like the " + 
   187          "Grim Reaper's.", 
   188        11.15, 
   189        "each"), 
   190      new product("Hammer", 
   191        "Tempered steel head, fiberglass handle. Perfect for hitting " + 
   192          "things.", 
   193        9.87, 
   194        "each"), 
   195      new product("Lawnmower", 
   196        "Self-propelled (you propel it yourself).", 
   197        165.95, 
   198        "each"), 
   199      new product("Pliers", 
   200        "Perfect for eye brows and nose hairs.", 
   201        6.59, 
   202        "each"),
   203      new product("Stake", 
   204        "This 2-in-1 miracle secures tents or gets rid of vampires.", 
   205        3.95, 
   206        "pair")
   207      );
   208  
   209    Music = new Array(
   210      new product("Bongos", 
   211        "Great little noise makers for even the most sophisticated " + 
   212          "occasions.", 
   213        35.50, 
   214        "bongo"), 
   215      new product("Piano", 
   216        "It ain't grand, but this baby will make you sound like tavern " + 
   217          "material in no time.", 
   218        1001.40, 
   219        "each"), 
   220      new product("Notes", 
   221        "Choose from A, B, C, D, E, F, or G. Can be reused in any song.", 
   222        2.97, 
   223        "note"), 
   224      new product("Guitar", 
   225        "Strum, strum. This one is your fast track to fame and fortune.", 
   226        241.11, 
   227        "each"), 
   228      new product("Trumpet", 
   229        "Solid copper body, and not many dents. Extra spit valve " + 
   230          "included.", 
   231         683.59, 
   232        "each")
   233      );
   234  
   235    categorySet = new Array(
   236      new category("Appliances", "Kitchen machines to make life easier"),
   237      new category("Buildings", "Architectural structures your can't " + 
   238        "resist"),
   239      new category("Clothing", "Fashionably questionable apparel for " + 
   240        "the 21st century"),
   241      new category("Electronics", "Nifty gizmos that drain your wallet"),
   242      new category("Food", "The best product to order over the Net"),
   243      new category("Hardware", "All kinds of general purpose " + 
   244        "construction tools"),
   245      new category("Music", "The hottest new instruments from places " + 
   246        "you've never heard of")
   247        );
   248    }

Product properties

Remember the JavaScript objects we used in the earlier chapters? They’re back with a vengeance. Each product is treated as an object with several properties; that is, each product has the following properties:

name

The product name

description

A basic description of the product

price

The cost of the product

unit

The unit by which the product is sold, e.g., by the dozen, the pair, per piece

plu

The price lookup number: an arbitrary product number for inventory tracking and order processing

icon

An image of each product

To achieve the desired result, the product constructor function is defined as follows in lines 1-10:

function product(name, description, price, unit) {  
  this.name = name;  
  this.description = description;  
  this.price = price;  
  this.unit = unit;  
  this.plu = name.substring(0, 3).toUpperCase() +     
    parseInt(price).toString();  
  this.icon = new Image();  
  return this;  
  }

Notice that there are six properties created, but only four arguments expected. The number of properties and the number of expected arguments aren’t correlated, but consider how each property receives its value. The first four are obvious. Properties name, description, price , and unit are all assigned the values of the matching argument names.

plu is a different story, though. It’s actually a composite of the name and price properties. The uppercase of the first three characters of name plus the integer value of price make the PLU number. So a boat that cost $5501.00 has the plu property of BOA5501. Keep in mind that this is arbitrary. The products you sell probably have their own tracking numbers. I did it this way to keep things simple. The last property is icon, which for now is assigned a new Image object. There’s no need for an argument to do that.

Product category properties

We know that each product is really a product object. Likewise, each product category is really a category object. Just as products have properties, so do categories. Have a look at the properties of the category object:

name

The category name

description

A basic description of the category

prodLine

All the products within that category

A category constructor saves the day in lines 11-21:

function category(name, description) {
  this.name = name;
  this.description = description;
  this.prodLine = eval(name);
  var imgDir = "images/" + name.toLowerCase() + "/";
  for (var i = 0; i < this.prodLine.length; i++) {
    this.prodLine[i].icon.src = imgDir +
       this.prodLine[i].name.toLowerCase() + ".gif";
    }
  return this;
   }

Each category has three properties—a string called name, another string called description, and an array called prodLine. Properties name and description seem straightforward, but where does the array come from, and how do you get it using eval()? The answers to both will be clearer in a moment, but this is the basic strategy: whatever you name the category, the product line will be an array of the same name. For example, if you name a category stereos, then the array containing all the stereo products will be called stereos. That is, prodLine would be a copy of the variable stereo, which is an array of different stereo products.

Remember that each product has a property called icon, which is an Image object that hasn’t been assigned a source. Let’s get some more mileage from the category name. Not only does every category keep its product line in an array of the same name, but all the images for the products in that category are stored in a directory of the same name.

All the products in the Music category are kept in the music/ directory. The Hardware category has images in the hardware/ directory, and so on. That sounds logical. If this type of directory structure is in place, then we can preload all the images for the category when the category is constructed. Lines 16-19 handle the job:

var imgDir = "images/" + name.toLowerCase() + "/";
for (var i = 0; i < this.prodLine.length; i++) {
  this.prodLine[i].icon.src = imgDir +
     this.prodLine[i].name.toLowerCase() + ".gif";
  }

If you examine the directory structure in ch08, you’ll see this:

images/
appliances/
buildings/
clothing/
electronics/
food/
hardware/
music/

Line 17 sets the SRC property of each icon (an Image) to images/ + the product name in lowercase + / + ".gif.” This goes back to those naming conventions I’ve been talking about in several previous chapters. Each product has an image of the same name and is located in a folder with the same name as the category to which the product belongs. Here’s the formula:

Each product image URL = images/category/product_name.gif

If you browse ch08images, you’ll notice each image name corresponds with a Shopping Bag product located in a directory corresponding with a Shopping Bag category. This keeps things simple, and lets you add, remove, and keep track of products very easily.

Note

If you have many large images, consider omitting image preloading. It sure is nice to have those images on the client machine so that the browsing experience has no delay. If you have lots of high-quality, large-sized images, though, the user might not be willing to wait until 500K of images load. Use your own discretion.

Creating products and categories

You’ve seen the constructor functions; now let’s put them to work. The first thing to do is create the products, then the categories. Function makeProducts() does both. Here are lines 22-248. Since much of it is the same product constructor called repeatedly, this is the abbreviated version:

function makeProducts() {
  Appliances = new Array(
    new product("Dryer",
       "Stylish pastel design, contemporary two-button engineering.",
       263.37  ,
       "each"),
     new product("Hairdryer",
       "Fancy yellowish blast, and durable cord. No expense spared.",
       1.15,
       "pair"),
     new product("Oven",
       "Made in the 1850's, this coal-powered unit quickly blackens any" +
         "favorite dish.",
       865.78,
       "each"),
     new product("Radio",
       "Revolutionary one-channel technology. White noise and static" +
         "included.",
         15.43,
         "each"),
     new product("Toaster",
       "BBQ-style toaster. Only a moderate shock hazard.",
       25.78,
       "each"),
    new product("Washer",
       "Does a great job on partially everything.",
       345.61,
       "each")
     );
...
...  and so on ...
...
  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")
       );
  }

                  

First come the products. Variable Appliances is set to an array. Each element in the array is a product object. Each call to product carries with it the expected arguments for building a product—a name, description, price, and unit. This happens for Buildings, Clothing, Electronics, Food, Hardware, and Music.

All that’s left is coming up with the categories. Actually, the category names are already in place (Appliances, Buildings, Clothing, etc.); we just have to let Shopping Bag know that. Lines 235-248 make it happen:

categorySet = new Array(
    new category("Appliances", "Kitchen machines to make life easier"),
    new category("Buildings", "Architectural structures your 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")
       );

Variable categorySet is also an array. Each element in the array is a category object constructed with two arguments, a name, and a description. The first argument is assigned to the name property, and the second is assigned to the description property. Take another look at line 14 of the category constructor:

this.prodLine = eval(name);

prodLine is set to the value of eval(name). So the call to category() in line 249 means prodLine equals eval("Appliances"), which equals Appliances. Now the category named Appliances knows about all its products (there in the prodLine array). Each element in categorySet represents another Shopping Bag category. This makes adding and removing them a snap.

Creating the shopping bag

The products have all been created. The only thing left to create during load time is . . . well . . . a shopping bag. All this shopping bag needs is a few properties to handle the payment and an array to store all the products the user selects. The Bag() constructor in manager.html defines the one and only shopping bag. Here are lines 21-31 of manager.html, shown in Example 8.4 later in the chapter:

function Bag() {
  this.taxRate   = .06;
  this.taxTotal   = 0;
  this.shipRate   = .02;
  this.shipTotal  = 0;
  this.subTotal   = 0;
  this.bagTotal   = 0;
  this.things   = new Array();
  }
shoppingBag = new Bag();

There are two variables to hold arbitrary rates, taxRate and shipRate . One is a multiple for computing state sales tax. The other, also a multiple, is used to calculate shipping charges. Your tax structure will likely differ, but you can at least see the direction here. Three other variables, taxTotal, subTotal , and shipTotal , represent the sum of the tax, the sum of all the product selections and their quantities, and the grand sum that the user must pay, respectively. The last variable is an array. things will contain all the products, including quantities that the user selects. Variable shoppingBag is then set to the value a new Bag(). Let’s shop around.

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

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