|  | Click Here!

Search the site:
EXPERT SEARCH

| Programming Languages
| Databases
| Security
| Web Services
| Network Services
| Middleware
| Components
| Operating Systems
| User Interfaces
| Groupware & Collaboration
| Content Management
| Productivity Applications
| Hardware
| Fun & Games

EarthWeb sites
Crossnodes
Datamation
Developer.com
DICE
EarthWeb.com
EarthWeb Direct
ERP Hub
Gamelan
GoCertify.com
HTMLGoodies
Intranet Journal
IT Knowledge
IT Library
JavaGoodies
JARS
JavaScripts.com
open source IT
RoadCoders
Y2K Info

# Chapter 25

# Order Entry

by Craig Eddy

CONTENTS

- Ensuring Secure Transactions on the Web
  - Authenticating the Merchant
  - Authenticating the Purchaser
  - Encrypting Web Communications
- Reviewing Cookies
- Designing the Order Entry Form
- Creating the Order Entry Form
- Examining the VBScript Code
- Testing the Application
- Review

Perhaps the biggest boon to the growth of the Internet, despite the complaints of many of the Internet's early pioneers, has been the advent of electronic commerce. The World Wide Web has been used for marketing purposes for a few years now. The availability of safe and accurate Web-based ordering is just now becoming a reality, however.

This chapter presents an example of a Web-based order entry application. It is written using a combination of HTML forms and VBScript code. The products available on this order form are static-that is, there is no connection to a database of available products. This makes the Web page easier to design and implement. To add such a connection requires using a server-side application to generate the HTML form and the appropriate VBScript code. This example won't delve into such detail.

The VBScript code in this order entry application performs the following functions:

- Accesses the document's `cookie` property to save and retrieve information about the user of the order entry form
- Calculates subtotals, shipping charges, and sales tax
- Validates the information entered, such as ZIP code
- Submits the validated information to the server-side process, which accepts the order data

This chapter begins with an overview of security as it relates to Web-based commerce such as online ordering. Then, a brief review of HTTP cookies is presented, which were discussed in Chapter 14, "Customize Your Web Page with Cookies." Finally, you'll see the example application itself.

## Ensuring Secure Transactions on the Web

When you discuss the Internet, the first and most hotly debated topic to enter the conversation is the subject of security. The concerns about security on the Web are well-founded given the ease with which a hacker can use well-documented methods to steal information from machines located on or communication occurring on a computer network such as the Internet. Although security isn't required to build and run the VBScript application presented in this chapter, a brief overview of various security concerns seems appropriate.

The typical concerns when dealing with electronic commerce follow:

- Verifying that the merchant is authentic
- Authenticating the user
- Preventing unauthorized access to information

These three concerns and possible solutions are touched on in the following sections. Another very good source of information is the Microsoft Internet Security Framework site located at `http://www.microsoft.com/intdev/security/default.htm`.

### Authenticating the Merchant

It is necessary to authenticate the merchant (or simply the Web site being accessed) because just about anyone these days can post a Web site and use a variety of methods to request credit card numbers or electronic cash payments. As a potential purchaser of products and services on the Web, you'd like to know that companies you're about to purchase from are who they say they are.

The current trend in merchant authentication is to use site certificates. These are issued by an agency that takes the responsibility to verify that organizations requesting the site certificates are who they say they are. Internet Explorer 3.0 supports the use of site certificates for authentication. Figure 25.1 shows a sample site certificate. Notice the small padlock at the right-hand side of the status bar. This indicates that Internet Explorer currently is viewing a secure and verified site.

Figure 25.1 : A sample site certificate for a secure Web site.

### Authenticating the Purchaser

Just as you as a purchaser are concerned with the authenticity of the Web site, the merchant also wants to ensure that you are who you say you are. This is less of a concern than authenticating the merchant because the merchant almost always verifies your ability to pay before providing the product or service. Still, with the possibility of credit card fraud and possible means of counterfeiting electronic cash, merchants still want to be able to verify your identity as a purchaser at their Web sites.

Internet Explorer 3.0 supports personal certificates. These are similar to site certificates and also are issued by an agency that verifies you are, indeed, who you claim to be. Currently, personal certificates are provided by an agency named VeriSign. Its Web site provides a very good overview of personal certificates and how they are obtained and used. The URL for the page is `http://digitalid.verisign.com/brw_intr.htm`.

### Encrypting Web Communications

Obviously, if you are willing to send credit card information across a public network like the Internet, you want to know that no one else can view that information. The same holds true for personal information such as household income. Several encryption standards currently are being debated, and some are in place within Web browsers today. Eventually, one or two standards will win out; until at least one gains general acceptance, everyday purchasing on the Web will remain a fantasy. Site certificates also play a vital role in securing the channels of communication.

## Reviewing Cookies

The term cookie, when used in reference to a Web page, refers to a string of characters that is stored for the particular Web page or site. The cookie can store any type of information you want. Typically, cookies store information that identifies the user of the Web browser (name, address, and phone number) or retain some state information (when the user last accessed the page, what his personal preferences related to the page are, and so on).

Using VBScript, you can access the cookie for a page using the `document.cookie` property. The format of the string is `variable_name=value`. Multiple variable/value pairs are stored by separating the pairs with a semicolon. For example, the `cookie` property may evaluate to this:

>     LastName=Eddy;FirstName=Craig;FavoriteColor=Green

This cookie has three variables stored: `LastName`, `FirstName`, and `FavoriteColor`.

You set the cookie for a page by assigning a string formatted as `variable_name=value` to the `document.cookie` property. For example,

>     document.cookie = "FavoriteColor=Yellow"

assigns or changes the setting for the variable `FavoriteColor`.

Cookie variables also can be set to expire at a certain time. This is accomplished by appending the string `;expires=date/time`. The cookie variable then is invalid after the date/time specified.

To remove a cookie variable, set its value to the string `NULL` and append an `expires` with a value set to some date in the past.

NOTE
Cookies are valid only if the page being accessed is stored on a Web server. This is due to the fact that cookies are actually part of the transport protocol used to communicate on the Web. If you attempt to assign a value to the `cookie` property for a page not located on a Web server, your script code produces a trappable runtime error.

## Designing the Order Entry Form

The order entry form created in this chapter is an order form that is static. For the sake of simplicity, no attempt is made to retrieve data from a product database and assemble an order form from that data.

The products sold using this form are framed portraits of United States presidents (hey, why not?). The user will be able to order any quantity of the available portraits. Shipping and handling, as well as sales tax, are calculated by the VBScript code so that users always know exactly how much the purchase will cost them. The script code also verifies the entered phone number and ZIP code for proper formatting before submitting the form data.

Figure 25.2 shows the order entry form. The top of the form contains header information: customer name, address, and phone number. This is followed by the order form that gives the user the details about each portrait: description, cost, and shipping charge. The user enters the quantity of each portrait to be ordered, and the script code updates the various subtotals and the grand total. The shipping cost, product total cost, and grand total are displayed in a separate frame that always appears at the bottom of the browser, regardless of where the user has scrolled to on the order form.

Figure 25.2 : The order entry form displayed with Internet Explorer.

Listing 25.1 shows the HTML used to create the frames. You can type it in or copy it from the CD-ROM. Save it to a Web server directory if possible. The name is irrelevant, but you'll need to remember what it is because this is the file that you'll open with Internet Explorer when it's time to test the application.

> Listing 25.1. The frame container for the order entry page.

>     <HTML>

>     <HEAD>

>     <TITLE>Portrait Order Form</TITLE>

>     </HEAD>

>     <BODY>

>     <FRAMESET FRAMEBORDER=NO ROWS="90,10">

>     <FRAME SCROLLING=YES SRC=25-3.htm>

>     <FRAME SCROLLING=NO MARGINHEIGHT=5 MARGINWIDTH=5 SRC=25-2.htm>

>     </FRAMESET>

>     </BODY>

>     </HTML>

This Web page makes pretty basic use of frames. The `<FRAMESET>` tag specifies the start of a frame definition. The `FRAMEBORDER=NO` specifies that there should be no borders around the frames. `ROWS="90,10"` specifies that the frames will be stacked vertically. The top frame will take up 90 percent of the browser's viewing area, and the bottom frame uses 10 percent.

The `<FRAME SCROLLING=YES SRC=25-3.htm>` tag for the first frame in the frameset specifies that the frame is to be scrollable and that a file named `25-3.htm` should be used as the content for the frame.

The `<FRAME SCROLLING=NO MARGINHEIGHT=5 MARGINWIDTH=5 SRC=25-2.htm>` tag for the second frame in the frameset specifies that the frame is not scrollable and that a file named `25-2.htm` should be used as the content for the frame. This is the bottom frame shown in Figure 25.2.

Next, Listing 25.2 shows the HTML code for the bottom frame (`25-2.htm`). You can type the code, use the ActiveX Control Pad to assist in inserting the Label controls, or copy the code from the accompanying CD-ROM. Save the file as `25-1.htm` in the same directory as the code from Listing 25.1.

> Listing 25.2. The bottom frame of the order entry page.

>     <HTML><HEAD><TITLE>New Page</TITLE></HEAD>

>     <BODY><CENTER>

>         <OBJECT ID="IeLabel1" WIDTH=127 HEIGHT=27

>      CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>         <PARAM NAME="_ExtentX" VALUE="3334">

>         <PARAM NAME="_ExtentY" VALUE="714">

>         <PARAM NAME="Caption" VALUE="Shipping Total:">

>         <PARAM NAME="Angle" VALUE="0">

>         <PARAM NAME="Alignment" VALUE="0">

>         <PARAM NAME="Mode" VALUE="1">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="ForeColor" VALUE="#000000">

>         <PARAM NAME="BackColor" VALUE="#C0C0C0">

>         <PARAM NAME="FontName" VALUE="Arial">

>         <PARAM NAME="FontSize" VALUE="12">

>         <PARAM NAME="FontItalic" VALUE="0">

>         <PARAM NAME="FontBold" VALUE="1">

>         <PARAM NAME="FontUnderline" VALUE="0">

>         <PARAM NAME="FontStrikeout" VALUE="0">

>         <PARAM NAME="TopPoints" VALUE="0">

>         <PARAM NAME="BotPoints" VALUE="0">

>     </OBJECT>   <OBJECT ID="lblShipTot" WIDTH=80 HEIGHT=27

>      CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>         <PARAM NAME="_ExtentX" VALUE="1879">

>         <PARAM NAME="_ExtentY" VALUE="714">

>         <PARAM NAME="Caption" VALUE="$0.00">

>         <PARAM NAME="Angle" VALUE="0">

>         <PARAM NAME="Alignment" VALUE="0">

>         <PARAM NAME="Mode" VALUE="1">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="ForeColor" VALUE="#000000">

>         <PARAM NAME="BackColor" VALUE="#C0C0C0">

>         <PARAM NAME="FontName" VALUE="Arial">

>         <PARAM NAME="FontSize" VALUE="12">

>         <PARAM NAME="FontItalic" VALUE="0">

>         <PARAM NAME="FontBold" VALUE="0">

>         <PARAM NAME="FontUnderline" VALUE="0">

>         <PARAM NAME="FontStrikeout" VALUE="0">

>         <PARAM NAME="TopPoints" VALUE="0">

>         <PARAM NAME="BotPoints" VALUE="0">

>     </OBJECT>     <OBJECT ID="IeLabel2" WIDTH=93 HEIGHT=27

>      CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>         <PARAM NAME="_ExtentX" VALUE="2461">

>         <PARAM NAME="_ExtentY" VALUE="714">

>         <PARAM NAME="Caption" VALUE="Total Cost:">

>         <PARAM NAME="Angle" VALUE="0">

>         <PARAM NAME="Alignment" VALUE="0">

>         <PARAM NAME="Mode" VALUE="1">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="ForeColor" VALUE="#000000">

>         <PARAM NAME="BackColor" VALUE="#C0C0C0">

>         <PARAM NAME="FontName" VALUE="Arial">

>         <PARAM NAME="FontSize" VALUE="12">

>         <PARAM NAME="FontItalic" VALUE="0">

>         <PARAM NAME="FontBold" VALUE="1">

>         <PARAM NAME="FontUnderline" VALUE="0">

>         <PARAM NAME="FontStrikeout" VALUE="0">

>         <PARAM NAME="TopPoints" VALUE="0">

>         <PARAM NAME="BotPoints" VALUE="0">

>     </OBJECT>   <OBJECT ID="lblCostTot" WIDTH=90 HEIGHT=27

>          CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>             <PARAM NAME="_ExtentX" VALUE="3360">

>             <PARAM NAME="_ExtentY" VALUE="423">

>             <PARAM NAME="Caption" VALUE="$0.00">

>             <PARAM NAME="Angle" VALUE="0">

>             <PARAM NAME="Alignment" VALUE="0">

>             <PARAM NAME="Mode" VALUE="1">

>             <PARAM NAME="FillStyle" VALUE="0">

>             <PARAM NAME="FillStyle" VALUE="0">

>             <PARAM NAME="ForeColor" VALUE="#000000">

>             <PARAM NAME="BackColor" VALUE="#C0C0C0">

>             <PARAM NAME="FontName" VALUE="Arial">

>             <PARAM NAME="FontSize" VALUE="12">

>             <PARAM NAME="FontItalic" VALUE="0">

>             <PARAM NAME="FontBold" VALUE="0">

>             <PARAM NAME="FontUnderline" VALUE="0">

>             <PARAM NAME="FontStrikeout" VALUE="0">

>             <PARAM NAME="TopPoints" VALUE="0">

>             <PARAM NAME="BotPoints" VALUE="0">

>        </OBJECT> <OBJECT ID="IeLabel3" WIDTH=104 HEIGHT=27

>      CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>         <PARAM NAME="_ExtentX" VALUE="2752">

>         <PARAM NAME="_ExtentY" VALUE="714">

>         <PARAM NAME="Caption" VALUE="Grand Total:">

>         <PARAM NAME="Angle" VALUE="0">

>         <PARAM NAME="Alignment" VALUE="0">

>         <PARAM NAME="Mode" VALUE="1">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="FillStyle" VALUE="0">

>         <PARAM NAME="ForeColor" VALUE="#000000">

>         <PARAM NAME="BackColor" VALUE="#C0C0C0">

>         <PARAM NAME="FontName" VALUE="Arial">

>         <PARAM NAME="FontSize" VALUE="12">

>         <PARAM NAME="FontItalic" VALUE="0">

>         <PARAM NAME="FontBold" VALUE="1">

>         <PARAM NAME="FontUnderline" VALUE="0">

>         <PARAM NAME="FontStrikeout" VALUE="0">

>         <PARAM NAME="TopPoints" VALUE="0">

>         <PARAM NAME="BotPoints" VALUE="0">

>     </OBJECT>   <OBJECT ID="lblGrandTot" WIDTH=90 HEIGHT=27

>          CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>             <PARAM NAME="_ExtentX" VALUE="3360">

>             <PARAM NAME="_ExtentY" VALUE="423">

>             <PARAM NAME="Caption" VALUE="$0.00">

>             <PARAM NAME="Angle" VALUE="0">

>             <PARAM NAME="Alignment" VALUE="0">

>             <PARAM NAME="Mode" VALUE="1">

>             <PARAM NAME="FillStyle" VALUE="0">

>             <PARAM NAME="FillStyle" VALUE="0">

>             <PARAM NAME="ForeColor" VALUE="#000000">

>             <PARAM NAME="BackColor" VALUE="#C0C0C0">

>             <PARAM NAME="FontName" VALUE="Arial">

>             <PARAM NAME="FontSize" VALUE="12">

>             <PARAM NAME="FontItalic" VALUE="0">

>             <PARAM NAME="FontBold" VALUE="0">

>             <PARAM NAME="FontUnderline" VALUE="0">

>             <PARAM NAME="FontStrikeout" VALUE="0">

>             <PARAM NAME="TopPoints" VALUE="0">

>             <PARAM NAME="BotPoints" VALUE="0">

>         </OBJECT></CENTER></BODY></HTML>

This HTML file is simply a set of six ActiveX Label controls. You can readily obtain these controls from the Microsoft ActiveX Control Gallery at `http://www.microsoft.com` if they don't already exist on your machine. Note that if you cannot guarantee that users have these controls installed on their machines, you should specify the `CODEBASE` property. The value of the property provides the location of where the control can be downloaded and installed.

Note that the `ID` properties specified as `lblShipTot`, `lblCostTot`, and `lblGrandTot` should not be modified without a corresponding change in `25-3.htm` that sets the `Caption` properties for these labels. Also, you should not modify the `Width` or `Height` properties. Giving the labels different `Height` properties from one another makes them appear in different places on the page as opposed to in a line, as shown in Figure 25.2.

Because the HTML for the main order form is mostly VBScript code, `25-3.htm` is discussed in the next section.

## Creating the Order Entry Form

This section discusses the creation of the main order form. Most of the HTML file is comprised of the script code. Most of the document is contained within the HTML `<FORM>` container. The `ACTION` element specified for the form should be the URL to the back-end program that is servicing the order entry process. In my example, I've used a simple ISAPI application that simply returns the data found on the HTML form.

The document is formatted with two tables. The top of the document has a table with one row (`<TR> ... </TR>`) and two columns (`<TD> ... </TD>`). The left-hand column contains the customer information input boxes. The right-hand column only contains the Submit button. Note that this is not an HTML form input of type `Submit`. This is actually an ActiveX command button control. This is necessary because, after this button is clicked, the VBScript code does some data-validation work before submitting the form's data to the back-end program. If the validation checks fail, the form's `Submit` method is not invoked and the user is given the opportunity to correct any errors.

The top and bottom portions of the form are separated with a horizontal rule (`<HR>`), which is simply a line that runs horizontally across the browser window. The bottom part of the document contains another table. Each row in this table has text describing the portraits and their costs. There is also a Microsoft Forms 2.0 ActiveX text box control, a hidden HTML input box, and an ActiveX Label control for each item in the table.

The ActiveX text box enables the user to enter an integer quantity specifying how many of each portrait to purchase. VBScript code verifies that the value entered is indeed an integer. After a quantity is entered, the total for the line is calculated. This total is displayed in the ActiveX label. Then the overall totals displayed in the bottom frame are updated. You'll see this when you delve into the VBScript code in the next section.

## Examining the VBScript Code

This section describes the actual script code for the order entry application. Listing 25.3 shows the HTML for `25-3.htm`. This section discusses the VBScript code but not the HTML contained in Listing 25.3. Most of the HTML is fairly standard.

> Listing 25.3. The main frame for the order entry page.

>     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">

>     <HTML><HEAD>

>         <SCRIPT LANGUAGE="VBScript">

>     <!--

>     Sub window_onLoad()

>     Dim lstrTemp

>     lstrTemp = ReadVariable("FirstName")

>     if lstrTemp <> NOT_FOUND then Document.ORDER.FirstName.Value = lstrTemp

>     lstrTemp = ReadVariable("LastName")

>     if lstrTemp <> NOT_FOUND then Document.ORDER.LastName.Value = lstrTemp

>     lstrTemp = ReadVariable("Address")

>     if lstrTemp <> NOT_FOUND then Document.ORDER.Address.Value = lstrTemp

>     lstrTemp = ReadVariable("City")

>     if lstrTemp <> NOT_FOUND then Document.ORDER.City.Value = lstrTemp

>     lstrTemp = ReadVariable("State")

>     if lstrTemp <> NOT_FOUND then Document.ORDER.State.Value = lstrTemp

>     lstrTemp = ReadVariable("ZIP")

>     if lstrTemp <> NOT_FOUND then Document.ORDER.ZIP.Value = lstrTemp

>     lstrTemp = ReadVariable("Phone")

>     if lstrTemp <> NOT_FOUND then Document.ORDER.Phone.Value = lstrTemp

>     Document.ORDER.FirstName.focus()

>     end sub

>     Function ReadVariable(strVariableName)

>     'these five variables are used in the string manipulation

>     'code that finds the variable in the cookie.

>     Dim intLocation

>     Dim intNameLength

>     Dim intValueLength

>     Dim intNextSemicolon

>     Dim strTemp

>     'calculate length and location of variable name

>     intNameLength = Len(strVariableName)

>     intLocation = Instr(Document.Cookie, strVariableName)

>     'check for existence of variable name

>     If intLocation = 0 Then

>         'variable not found, so it can't be read

>         ReadVariable = NOT_FOUND

