by Owen Graupman
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 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.
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 &  " "
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 &  " "
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: 
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:
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:
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.
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.
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
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:
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.
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
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 &  " "
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 &  " "
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:
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 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 (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
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 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:
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: