Profit and Value from Information Technology
Ecommerce & Extranets : Client Systems : Enterprise Applications : Application Development

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 24

# WWW Personal Information Manager

by Owen Graupman

CONTENTS

- Overview
- How It Works
- Creating the Page
  - Working with Cookies
  - Creating Dynamic HTML
  - Presenting Information
  - Tying It All Together
- Review

## Overview

Personal information managers have always been one of the most popular applications for a computer. This chapter will show you how to make a World Wide Web-based personal information manager that allows the user to store to-do's, appointments, and e-mail addresses with a few simple clicks of the mouse.

Two very important techniques are used to create this interactive page:

- Dynamic page creation
- Persistent storage through cookies

Dynamic page creation is one of the hottest topics in page creation. A dynamic page changes in response to the environment, user input, or a variety of other information. The WWW PIM uses VBScript to generate the entire page based on the current date and information stored by the user.

Persistent storage through cookies allows visitors to this page to store their appointments in small text files called cookies, which reside on their local computer and can be recalled at any time. Many sites today use cookies to store information about the user. Some of the most common uses are to store color preferences or information provided by the user like their name and address. Because a cookie is just a text file managed by the browser, client-side security is very good. Even if a miscreant person was able to place a virus in a cookie, the file contains headers and footers that would prevent the code from running and infecting your system.

Before you go running off to explore cookies, keep in mind that cookies will only work when the page is loaded from an HTTPD server. Loading this page locally will produce a blank page that will not store any data.

## How It Works

When a user loads this page from the Internet, VBScript goes to work parsing through the cookie to pull out information for each of the categories of data. It then formats this information into HTML and writes it directly into the document context as HTML.

When a user clicks on any item, whether it's a to-do, address, or appointment, message boxes prompt the user through creating a new item. The information is then placed into the cookie and the page reloaded.

You can see how the finished example looks in Figure 24.1, and the entire HTML and VBScript code in Listing 24.1.

Figure 24.1 : The finished WWW Personal Information Manager.

> Listing 24.1. The WWW Personal Information Manager code listing.

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

>     2:

>     3: <HTML>

>     4:

>     5: <HEAD>

>     6: <TITLE>WWW Personal Information Manager</title>

>     7: </HEAD>

>     8:

>     9: <BODY BGCOLOR="#FFFFFF" LANGUAGE="VBSCRIPT">

>     10: <H1 ALIGN=CENTER>WWW Personal Information Manager</H1>

>     11: <P ALIGN=CENTER><FONT SIZE=2>Welcome to the WWW Personal Information Manager.

>         You can use this site to store to-do's, appointments,

>     12: and email addresses. This information is stored on your local computer via

>              cookies. To add, edit, or delete an item, click on the item

>     13: number in the list and follow the prompts.</FONT></P>

>     14: <P ALIGN=CENTER><FONT SIZE=2>NOTE: This page must be accessed from the Internet

>              or information will not get stored in the cookie. </FONT></P>

>     15: <CENTER>

>     16: <TABLE CELLPADDING=0 CELLSPACING=5 WIDTH=100%>

>     17: <SCRIPT LANGUAGE="VBSCRIPT"><!--

>     18: Call docCreate

>     19:

>     20: Sub setVariable(sVariableName, varVariableValue)

>     21: Document.Cookie = sVariableName & "=" & varVariableValue & ";expires=Monday,

>         28-Sep-98 12:00:00 GMT"

>     22: end sub

>     23:

>     24: Function readVariable(sVariableName)

>     25: Dim iLocation

>     26: Dim iNameLength

>     27: Dim iValueLength

>     28: Dim iNextSemicolon

>     29: Dim sTemp

>     30:

>     31: iNameLength = Len(sVariableName)

>     32: iLocation = InStr(Document.Cookie, sVariableName)

>     33: If iLocation = 0 Then

>     34:     readVariable = ""

>     35: Else

>     36:     sTemp = Right(Document.Cookie, Len(Document.Cookie) - iLocation + 1)

>     37:     If Mid(sTemp, iNameLength + 1, 1) <> "=" Then

>     38:         readVariable = ""

>     39:     Else

>     40:         iNextSemicolon = InStr(sTemp, ";")

>     41:         If iNextSemicolon = 0 Then iNextSemicolon = Len(sTemp) + 1

>     42:         If iNextSemicolon = (iNameLength + 2) Then

>     43:             readVariable = ""

>     44:         Else

>     45:             iValueLength = iNextSemicolon - iNameLength - 2

>     46:             readVariable = Mid(sTemp, iNameLength + 2, iValueLength)

>     47:         End If

>     48:     End If

>     49: End if

>     50: end function

>     51:

>     52: Sub killVariable(sVariableName)

>     53: setVariable sVariableName, "NULL;expires=Monday, 01-Jan-95 12:00:00 GMT"

>     54: end sub

>     55:

>     56: Sub addTodo(iRecord)

>     57: Dim sTodo

>     58: Dim iChoice

>     59:

>     60: iChoice = MsgBox("Do you want to add or delete this item? Click yes to add or

>         no to delete.", 3, "Add/Delete Item")

>     61: Select Case iChoice

>     62:     Case 6

>     63:         sTodo = InputBox("What do you want to do?", "Add To-Do")

>     64:         Call setVariable("%%TD" & Trim(iRecord), sTodo)

>     65:     Case 7

>     66:         killVariable "%%TD" & Trim(iRecord)

>     67:     Case 2

>     68:         Exit Sub

>     69: End Select

>     70: window.navigate "wwwpim.htm"

>     71: End Sub

>     72:

>     73: Sub addAppt(m,d,y)

>     74: Dim sAppt

>     75: Dim TempAppt

>     76:

>     77: TempAppt = readVariable("%%AP" & Trim(m) & "/" & Trim(d) & "/" & Trim(y))

>     78:

>     79: If Len(Trim(TempAppt)) > 0 Then

>     80:     sAppt = InputBox("Please enter or edit your appointment list for today",

>                      "Add/Edit Appointment", readVariable("%%AP" & Trim(m)

>     				 & "/" & Trim(d) & "/"

>             & Trim(y)))

>     81: Else

>     82:     sAppt = InputBox("Please enter or edit your appointment list for today",

>                      "Add/Edit Appointment")

>     83: End If

>     84: If Len(Trim(sAppt)) > 0 Then

>     85:     Call setVariable("%%AP" & Trim(m) & "/" & Trim(d) & "/" & Trim(y), sAppt)

>     86: Else

>     87:     killVariable("%%AP" & Trim(m) & "/" & Trim(d) & "/" & Trim(y))

>     88: End If

>     89: window.navigate "wwwpim.htm"

>     90: End Sub

>     91:

>     92: Sub addAddr(iRecord)

>     93: Dim Addr

>     94: Dim iChoice

>     95: iChoice = MsgBox("Do you want to add or delete this item? Click yes to add or

>              no to delete.", 3,"Add/Delete Item")

>     96:

>     97: Select Case iChoice

>     98:     Case 6

>     99:         Addr=InputBox("What address do you want to add?", "Add Email Address")

>     100:         Call setVariable("%%AD" & Trim(iRecord), Addr)

>     101:     Case 7

>     102:         killVariable "%%AD" & Trim(iRecord)

>     103:     Case 2

>     104:         Exit Sub

>     105: End Select

>     106: window.navigate "wwwpim.htm"

>     107: End Sub

>     108:

>     109: Sub ApptStat(m,d,y)

>     110: Dim sTemp

>     111:

>     112: sTemp    = CStr(d & " " & readVariable("%%AP" & m & "/" & d & "/" & y))

>     113: If Len(Trim(sTemp)) > 0 AND readVariable("%%AP" & m & "/" & d & "/" & y) <>

>                "NULL" Then

>     114:     window.status = sTemp

>     115: Else

>     116:     window.status = CStr(d)

>     117: End If

>     118: End Sub

>     119:

>     120: Function makTD_URL(iRecord)

>     121: If Trim(readVariable("%%TD" & Trim(iRecord))) <> "NULL" Then

>     122:     makTD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addTodo(" &

>                        Trim(iRecord) & ")>" & iRecord & ". " & readVariable("%%TD" &

>              Trim(iRecord)) & "</A>"

>     123: Else

>     124:     makTD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addTodo(" &

>                        Trim(iRecord) & ")>" & iRecord & ". </A>"

>     125: End If

>     126: End Function

>     127:

>     128: Function makAD_URL(iRecord)

>     129: If Trim(readVariable("%%AD" & Trim(iRecord))) <> "NULL" Then

>     130:     makAD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addAddr(" &

>                        Trim(iRecord) & ")>" & iRecord & ". " & "</a>" & "<A HREF=mailto:" &

>                        readVariable("%%AD" & Trim(iRecord)) & ">" & readVariable("%%AD" &

>              Trim(iRecord)) & "</A>"

>     131: Else

>     132:     makAD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addAddr(" &

>                        Trim(iRecord) & ")>" & iRecord & ". " & "</A>"

>     133: End If

>     134: End Function

>     135:

>     136: Function makAP_URL(m,d,y)

>     137: Dim stAppt

>     138:

>     139: stAppt = readVariable("%%AP" & m & "/" & d & "/" & y)

>     140: If Len(Trim(stAppt)) > 0 AND Trim(stAppt) <> "NULL" Then

>     141:     sTemp = "<A LANGUAGE=VBScript HREF=#null onClick="

>     142:     sTemp = sTemp & Chr(34)

>     143:     sTemp = sTemp & "Call addAppt(" & m & ", " & d & ", " & y & ")"

>     144:     sTemp = sTemp & Chr(34)

>     145:     sTemp = sTemp & " onMouseOver="

>     146:     sTemp = sTemp & Chr(34)

>     147:     sTemp = sTemp & "Call ApptStat(" & m & ", " & d & ", " & y & ")" & Chr(34)

>                         & ">"

>     148:     sTemp = sTemp & d & "!</a>"

>     149: Else

>     150:     sTemp = "<A LANGUAGE=VBScript HREF=#null onClick="

>     151:     sTemp = sTemp & Chr(34)

>     152:     sTemp = sTemp & "Call addAppt(" & m & ", " & d & ", " & y & ")"

>     153:     sTemp = sTemp & Chr(34)

>     154:     sTemp = sTemp & " onMouseOver="

>     155:     sTemp = sTemp & Chr(34)

>     156:     sTemp = sTemp & "Call ApptStat(" & m & ", " & d & ", " & y & ")" & Chr(34)

>                         & ">"

>     157:     sTemp = sTemp & d & "</A>"

>     158: End If

>     159: makAP_URL = sTemp

>     160: End Function

>     161:

>     162: Sub docCreate

>     163: Dim sDocument

>     164: sDocument = "<TD ALIGN=LEFT VALIGN=TOP WIDTH=35%><CENTER><B>To Do</B></

>          CENTER>"

>     165: sDocument = sDocument & Chr(13) & Chr(10) & "<HR>"

>     166: For i = 1 to 10

>     167:     sDocument = sDocument & "<BR>" & makTD_URL(i)

>     168: Next

>     169: sDocument = sDocument & "</TD><TD ALIGN=CENTER VALIGN=MIDDLE WIDTH=30%>"

>     170: sDocument = sDocument & makCalendar()

>     171: sDocument = sDocument & "</TD><TD ALIGN=LEFT VALIGN=TOP WIDTH=35%>"

>     172: sDocument = sDocument & "<CENTER><B>ADDRESSES</B></CENTER>"

>     173: sDocument = sDocument & Chr(13) & Chr(10) & "<HR>"

>     174: For j = 1 to 10

>     175:     sDocument = sDocument & "<BR>" & makAD_URL(j)

>     176: Next

>     177:

>     178: sDocument = sDocument & "</TD></TR>"

>     179: sDocument = sDocument & Chr(13) & Chr(10) & "</TABLE>"

>     180:

>     181: Document.Write sDocument

>     182:

>     183: End Sub

>     184:

>     185: Function makCalendar()

>     186: m=Month(Now())

>     187: y=Year(Now())

>     188:

>     189: FirstDay = WeekDay(Dateserial(y,m,1))

>     190: DaysInMonth= Day(Dateserial(y,m+1,1)-1)

>     191: ThisMonth=GMonth(Month(Dateserial(y,m,1)), true) & " " &

>                Year(Dateserial(y,m,1))

>     192:

>     193: sCalendar=""

>     194: sCalendar=sCalendar & "<CENTER><TABLE BORDER=1 CELLPADDING=2>"

>     195: sCalendar=sCalendar & "<TR><TH COLSPAN=7>" & ThisMonth & "</TH>"

>     196: sCalendar=sCalendar & "<TR><TH WIDTH=50 ALIGN=CENTER>Sun</TH><TH WIDTH=50

>                ALIGN=CENTER>Mon</TH><TH WIDTH=50 ALIGN=CENTER>Tue</TH><TH WIDTH=50

>                ALIGN=CENTER>Wed</TH><TH WIDTH=50 ALIGN=CENTER>Thu</TH><TH WIDTH=50

>                ALIGN=CENTER>Fri</TH><TH WIDTH=50 ALIGN=CENTER>Sat</TH></TR>"

>     197:

>     198: ictrDay=0

>     199: For Row=1 to 6

>     200:     sCalendar=sCalendar & "<TR>"

>     201:     For Col=1 to 7

>     202:         sCalendar=sCalendar & "<TD WIDTH=50 ALIGN=CENTER>"

>     203:         If Row=1 AND Col=FirstDay then

>     204:             ictrDay=1

>     205:         End If

>     206:         If ictrDay = 0 Then

>     207:             sCalendar=sCalendar &  "&nbsp;"

>     208:         End If

>     209:         If ictrDay <> 0 Then

>     210:             If ictrDay <= DaysInMonth Then

>     211:                 sCalendar=sCalendar & makAP_URL(m,ictrDay,y)

>     212:             End If

>     213:             If ictrDay > DaysInMonth Then

>     214:                 sCalendar=sCalendar &  "&nbsp;"

>     215:             End If

>     216:         ictrDay=ictrDay+1

>     217:         End if

>     218:         sCalendar=sCalendar &  "</TD>"

>     219:     Next

>     220:     sCalendar=sCalendar &  "</TR>"

>     221: Next

>     222: sCalendar=sCalendar &  "</TABLE>"

>     223: makCalendar = sCalendar

>     224: End Function

>     225:

>     226: Function GMonth(iMonth, fLongShort)

>     227: Select Case iMonth

>     228: Case 1

>     229:     If fLongShort = true then GMonth="January" else GMonth="Jan"

>     230: Case 2

>     231:     If fLongShort = true then GMonth="February" else GMonth="Feb"

>     232: Case 3

>     233:     If fLongShort = true then GMonth="March" else GMonth="Mar"

>     234: Case 4

>     235:     If fLongShort = true then GMonth="April" else GMonth="Apr"

>     236: Case 5

>     237:     If fLongShort = true then GMonth="May" else GMonth="May"

>     238: Case 6

>     239:     If fLongShort = true then GMonth="June" else GMonth="Jun"

>     240: Case 7

>     241:     If fLongShort = true then GMonth="July" else GMonth="Jul"

>     242: Case 8

>     243:     If fLongShort = true then GMonth="August" else GMonth="Aug"

>     244: Case 9

>     245:     If fLongShort = true then GMonth="September" else GMonth="Sep"

>     246: Case 10

>     247:     If fLongShort = true then GMonth="October" else GMonth="Oct"

>     248: Case 11

>     249:     If fLongShort = true then GMonth="November" else GMonth="Nov"

>     250: Case 12

>     251:     If fLongShort = true then GMonth="December"  else GMonth="Dec"

>     252: End Select

>     253: End Function

>     254:

>     255: --></SCRIPT>

>     256: </TABLE>

>     257: </CENTER>

>     258: </BODY>

>     259:

>     260: </HTML>

>     261:

## Creating the Page

Looking at the source reveals quite a bit of VBScript code and very little HTML. Almost the entire page is generated by VBScript as it is loaded. We accomplish this feat through several routines, which are broken up into the following areas:

- Working with cookies
- Creating dynamic HTML
- Presenting information
- Tying it all together

### Working with Cookies

Cookies (or more properly, magic cookies) provide a means for browsers to store persistent information without the need for access to CGI scripts, custom executables, or other means of data storage and retrieval. I use a 'variable' metaphor for working with cookies as described in the following sections:

- The Variable Metaphor
- Reading Variables
- Writing and Deleting Variables

#### The Variable Metaphor

An easy way to access random pieces of information from a cookie is through variable assignment. By assigning a recognizable name to persistent information, you can easily pull out relevant pieces from the cookie using a simple subroutine.

The WWW PIM uses three different types of variables to store information. It uses `%%TDx` where `x` is the record number to store to-do's, `%%ADx` where `x` is the record number for addresses, and, finally, `%%APmm/dd/yyyy` for appointment dates.

#### Reading Variables

The code in Listing 24.2 is used to read a variable from within the cookie.

> Listing 24.2. The `readVariable()` function.

>      1: Function readVariable(sVariableName)

>      2: Dim iLocation

>      3: Dim iNameLength

>      4: Dim iValueLength

>      5: Dim iNextSemicolon

>      6: Dim sTemp

>      7:

>      8: iNameLength = Len(sVariableName)

>      9: iLocation = InStr(Document.Cookie, sVariableName)

>     10: If iLocation = 0 Then

>     11:     readVariable = ""

>     12: Else

>     13:     sTemp = Right(Document.Cookie, Len(Document.Cookie) - iLocation + 1)

>     14:     If Mid(sTemp, iNameLength + 1, 1) <> "=" Then

>     15:         readVariable = ""

>     16:     Else

>     17:         iNextSemicolon = InStr(sTemp, ";")

>     18:         If iNextSemicolon = 0 Then iNextSemicolon = Len(sTemp) + 1

>     19:         If iNextSemicolon = (iNameLength + 2) Then

>     20:             readVariable = ""

>     21:         Else

>     22:             iValueLength = iNextSemicolon - iNameLength - 2

>     23:             readVariable = Mid(sTemp, iNameLength + 2, iValueLength)

>     24:         End If

>     25:     End If

>     26: End if

>     27: end function

>     28:

The `readVariable()` function takes a single parameter-the variable name to read-and returns the value of that variable. The `readVariable()` function accomplishes this through several iterations of `InStr` and `Mid`. This works fine for storing numerical information, but you run into a problem when storing random character information. Let's say you create a variable called `Appt`, which stores appointment information. Now if a user enters `Dentist Appt` in their appointment information, `InStr` can return the wrong chunk of information, or worse, complete garbage. The `readVariable()` function attempts to reduce this possibility by searching for an equal sign (`=`) immediately after the string being sought. To further reduce the chances of this problem occurring, routines append `%%` to the beginning of each variable name.

#### Writing and Deleting Variables

The page uses the same subroutine to both write and delete variables from the cookie. Just like those found on the store shelves, all magic cookies have expiration dates. By default, an entry in a cookie will expire when the browser is closed, which isn't very persistent. Imagine what would happen if your daily planner erased itself every time you closed the cover.

The `setVariable` routine in Listing 24.3 takes a pair of parameters: The former is the variable name, and the latter its corresponding value. It then appends an expiration date of September 28, 1998, to the end of the cookie.

> Listing 24.3. The `setVariable` routine.

>     1:

>     2: Sub setVariable(sVariableName, varVariableValue)

>     3: Document.Cookie = sVariableName & "=" & varVariableValue & ";expires=Monday, 28-

>        Sep-98 12:00:00 GMT"

>     4: end sub

>     5:

Correspondingly, the `killVariable` routine in Listing 24.4 sets the variable to `NULL`, appends an expiration date of January 1, 1995, and then calls the `setVariable` routine. Watchful readers will note that using `killVariable` will create an entry with two expiration dates. Fortunately for us, the second date is ignored and then deleted.

> Listing 24.4. The `killVariable` routine.

>     1:

>     2: Sub killVariable(sVariableName)

>     3: setVariable sVariableName, "NULL;expires=Monday, 01-Jan-95 12:00:00 GMT"

>     4: end sub

### Creating Dynamic HTML

The code uses five functions to create the statements needed to display the information in HTML format. These functions are divided into two related areas:

- Creating HREF functions
- Creating the calendar functions

The first set of functions is used to create a single `<A HREF>` statement that displays the stored data, if any, and provides the necessary code to edit the item.

The second set of functions is similar to the first, but also generates a table in addition to one of the HREF functions.

#### Creating HREFs from Scratch

The following three functions in Listings 24.5, 24.6, and 24.7 are used to create a single `<A HREF>` statement. The first two take only the record number as a parameter and pass back a formatted string that can be written directly into the document. Listing 24.7, `makAP_URL(),` takes the month, day, and year for the current record.

The code in Listing 24.6, which is used to create the address code, takes the address provided and converts it to a `mailto:` directive so that a user can easily mail someone on the address list by clicking on the address, or edit the record by clicking on the number.

In addition to the code to edit an appointment, the `makAP_URL()` function also contains an `onMouseOver` event to place the current appointment in the status bar.

> Listing 24.5. The `makTD_URL()` function.

>     1:

>     2: Function makTD_URL(iRecord)

>     3: If Trim(readVariable("%%TD" & Trim(iRecord))) <> "NULL" Then

>     4:     makTD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addTodo(" &

>                    Trim(iRecord) & ")>" & iRecord & ". " & readVariable("%%TD" &

>                    Trim(iRecord)) & "</A>"

>     5: Else

>     6:     makTD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addTodo(" &

>                    Trim(iRecord) & ")>" & iRecord & ". </A>"

>     7: End If

>     8: End Function

>     9:

> Listing 24.6. The `makAD_URL()` function.

>     1:

>     2: Function makAD_URL(iRecord)

>     3: If Trim(readVariable("%%AD" & Trim(iRecord))) <> "NULL" Then

>     4:     makAD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addAddr(" &

>            Trim(iRecord) & ")>" & iRecord & ". " & "

>     	   </a>" & "<A HREF=mailto:" &

>            readVariable("%%AD" & Trim(iRecord)) & ">" &

>     	   readVariable("%%AD" &

>            Trim(iRecord)) & "</A>"

>     5: Else

>     6:     makAD_URL = "<A LANGUAGE=VBScript HREF=#null onClick=addAddr(" &Trim(iRecord)

>     & ")>" & iRecord & ". " & "</A>"

>     7: End If

>     8: End Function

>     9:

> Listing 24.7. The `makAP_URL()` function.

>      1:

>      2: Function makAP_URL(m,d,y)

>      3: Dim stAppt

>      4:

>      5: stAppt = readVariable("%%AP" & m & "/" & d & "/" & y)

>      6: If Len(Trim(stAppt)) > 0 AND Trim(stAppt) <> "NULL" Then

>      7:     sTemp = "<A LANGUAGE=VBScript HREF=#null onClick="

>      8:     sTemp = sTemp & Chr(34)

>      9:     sTemp = sTemp & "Call addAppt(" & m & ", " & d & ", " & y & ")"

>     10:     sTemp = sTemp & Chr(34)

>     11:     sTemp = sTemp & " onMouseOver="

>     12:     sTemp = sTemp & Chr(34)

>     13:     sTemp = sTemp & "Call ApptStat(" & m & ", " & d & ", " & y & ")" & Chr(34)

>             & ">"

>     14:     sTemp = sTemp & d & "!</a>"

>     15: Else

>     16:     sTemp = "<A LANGUAGE=VBScript HREF=#null onClick="

>     17:     sTemp = sTemp & Chr(34)

>     18:     sTemp = sTemp & "Call addAppt(" & m & ", " & d & ", " & y & ")"

>     19:     sTemp = sTemp & Chr(34)

>     20:     sTemp = sTemp & " onMouseOver="

>     21:     sTemp = sTemp & Chr(34)

>     22:     sTemp = sTemp & "Call ApptStat(" & m & ", " & d & ", " & y & ")" & Chr(34)

>             & ">"

>     23:     sTemp = sTemp & d & "</A>"

>     24: End If

>     25: makAP_URL = sTemp

>     26: End Function

#### Creating the Calendar

The final set of HREF functions is the `makCalendar()` function (see Listing 24.8), which iterates through several loops to create a calendar out of an embedded table based on the current month and year, and the `GMonth()` function (see Listing 24.9), which provides the month names for `makCalendar()`.

> Listing 24.8. The `makCalendar()` function.

>     1:

>     2: Function makCalendar()

>     3: m=Month(Now())

>     4: y=Year(Now())

>     5:

>     6: FirstDay = WeekDay(Dateserial(y,m,1))

>     7: DaysInMonth= Day(Dateserial(y,m+1,1)-1)

>     8: ThisMonth=GMonth(Month(Dateserial(y,m,1)), true) & " " & Year(Dateserial(y,m,1))

>     9:

>     10: sCalendar=""

>     11: sCalendar=sCalendar & "<CENTER><TABLE BORDER=1 CELLPADDING=2>"

>     12: sCalendar=sCalendar & "<TR><TH COLSPAN=7>" & ThisMonth & "</TH>"

>     13: sCalendar=sCalendar & "<TR><TH WIDTH=50 ALIGN=CENTER>Sun</TH><TH WIDTH=50

>           ALIGN=CENTER>Mon</TH><TH WIDTH=50 ALIGN=CENTER>Tue</TH><TH WIDTH=50

>           ALIGN=CENTER>Wed</TH><TH WIDTH=50 ALIGN=CENTER>Thu</TH><TH WIDTH=50

>           ALIGN=CENTER>Fri</TH><TH WIDTH=50 ALIGN=CENTER>Sat</TH></TR>"

>     14:

>     15: ictrDay=0

>     16: For Row=1 to 6

>     17:     sCalendar=sCalendar & "<TR>"

>     18:     For Col=1 to 7

>     19:         sCalendar=sCalendar & "<TD WIDTH=50 ALIGN=CENTER>"

>     20:         If Row=1 AND Col=FirstDay then

>     21:             ictrDay=1

>     22:         End If

>     23:         If ictrDay = 0 Then

>     24:             sCalendar=sCalendar &  "&nbsp;"

>     25:         End If

>     26:         If ictrDay <> 0 Then

>     27:             If ictrDay <= DaysInMonth Then

>     28:                 sCalendar=sCalendar & makAP_URL(m,ictrDay,y)

>     29:             End If

>     30:             If ictrDay > DaysInMonth Then

>     31:                 sCalendar=sCalendar &  "&nbsp;"

>     32:             End If

>     33:             ictrDay=ictrDay+1

>     34:         End if

>     35:         sCalendar=sCalendar &  "</TD>"

>     36:     Next

>     37:     sCalendar=sCalendar &  "</TR>"

>     38: Next

>     39: sCalendar=sCalendar &  "</TABLE>"

>     40: makCalendar = sCalendar

>     41: End Function

>     42:

The `makCalendar()`function creates a table definition, creates the month banner and the seven weekday columns, and then loops through the remaining rows and columns, calling the `makAP_URL()` function from Listing 24.7 to place the date. The `makAP_URL()` function appends an exclamation mark to the end of a date that contains an appointment.

The GMonth() function takes a pair of arguments, the month number, and a boolean value to determine whether it should return a long month like January or a short month like Jan. Although the short month is not used, it produces a value that can be used in the expiration field of a cookie so that you can expand this example to create time-sensitive to-do's.

> Listing 24.9. The `GMonth()` function.

>     1: Function GMonth(iMonth, fLongShort)

>     2: Select Case iMonth

>     3: Case 1

>     4:     If fLongShort = true then GMonth="January" else GMonth="Jan"

>     5: Case 2

>     6:     If fLongShort = true then GMonth="February" else GMonth="Feb"

>     7: Case 3

>     8:     If fLongShort = true then GMonth="March" else GMonth="Mar"

>     9: Case 4

>     10:     If fLongShort = true then GMonth="April" else GMonth="Apr"

>     11: Case 5

>     12:     If fLongShort = true then GMonth="May" else GMonth="May"

>     13: Case 6

>     14:     If fLongShort = true then GMonth="June" else GMonth="Jun"

>     15: Case 7

>     16:     If fLongShort = true then GMonth="July" else GMonth="Jul"

>     17: Case 8

>     18:     If fLongShort = true then GMonth="August" else GMonth="Aug"

>     19: Case 9

>     20:     If fLongShort = true then GMonth="September" else GMonth="Sep"

>     21: Case 10

>     22:     If fLongShort = true then GMonth="October" else GMonth="Oct"

>     23: Case 11

>     24:     If fLongShort = true then GMonth="November" else GMonth="Nov"

>     25: Case 12

>     26:     If fLongShort = true then GMonth="December"  else GMonth="Dec"

>     27: End Select

>     28: End Function

>     29:

### Presenting Information

An application is completely useless if it doesn't provide the user any feedback. In order to keep the WWW PIM from being completely useless, we need to add some code that creates an interface for the user to edit and view information from the page. This code is broken down into two separate groups:

- The `add` routines
- The `ApptStat` routine

#### The `add` Routines

The `add` routines in Listings 24.10, 24.11, and 24.12 provide an interface for the user to input, edit, or delete information. Each routine displays one or more message boxes and prompts the user for the necessary information. Depending on whether the user is adding, editing, or deleting information, each routine then calls either `setVariable` or `killVariable.`

The `addTodo` and `addAddr` routines both display a generic message box like the one in Figure 24.2.

Figure 24.2 : The Add/Delete Item message box.

> Listing 24.10. The `addTodo` routine.

>     1:

>     2: Sub addTodo(iRecord)

>     3: Dim sTodo

>     4: Dim iChoice

>     5:

>     6: iChoice = MsgBox("Do you want to add or delete this item? Click yes to add or no

>        to delete.", 3, "Add/Delete Item")

>     7: Select Case iChoice

>     8:     Case 6

>     9:         sTodo = InputBox("What do you want to do?", "Add To-Do")

>     10:         Call setVariable("%%TD" & Trim(iRecord), sTodo)

>     11:     Case 7

>     12:         killVariable "%%TD" & Trim(iRecord)

>     13:     Case 2

>     14:         Exit Sub

>     15: End Select

>     16: window.navigate "wwwpim.htm"

>     17: End Sub

>     18:

Listing 24.10 displays an input box that looks like Figure 24.3.

Figure 24.3 : The Add To-Do dialog.

> Listing 24.11. The `addAppt` routine.

>     1:

>     2: Sub addAppt(m,d,y)

>     3: Dim sAppt

>     4: Dim TempAppt

>     5:

>     6: TempAppt = readVariable("%%AP" & Trim(m) & "/" & Trim(d) & "/" & Trim(y))

>     7:

>     8: If Len(Trim(TempAppt)) > 0 Then

>     9:     sAppt = InputBox("Please enter or edit your appointment list for today",

>                 "Add/Edit Appointment", readVariable("%%AP" & Trim(m) & "/"

>     & Trim(d) & "/"       & Trim(y)))

>     10: Else

>     11:     sAppt = InputBox("Please enter or edit your appointment list for today",

>             "Add/Edit Appointment")

>     12: End If

>     13: If Len(Trim(sAppt)) > 0 Then

>     14:     Call setVariable("%%AP" & Trim(m) & "/" & Trim(d)

>     & "/" & Trim(y), sAppt)

>     15: Else

>     16:     killVariable("%%AP" & Trim(m) & "/" & Trim(d) & "/" & Trim(y))

>     17: End If

>     18: window.navigate "wwwpim.htm"

>     19: End Sub

>     20:

Listing 24.11 displays an input box like the one in Figure 24.4.

Figure 24.4 : The Add/Edit Appointment dialog.

Listing 24.12 displays an input box like the one in Figure 24.5.

Figure 24.5 : The Add/Delete address routine.

> Listing 24.12. The `addAddr` routine.

>     1:

>     2: Sub addAddr(iRecord)

>     3: Dim Addr

>     4: Dim iChoice

>     5: iChoice = MsgBox("Do you want to add or delete this item? Click yes to add or no

>     to delete.", 3,"Add/Delete Item")

>     6:

>     7: Select Case iChoice

>     8:     Case 6

>     9:         Addr=InputBox("What address do you want to add?", "Add Email Address")

>     10:         Call setVariable("%%AD" & Trim(iRecord), Addr)

>     11:     Case 7

>     12:         killVariable "%%AD" & Trim(iRecord)

>     13:     Case 2

>     14:         Exit Sub

>     15: End Select

>     16: window.navigate "wwwpim.htm"

>     17: End Sub

>     18:

#### The `ApptStat` Routine

The `ApptStat` routine (see Listing 24.13) is called by the `onMouseOver` event associated with each day. When the mouse passes over a date, this routine is called and the current appointment is placed in the status bar.

> Listing 24.13. The `ApptStat` routine.

>     1:

>     2: Sub ApptStat(m,d,y)

>     3: Dim sTemp

>     4:

>     5: sTemp    = CStr(d & " " & readVariable("%%AP" & m & "/" & d & "/" & y))

>     6: If Len(Trim(sTemp)) > 0 AND readVariable("%%AP" & m & "/" & d & "/" & y) <> "NULL" Then

>     7:     window.status = sTemp

>     8: Else

>     9:     window.status = CStr(d)

>     10: End If

>     11: End Sub

### Tying It All Together

Now that we've covered all the routines that support generation of the page, we have one last procedure to cover, the `docCreate` routine.

#### The `docCreate` Procedure

The `docCreate` procedure in Listing 24.14 encapsulates all the previous functions to generate all of the HTML for the page. It creates each column one at a time, filling in each cell with an `<HREF>` from one of the `mak()` functions, and then it calls `document.write` to append the new content to the document.

> Listing 24.14. The `docCreate` procedure.

>     1:

>     2: Sub docCreate

>     3: Dim sDocument

>     4: sDocument = "<TD ALIGN=LEFT VALIGN=TOP WIDTH=35%><CENTER><B>To Do</B></CENTER>"

>     5: sDocument = sDocument & Chr(13) & Chr(10) & "<HR>"

>     6: For i = 1 to 10

>     7:     sDocument = sDocument & "<BR>" & makTD_URL(i)

>     8: Next

>     9: sDocument = sDocument & "</TD><TD ALIGN=CENTER VALIGN=MIDDLE WIDTH=30%>"

>     10: sDocument = sDocument & makCalendar()

>     11: sDocument = sDocument & "</TD><TD ALIGN=LEFT VALIGN=TOP WIDTH=35%>"

>     12: sDocument = sDocument & "<CENTER><B>ADDRESSES</B></CENTER>"

>     13: sDocument = sDocument & Chr(13) & Chr(10) & "<HR>"

>     14: For j = 1 to 10

>     15:     sDocument = sDocument & "<BR>" & makAD_URL(j)

>     16: Next

>     17:

>     18: sDocument = sDocument & "</TD></TR>"

>     19: sDocument = sDocument & Chr(13) & Chr(10) & "</TABLE>"

>     20:

>     21: Document.Write sDocument

>     22:

>     23: End Sub

>     24:

## Review

After trying this sample, you can see how to create Web applications that can easily store and retrieve complex sets of information and display them to the user.

Here's a few challenges for you to extend your WWW Personal Information Manager:

- Extend functionality by allowing you to create as many to-do's and addresses as you want, place appointments for future dates, or add more information like phone and street addresses.
- Add a notification capability that tells you when appointments are due or forthcoming.
- Convert the page to use ActiveX controls to give it a sleek and modern look.

| 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.