>     Else

>         'get a smaller substring to work with

>         strTemp = Right(Document.Cookie, Len(Document.Cookie) - intLocation + 1)

>         'check to make sure we found the full string, not just a substring

>         If Mid(strTemp, intNameLength + 1, 1) <> "=" Then

>             'oops, only found substring, not good enough

>             ReadVariable = NOT_FOUND

>             'note that this will incorrectly give a not found result if and only if

>             'a search for a variable whose name is a substring of a preceding

>             'variable is undertaken.  For example, this will fail:

>             '

>             'search for: MyVar

>             'cookie contains: MyVariable=2;MyVar=1

>         Else

>             'found full string

>             intNextSemicolon = Instr(strTemp, ";")

>             'if not found, then we need the last element of the cookie

>             If intNextSemicolon = 0 Then intNextSemicolon = Len(strTemp) + 1

>             'check for empty variable (Var1=;)

>             If intNextSemicolon = (intNameLength + 2) Then

>                 'variable is empty

>                 ReadVariable = ""

>             Else

>                 'calculate value normally

>                 intValueLength = intNextSemicolon - intNameLength - 2

>                 ReadVariable = Mid(strTemp, intNameLength + 2, intValueLength)

>             End If

>         End If

>     End If

>     end function

>     dim  NOT_FOUND

>     NOT_FOUND = "NOT_FOUND"

>     -->

>         </SCRIPT>

>     <TITLE>Main Frame in Order Entry</TITLE ></HEAD>

>     <BODY>

>     <H3>Order Entry (all fields are required)</H3><p>

>      <div align=center><center><table width=80% align=center><tr><td width=75%>

>         <FORM ACTION="http://pipestream.ipctech.com/cgi-win/spitback.dll"

>          METHOD="POST" NAME="ORDER">

>     <pre><p>First Name: <input type=text size=20 maxlength=256 name="FirstName">

>      Last Name: <INPUT TYPE=text SIZE=20 NAME="LastName" maxlength=256>

>     <br>   Address: <INPUT TYPE=text SIZE=40 NAME="Address" maxlength=256>

>           City: <INPUT TYPE=text SIZE=40 NAME="City" maxlength=256>

>          State: <INPUT TYPE=text SIZE=15 NAME="State" maxlength=256> ZIP: <INPUT

>     TYPE=text SIZE=10 NAME="ZIP" maxlength=10>

>          Phone: <INPUT TYPE=text SIZE=20 NAME="Phone" maxlength=256></pre></td>

>     <td width=25%><CENTER><OBJECT ID="cmdSubmit" WIDTH=96 HEIGHT=32

>          CLASSID="CLSID:D7053240-CE69-11CD-A777-00DD01143C57">

>             <PARAM NAME="Caption" VALUE="Submit">

>             <PARAM NAME="Size" VALUE="2540;846">

>             <PARAM NAME="FontCharSet" VALUE="0">

>             <PARAM NAME="FontPitchAndFamily" VALUE="2">

>             <PARAM NAME="ParagraphAlign" VALUE="3">

>             <PARAM NAME="FontWeight" VALUE="0">

>         </OBJECT></CENTER></td>

>     </tr></table></center></div>

>      <hr>

>     <div align=center><center>

>     <table width=60% BORDER=1>

>     <tr><td width=25%>Description</td><td width=25%>Cost/Shipping</td>

>     <td width=25%>Qty</td><td width=25%>Total</td></tr>

>     <tr><td width=25%>Lincoln</td><td width=25%>$24.95/$4.95</td><td width=25%>

>     <!-- MORE SCRIPT CODE -->

>     <SCRIPT LANGUAGE="VBScript">

>     <!--

>     Function GetPrice(pzQtyText, pzQtyHidden, pdPrice)

>     Dim lExtPrice

>     GetPrice = -1

>     If instr(pzQtyText.Text, ".") then

>         pzQtyText.Text = pzQtyHidden.value

>         MsgBox "Please enter a vaid integer quantity!"

>         Exit Function

>     end if

>     if not(isNumeric(pzQtyText.Text)) then

>         pzQtyText.Text = pzQtyHidden.value

>         MsgBox "Please enter a vaid integer quantity!"

>         exit function

>     end if

>     lExtPrice = pdPrice * pzQtyText.Text

>     pzQtyHidden.value = pzQtyText.Text

>     GetPrice = FormatCurrency(lExtPrice)

>     end function

>     Function FormatCurrency(ptInputValue)

>     Dim ltValue

>     ltValue = ptInputValue

>     if instr(ltValue,".") = 0 then

>         ltValue = ltValue & ".00"

>     elseif instr(ltValue,".") = Len(ltValue) - 1 then

>         ltValue = ltValue & "0"

>     end if

>     ltValue = "$" & ltValue

>     FormatCurrency = ltValue

>     end function

>     Sub UpdateTotals()

>     dim lTmp

>     lTmp = CInt(document.order.LincolnQty.Value )

>     lTmp = lTmp + CInt(document.order.RooseveltQty.Value)

>     lTmp = lTmp + CInt(document.order.ReaganQty.Value)

>     lTmp = lTmp * 4.95

>     window.parent.frames(1).lblShipTot.Caption = cstr(FormatCurrency(lTmp))

