|
|
From the Web:
James Thiele's Reminder Calendar
James Thiele has designed a simple reminder calendar as an example
of using cookies in JavaScript. The calendar is available at
http://www.eskimo.com/~jet/javascript/calendar_js.html
Rather than being a full-fledged application, this page provides
simple functionality, yet is a compelling example of how cookies
can extend the value of a script beyond time and session constraints.
The program (see Listing W4.1) displays a calendar of the current
month, much the same as in Dave Eisenberg's calendar example.
When users click on any of the days in the calendar, they either
can enter a reminder for that day, or are alerted of their previously
entered reminder.
When the user reloads the page or returns to it later in the month,
the days with reminders are displayed in a different color.
Listing W4.1. Source code for James Thiele's Reminder Calendar.
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!-- to hide script contents from old browsers
//
// Cookie Functions
// Written by: Bill Dortch, hIdaho Design
// The following functions are released to the public
domain.
//
//
// "Internal" function to encode cookie value. This
permits cookies to
// contain whitespace, comma and semicolon characters.
//
function encode (str) {
var dest = "";
var len = str.length;
var index = 0;
var code = null;
for (var i = 0; i < len; i++) {
var ch = str.charAt(i);
if (ch == " ") code = "%20";
else if (ch == "%") code = "%25";
else if (ch == ",") code = "%2C";
else if (ch == ";") code = "%3B";
else if (ch == "\b") code =
"%08";
else if (ch == "\t") code =
"%09";
else if (ch == "\n") code =
"%0A";
else if (ch == "\f") code =
"%0C";
else if (ch == "\r") code =
"%0D";
if (code != null) {
dest += str.substring(index,i)
+ code;
index = i + 1;
code = null;
}
}
if (index < len)
dest += str.substring(index, len);
return dest;
}
//
// "Internal" function to decode cookie values.
//
function decode (str) {
var dest = "";
var len = str.length;
var index = 0;
var code = null;
var i = 0;
while (i < len) {
i = str.indexOf ("%", i);
if (i == -1)
break;
if (index < i)
dest += str.substring(index,
i);
code = str.substring (i+1,i+3);
i += 3;
index = i;
if (code == "20") dest += "
";
else if (code == "25") dest
+= "%";
else if (code == "2C") dest
+= ",";
else if (code == "3B") dest
+= ";";
else if (code == "08") dest
+= "\b";
else if (code == "09") dest
+= "\t";
else if (code == "0A") dest
+= "\n";
else if (code == "0C") dest
+= "\f";
else if (code == "0D") dest
+= "\r";
else {
i -= 2;
index -= 3;
}
}
if (index < len)
dest += str.substring(index, len);
return dest;
}
//
// "Internal" function to return the decoded value of
a cookie
//
function getCookieVal (offset) {
var endstr = document.cookie.indexOf (";",
offset);
if (endstr == -1)
endstr = document.cookie.length;
return decode(document.cookie.substring(offset, endstr));
}
//
// Function to return the value of the cookie specified
by "name".
// name - String object containing the
cookie name.
//
function GetCookie (name) {
var arg = name + "=";
var alen = arg.length;
var clen = document.cookie.length;
var i = 0;
while (i < clen) {
var j = i + alen;
if (document.cookie.substring(i, j) ==
arg)
return getCookieVal (j);
i = document.cookie.indexOf(" ",
i) + 1;
if (i == 0) break;
}
return null;
}
//
// Function to create or update a cookie.
// name - String object object containing
the cookie name
// value - String object containing the
cookie value. May contain
// any valid sting characters,
including whitespace, commas and quotes.
// expires - Date object containing the
expiration date of the cookie,
// or null to expire the cookie
at the end of the current session.
//
function SetCookie (name, value, expires) {
document.cookie = name + "=" + encode(value)
+ ((expires == null) ? "" :
Â("; expires="
+ expires.toGMTString()));
}
// Function to delete a cookie. (Sets expiration date
to current date/time)
// name - String object containing the
cookie name
//
function DeleteCookie (name) {
var exp = new Date();
var cval = GetCookie (name);
document.cookie = name + "=" + cval + ";
expires=" + exp.toGMTString();
}
function intro()
{
document.write ("<CENTER>");
document.writeln("<BR>");
document.write ("<H1>");
document.write ("Reminder Calendar");
document.writeln("</H1>");
document.writeln("</CENTER>");
document.writeln("<h2>How to use
the Reminder Calendar:</h2>");
document.writeln("<ul><li>Click
on a date to add a reminder");
document.writeln(" <li>Click
on that date again to see the reminder");
document.writeln(" <li>Reload
the page to see dates with
Âreminders in different
colors");
document.writeln("</ul>");
document.writeln("<h2>Notes:</h2>");
document.writeln("<ul><li>Lame
user interface");
document.writeln(" <li>Can't
delete a reminder");
document.writeln(" <li>Reminders
disappear in about 24 hours");
document.writeln("</ul>");
document.writeln("<h2>This is mostly
a programming example of:</h2>");
document.writeln("<ul><li>Using
cookies in JavaScript");
document.writeln(" <li>Using
text links to call a
Âfunction, not open a URL");
document.writeln("</ul>");
document.writeln("<h2>Credits:</h2>");
document.writeln("<ul><li>Cookie
Functions written by:
Â<A href='mailto:[email protected]'>Bill
Dortch</A>, hIdaho Design");
document.writeln("<ul>The functions
are at:");
document.writeln(" <li>Code:
<A href='http://www.hidaho.com/cookies/
cookie.txt'>
http://www.hidaho.com/cookies/cookie.txt</A>");
document.writeln(" <li>Demo:
<A href='http://www.hidaho.com/cookies/
Âcookie.html'> http://www.hidaho.com/cookies/cookie.html</A>");
document.writeln("</ul>");
document.writeln(" <li>Reminder
Calendar by
ÂJames Thiele who can be
reached:");
document.writeln(" <UL><LI>at
his home page ");
document.writeln(" <A
href='http://www.eskimo.com/~jet'>
Âhttp://www.eskimo.com/~jet</A>");
document.writeln(" <LI>
via email at ");
document.writeln(" <address><A
href='mailto:[email protected]'>
Â[email protected]</a></address></p>");
document.writeln("</ul>");
}
function arrayOfDaysInMonths(isLeapYear)
{
this[0] = 31;
this[1] = 28;
if (isLeapYear)
this[1]
= 29;
this[2] = 31;
this[3] = 30;
this[4] = 31;
this[5] = 30;
this[6] = 31;
this[7] = 31;
this[8] = 30;
this[9] = 31;
this[10] = 30;
this[11] = 31;
}
function daysInMonth(month, year)
{
//
do the classic leap year calculation
var isLeapYear = (((year % 4 == 0) &&
Â(year % 100 != 0)) || (year
% 400 == 0));
var monthDays = new arrayOfDaysInMonths(isLeapYear);
return monthDays[month];
}
function calendar()
{
var monthNames = "JanFebMarAprMayJunJulAugSepOctNovDec";
var today =
new Date();
var day =
today.getDate();
var month =
today.getMonth();
var year
= today.getYear() + 1900;
// figure out how many days this month will
have...
var numDays = daysInMonth(month, year);
// and go back to the first day of the month...
var firstDay = today;
firstDay.setDate(1);
// and figure out which day of the week it hits...
var startDay = firstDay.getDay();
var column = 0;
// Start the calendar table
document.write("<CENTER>");
document.write("<TABLE BORDER>");
document.write("<TR><TH COLSPAN=7>");
document.write(monthNames.substring(3*month,
3*(month + 1)) + " " + year);
document.write("<TR><TH>Sun<TH>Mon<TH>Tue<TH>Wed<TH>Thu<TH>Fri<TH>Sat");
// put blank table entries for days of week
before beginning of the month
document.write("<TR>");
for (i=1; i < startDay; i++)
{
document.write("<TD>");
column++;
}
for (i=1; i <= numDays; i++)
{
// Write the day
var s = "" + i;
if ((GetCookie("d"+i)
!= null))
// s = s.fontcolor(document.vlinkColor);
s = s.fontcolor("#FF0000");
s = s.link("javascript:dayClick("
+ i + ")")
document.write("<TD>"
+ s);
// Check for end of week/row
if (++column == 7)
{
document.write("<TR>");
// start a new row
column =
0;
}
}
document.write("</TABLE>");
document.writeln("</CENTER>");
}
////////////////////////////
//////// dayClick //////////
////////////////////////////
function dayClick(day)
{
var expdate =
new Date ();
expdate.setTime
(expdate.getTime() + (24 * 60 * 60 * 1000));
Â//
24 hrs from now
var prefix =
"d";
var theCookieName =
prefix + day;
var theDayclickedReminder
= GetCookie(theCookieName);
if (theDayclickedReminder != null) {
alert("The
reminder for day " + day + " is:" +
theDayclickedReminder);
} // end if
if (confirm("Do
you wish to enter a reminder for day " +
Âday
+ " of this month?"))
{
x
= prompt("Enter a reminder for day "+ day +
Â"
of this month", theDayclickedReminder);
SetCookie (theCookieName,
x, expdate);
} // end if
}
// --> <!-- end hiding contents from old browsers -->
</SCRIPT>
<TITLE>James Thiele's Calendar reminders
</TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!-- to hide script contents from old browsers
// Write the intro
// Write the calendar
calendar();
document.write("<HR>");
intro();
// --> <!-- end hiding contents from old browsers -->
</SCRIPT>
<IMG SRC="../RainbowLine.gif">
<A href="index.html"><IMG SRC="javascriptlogo.gif">To
JavaScript stuff</A>
<br><em>Page last modified 24 Jan 96</em>
</BODY>
</HTML>
The results look like Figures W4.1 and W4.2.
Figure W4.1 : A reminder prompt dialog appears when users click a date for the first time.
Figure W4.2 : In future visits, the days with reminders are displayed in different color.
|
The first thing you notice is that Thiele is using an early version of Bill Dortch's cookie function set. This version was written before JavaScript included the escape() and unescape() functions, which forced Dortch to write his own
functions, encode() and decode(), to perform the encoding of values.
|
In any case, the newer version of Dortch's functions is backward
compatible and could replace the old version in this script without
affecting its operation in newer browsers.
Thiele has written five functions to implement his calendar program:
intro(), arrayOfDaysInMonth(),
daysInMonth(), calendar(),
and dayClick().
In addition, he builds most of the body of his HTML document using
a JavaScript script:
<SCRIPT LANGUAGE="JavaScript">
<!-- to hide script contents from old browsers
// Write the intro
// Write the calendar
calendar();
document.write("<HR>");
intro();
// --> <!-- end hiding contents from old browsers -->
</SCRIPT>
This script is quite simple: it calls calendar()
to display the calendar, it draws a horizontal line, and then
it calls intro(), which displays
most of the rest of the text of the script.
The intro() Function
This function needs little discussion. It is just a static collection
of document.write() statements
that output the introductory information about the application.
The arrayOfDaysInMonth() Function
The arrayOfDaysInMonth()
function simply creates a twelve-element array containing the
number of days in each calendar month. It accepts one Boolean
variable as an argument. This enables it to correctly set the
number of days in February based on whether or not it is a leap
year.
The daysInMonth() Function
This function takes two arguments-the month and year-and uses
these to determine if it is a leap year. It then creates an array
of days in each month of the particular year and returns the number
of days in the specified month.
The calendar() Function
The calendar() function is
where some of the more complex processing occurs.
var monthNames = "JanFebMarAprMayJunJulAugSepOctNovDec";
var today =
new Date();
var day =
today.getDate();
var month =
today.getMonth();
var year
= today.getYear() + 1900;
// figure out how many days this month will
have...
var numDays = daysInMonth(month,
year);
// and go back to the first day of the month...
var firstDay = today;
firstDay.setDate(1);
// and figure out which day of the week it hits...
var startDay = firstDay.getDay();
var column = 0;
As you might expect, the function starts by setting up key variables
for use throughout the function. These include a string of month
names-the same technique you saw in Dave Eisenberg's calendar
script.
The firstDay Date
object is used to get the day of the week of the first day of
the month and store it in startDay.
// Start the calendar
table
document.write("<CENTER>");
document.write("<TABLE BORDER>");
document.write("<TR><TH COLSPAN=7>");
document.write(monthNames.substring(3*month,
3*(month + 1)) + " " + year);
document.write("<TR><TH>Sun<TH>Mon<TH>Tue<TH>Wed<TH>Thu<TH>Fri<TH>Sat");
// put blank table entries for days of week
before beginning of the month
document.write("<TR>");
for (i=1; i < startDay; i++)
{
document.write("<TD>");
column++;
}
After building the header of the table, which holds the calendar
for the month, the for loop
inserts blank cells for each of the unused days of the week before
the first day of the month.
for (i=1; i <= numDays;
i++)
{
// Write the day
var s = "" + i;
if ((GetCookie("d"+i)
!= null))
// s = s.fontcolor(document.vlinkColor);
s = s.fontcolor("#FF0000");
s = s.link("javascript:dayClick("
+ i + ")")
document.write("<TD>"
+ s);
// Check for end of week/row
if (++column == 7)
{
document.write("<TR>");
// start a new row
column =
0;
}
}
Next, another for loop repeats
for each day in the month. For each day, a cell is created and
the number is displayed with a hypertext link to the URL javascript:dayClick(number).
This is done by using the string's link
method to add the URL. As you will see in Chapter 10,
"Strings, Math, and the History List," if the link
method is used, then the value of the string is surrounded by
an appropriate <A>
HTML container tag.
Note |
Notice the use of the javascript: URL. This type of URL can be used to call a function in the current document. When used in the HREF attribute of the <A> tag, this is often an alternative to using the onClick
event handler. It can also be used in the open location dialog box of the Navigator browser to test what a line of JavaScript code will evaluate to. In this case, the result of evaluating an expression is displayed in the browser window.
|
Similarly, the fontcolor()
method adds the appropriate HTML tags to the value of the string.
In this case, the fontcolor()
method is called only if the cookie for that day has been previously
set with a reminder.
The final if statement checks
whether you have reached the last column, and if so, closes the
row, opens a new row in the table, and resets the column
counter.
The dayClick() Function
This function handles both prompting for a reminder and displaying
existing reminders. It is invoked when the user clicks on a date.
It accepts the date as an argument.
var
expdate = new Date ();
expdate.setTime
(expdate.getTime() + (24 * 60 * 60 * 1000));
//
24 hrs from now
var prefix =
"d";
var theCookieName =
prefix + day;
var theDayclickedReminder
= GetCookie(theCookieName);
The function starts by setting up its variables, including an
expiry date for cookies and a value of the cookie for the selected
date.
if (theDayclickedReminder
!= null) {
alert("The
reminder for day " + day + " is:" +
theDayclickedReminder);
} // end if
If the value of the cookie is not null,
then the reminder is displayed in an alert dialog box.
if
(confirm("Do you wish to enter a reminder for day "
+
day
+ " of this month?"))
{
x
= prompt("Enter a reminder for day "+ day +
"
of this month", theDayclickedReminder);
SetCookie (theCookieName,
x, expdate);
}
// end if
If the value of the cookie is null,
then users are asked if they wish to enter a reminder for the
current day and, if they do, they are further prompted for the
text of the reminder. The reminder is then stored in a cookie.
Notice the use of the confirm()
call as the condition of the if
statement-confirm() returns
a value of true or false
based on the user's response.
|