>     Dim lTmp2

>     lTmp2 = CDbl(document.order.lblLincolnExt.Caption)

>     lTmp2 = lTmp2 + CDbl(document.order.lblRooseveltExt.Caption)

>     lTmp2 = lTmp2 + CDbl(document.order.lblReaganExt.Caption)

>     window.parent.frames(1).lblCostTot.Caption = cstr(FormatCurrency(lTmp2))

>     window.parent.frames(1).lblGrandTot.Caption = cstr(FormatCurrency(lTmp + ltmp2))

>     end sub

>     Sub txtLincolnQty_Change()

>     Dim lExtPrice

>     lExtPrice = GetPrice(document.order.txtLincolnQty, document.order.LincolnQty, 24.95)

>     if lExtPrice = -1 then exit sub

>     Document.ORDER.lblLincolnExt.caption = cstr(lExtPrice)

>     Call UpdateTotals()

>     end sub

>     Sub txtRooseveltQty_Change()

>     Dim lExtPrice

>     lExtPrice = GetPrice(document.order.txtRooseveltQty, document.order.RooseveltQty, 22.95)

>     if lExtPrice = -1 then exit sub

>     Document.ORDER.lblRooseveltExt.caption = cstr(lExtPrice)

>     Call UpdateTotals()

>     end sub

>     Sub txtReaganQty_Change()

>     Dim lExtPrice

>     lExtPrice = GetPrice(document.order.txtReaganQty, document.order.ReaganQty, 14.95)

>     if lExtPrice = -1 then exit sub

>     Document.ORDER.lblReaganExt.caption = cstr(lExtPrice)

>     Call UpdateTotals()

>     end sub

>     -->

>             </SCRIPT>

>             <OBJECT ID="txtLincolnQty" WIDTH=71 HEIGHT=24

>              CLASSID="CLSID:8BD21D10-EC42-11CE-9E0D-00AA006002f3">

>                 <PARAM NAME="VariousPropertyBits" VALUE="746604571">

>                 <PARAM NAME="Size" VALUE="1873;635">

>                 <PARAM NAME="FontCharSet" VALUE="0">

>                 <PARAM NAME="FontPitchAndFamily" VALUE="2">

>                 <PARAM NAME="FontWeight" VALUE="0">

>             </OBJECT>

>             <INPUT TYPE=hidden VALUE="0" SIZE=5 NAME="LincolnQty" maxlength=256>

>     </td><td width=25%>

>             <OBJECT ID="lblLincolnExt" WIDTH=83 HEIGHT=16

>              CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>                 <PARAM NAME="_ExtentX" VALUE="2196">

>                 <PARAM NAME="_ExtentY" VALUE="423">

>                 <PARAM NAME="Caption" VALUE="$0.00">

>                 <PARAM NAME="Angle" VALUE="0">

>                 <PARAM NAME="Alignment" VALUE="0">

>                 <PARAM NAME="Mode" VALUE="1">

>                 <PARAM NAME="FillStyle" VALUE="0">

>                 <PARAM NAME="FillStyle" VALUE="0">

>                 <PARAM NAME="ForeColor" VALUE="#000000">

>                 <PARAM NAME="BackColor" VALUE="#C0C0C0">

>                 <PARAM NAME="FontName" VALUE="Arial">

>                 <PARAM NAME="FontSize" VALUE="12">

>                 <PARAM NAME="FontItalic" VALUE="0">

>                 <PARAM NAME="FontBold" VALUE="0">

>                 <PARAM NAME="FontUnderline" VALUE="0">

>                 <PARAM NAME="FontStrikeout" VALUE="0">

>                 <PARAM NAME="TopPoints" VALUE="0">

>                 <PARAM NAME="BotPoints" VALUE="0">

>             </OBJECT>

>     </td></tr>

>     <tr><td width=25%>Roosevelt</td><td width=25%>$22.95/$4.95</td><td width=25%>

>             <OBJECT ID="txtRooseveltQty" WIDTH=71 HEIGHT=24

>              CLASSID="CLSID:8BD21D10-EC42-11CE-9E0D-00AA006002f3">

>                 <PARAM NAME="VariousPropertyBits" VALUE="746604571">

>                 <PARAM NAME="Size" VALUE="1873;635">

>                 <PARAM NAME="FontCharSet" VALUE="0">

>                 <PARAM NAME="FontPitchAndFamily" VALUE="2">

>                 <PARAM NAME="FontWeight" VALUE="0">

>             </OBJECT>

>             <INPUT TYPE=hidden VALUE="0" SIZE=5 NAME="RooseveltQty" maxlength=256>

>     </td><td width=25%>

>             <OBJECT ID="lblRooseveltExt" WIDTH=83 HEIGHT=16

>              CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>                 <PARAM NAME="_ExtentX" VALUE="2196">

>                 <PARAM NAME="_ExtentY" VALUE="423">

>                 <PARAM NAME="Caption" VALUE="$0.00">

>                 <PARAM NAME="Angle" VALUE="0">

>                 <PARAM NAME="Alignment" VALUE="0">

>                 <PARAM NAME="Mode" VALUE="1">

>                 <PARAM NAME="FillStyle" VALUE="0">

>                 <PARAM NAME="FillStyle" VALUE="0">

>                 <PARAM NAME="ForeColor" VALUE="#000000">

>                 <PARAM NAME="BackColor" VALUE="#C0C0C0">

>                 <PARAM NAME="FontName" VALUE="Arial">

>                 <PARAM NAME="FontSize" VALUE="12">

>                 <PARAM NAME="FontItalic" VALUE="0">

>                 <PARAM NAME="FontBold" VALUE="0">

>                 <PARAM NAME="FontUnderline" VALUE="0">

>                 <PARAM NAME="FontStrikeout" VALUE="0">

>                 <PARAM NAME="TopPoints" VALUE="0">

>                 <PARAM NAME="BotPoints" VALUE="0">

>             </OBJECT>

>     </td></tr>

>     <tr><td width=25%>Reagan</td><td width=25%>$14.95/$4.95</td><td width=25%>

>             <OBJECT ID="txtReaganQty" WIDTH=71 HEIGHT=24

>              CLASSID="CLSID:8BD21D10-EC42-11CE-9E0D-00AA006002f3">

>                 <PARAM NAME="VariousPropertyBits" VALUE="746604571">

>                 <PARAM NAME="Size" VALUE="1873;635">

>                 <PARAM NAME="FontCharSet" VALUE="0">

>                 <PARAM NAME="FontPitchAndFamily" VALUE="2">

>                 <PARAM NAME="FontWeight" VALUE="0">

>             </OBJECT>

>             <INPUT TYPE=hidden VALUE="0" SIZE=5 NAME="ReaganQty" maxlength=256>

>     </td><td width=25%>

>             <OBJECT ID="lblReaganExt" WIDTH=83 HEIGHT=16

>              CLASSID="CLSID:99B42120-6EC7-11CF-A6C7-00AA00A47DD2">

>                 <PARAM NAME="_ExtentX" VALUE="2196">

>                 <PARAM NAME="_ExtentY" VALUE="423">

>                 <PARAM NAME="Caption" VALUE="$0.00">

>                 <PARAM NAME="Angle" VALUE="0">

>                 <PARAM NAME="Alignment" VALUE="0">

>                 <PARAM NAME="Mode" VALUE="1">

>                 <PARAM NAME="FillStyle" VALUE="0">

>                 <PARAM NAME="FillStyle" VALUE="0">

>                 <PARAM NAME="ForeColor" VALUE="#000000">

>                 <PARAM NAME="BackColor" VALUE="#C0C0C0">

>                 <PARAM NAME="FontName" VALUE="Arial">

>                 <PARAM NAME="FontSize" VALUE="12">

>                 <PARAM NAME="FontItalic" VALUE="0">

>                 <PARAM NAME="FontBold" VALUE="0">

>                 <PARAM NAME="FontUnderline" VALUE="0">

>                 <PARAM NAME="FontStrikeout" VALUE="0">

>                 <PARAM NAME="TopPoints" VALUE="0">

>                 <PARAM NAME="BotPoints" VALUE="0">

>             </OBJECT>

>     </td></tr>

>     </table>

>     </center></div>

>         </FORM>

>     <!-- FINAL SCRIPT SECTION -->

>     <SCRIPT LANGUAGE="VBScript">

>     <!--

>     Sub cmdSubmit_Click()

>     dim lTmp

>     if ValidateLen(Document.Order.FirstName, "First Name") = 0 then exit sub

>     if ValidateLen(Document.Order.LastName, "Last Name") = 0 then exit sub

>     if ValidateLen(Document.Order.Address, "Address") = 0 then exit sub

>     if ValidateLen(Document.Order.City, "City") = 0 then exit sub

>     if ValidateLen(Document.Order.State, "State") = 0 then exit sub

>     if ValidateLen(Document.Order.ZIP, "ZIP Code") = 0 then exit sub

>     lTmp = (Document.ORDER.ZIP.value)

>     select case Len(lTmp)

>     case 5

>          if not isnumeric(lTmp)  then

>              Call ErrorOnZIP()

>              exit sub

>          end if

>     case 10

>          if mid(lTmp,6,1) <> "-" then

>              call ErrorOnZIP()

>              exit sub

>          end if

>          if not IsNumeric(left(lTmp,5)) then

>              Call ErrorOnZIP()

>              exit sub

>          end if

>          if not isnumeric(right(lTmp,4)) then

>              Call ErrorOnZIP()

>              exit sub

>          end if

>     case else

>          Call ErrorOnZIP()

>          exit sub

>     end select

>     Document.Cookie = "FirstName=" & document.order.FirstName.Value

>     Document.Cookie = "LastName=" & Document.Order.LastName.Value

>     Document.Cookie = "Address=" & Document.Order.Address.Value

>     Document.Cookie = "City=" & Document.Order.City.Value

>     Document.Cookie = "State=" & Document.Order.State.Value

>     Document.Cookie = "ZIP=" & Document.Order.ZIP.Value

>     Document.Cookie = "Phone=" & Document.Order.Phone.Value

>     Document.Cookie = "LastOrderDate=" & CStr(Now)

>     call Document.ORDER.submit()

>     end sub

>     Function ValidateLen(pzField, ptMessage)

>     if Len(pzField.value) = 0 then

>          MsgBox ptMessage & " is required!"

>          call pzField.Focus()

>          ValidateLen = 0

>          exit function

>     end if

>     ValidateLen = 1

>     end function

>     Sub ErrorOnZIP()

>         MsgBox "ZIP Code invalid!"

>         call Document.ORDER.ZIP.Select

>         call Document.ORDER.ZIP.focus()

>     end sub

>     -->

>         </SCRIPT>

>     </BODY></html>

The script code begins with the `window_onLoad` event. The first step of the script is to load any cookie data that exists for the order entry page. The cookie data is saved when the user clicks the Submit button. The `onLoad` event calls the `ReadVariable()` function discussed in Chapter 14. This function reads a cookie variable from the `cookie` property and returns the cookie's value. The cookie data then is placed into the appropriate text boxes on the form.

After the cookie data is loaded, the focus is set to the first name text box by invoking the `focus()` method. This is necessary because you cannot guarantee that the first name box will receive focus when the page loads. Usually, one of the ActiveX text boxes receives focus before the HTML form does.

Scrolling further down the listing, find the comment `<!-- MORE SCRIPT CODE -->`. This section of code is where calculations are made based on the quantities entered by the user. The first function, `GetPrice()`, ensures that the user entered an integer and then calculates the total price for the line on which the quantity was entered. Note the use of the `IsNumeric()` function. Because the Visual Basic `val()` function does not appear to work within VBScript, you should use `IsNumeric()` instead of `if val(variable_name) = 0` to determine whether `variable_name` stores a numeric value.

Next comes the `FormatCurrency()` function. Because VBScript lacks the Visual Basic `format$()` function, you must manually format strings. The `FormatCurrency()` function takes a string and formats it as `$#.00` would in the `format$()` function.

Next comes the `UpdateTotals` procedure. This procedure updates the ActiveX labels found in the bottom frame. The first section of code in Listing 25.3 updates the label that displays the total shipping cost. The second section updates the total cost of the portraits, not including shipping. The final line of code updates the label displaying the grand total.

Finally, the `change` event code is used for the three ActiveX text boxes. All three event procedures perform the same tasks. First, the `GetPrice()` function is called to obtain the total product cost for the current portrait. If the quantity entered was valid, the ActiveX label displaying the extended cost for the portrait (quantity multiplied by price) is updated. Finally, the `UpdateTotals` procedure is called to update the bottom frame.

The final section of code appears after the `<!-- FINAL SCRIPT SECTION -->` comment. This code is responsible for validating the data entered into the form. The validation rules follow:

- All user information fields must have values.
- The ZIP code entered must be in `#####` format or `#####-####` format.

WARNING
Early versions of Internet Explorer 3.0 appear to submit an HTML form whenever the user presses the Enter key, bypassing the validation code placed in the command button's `Click` event. If you come up with a clever way to avoid this, e-mail me at `craige@pipestream. ipctech.com`.

The Submit button is not an HTML form's Submit button but rather an ActiveX command button control. Clicking this button fires the `cmdSubmit_click` event. This event first uses a function named `ValidateLen()` to check the existence of data in the specified text box. If the text box is empty, a message box is displayed and the function returns a 0. The HTML form data is not submitted in this case. After all the user information boxes are validated as having data, the ZIP code field is checked to make sure that the data is in the proper format.

After all the validation checks have passed, the script updates the cookie data. The current values entered in the text boxes are stored into the cookie. The current date/time also is stored in a cookie to store the date/time of the user's last order submission.

Finally, the form's `submit()` method is invoked to send the form's data to the back-end process that is servicing the order entry application.

## Testing the Application

After you save or copy the code for the three listings from the CD-ROM, you can test the script. If you want to use the cookie feature, you must save the files to a Web server's content directory because cookies depend on a Web server for their operation.

Load the file `25-1.htm`. It should appear as in Figure 25.2. Enter information into all the user information boxes at the top of the page. Try entering some invalid ZIP codes and clicking the Submit button. If you don't receive a message box informing you that the ZIP code is invalid, check the code in the `cmdSubmit_click` event. Also, if you can leave a user information field blank without receiving a message box, check to make sure that the field is included in the calls to `ValidateLen()`.

Next, try entering some quantities into the table at the bottom of the form. You should see the appropriate label captions change. Try entering a number other than an integer. A message box should appear asking you to enter an integer. If not, check the code in the `GetPrice()` function.

After testing the other portions and successfully submitting the form, reload the page. The user information text boxes should contain the data previously entered. If not, first check the `cmdSubmit_click` event to make sure that the `cookie` property is being set for any missing information. If everything looks fine there, check the `window_onLoad` event to make sure that the data is being read for the missing field. If all fields are missing, check the code in `ReadVariable()` and make sure that you're using the Web server to provide the page, instead of using Internet Explorer's File | Open menu to load the operating system.

## Review

The example in this chapter provides the basis for a fully operational order entry Web application. The only piece you must add is the back-end application that processes the submitted data. This is another subject for another book. Web Programming with Visual Basic, published by Sams.net, is an excellent source for learning how to program back-end Web server applications using Visual Basic.

| Use of this site is subject certain Terms & Conditions. Copyright (c) 1996-1999 EarthWeb, Inc.. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Please read our privacy policy for details.