Create the Calendar Constructor
Next, open a new file in your text editor and type in the constructor for the calendar object as follows:
// Constructor
function calendar(id, d, p){
this.id = id;
this.dateObject = d;
this.pix = p;
this.write = writeCalendar;
this.length = getLength();
this.month = d.getMonth();
this.date = d.getDate();
this.day = d.getDay();
this.year = d.getFullYear();
this.getFormattedDate = getFormattedDate;
// get the first day of the month's day
d.setDate(1);
this.firstDay = d.getDay();
// then reset the date object to the correct date
d.setDate(this.date);
}
The constructor takes three parameters: an
id value (so that it's possible to place multiple calendars on a single page), a JavaScript Date object (so a calendar can begin at any arbitrary date), and an array of JavaScript Image objects (which you can manipulate programmatically if need be).
In addition to assigning the three parameters to the appropriate properties, the code adds additional properties and methods to the calendar object that make it functional. All the properties expose values from the wrapped Date object, while the methods provide mechanisms that enable the calendar to display its information. Hiding the Date object within the calendar object is what the Façade design pattern is all about.
Write the Methods
The calendar contains three useful methods:
writeCalendar(),
getLength(), and
getFormattedDate(). To implement
getFormattedDate() the code uses two "convenience" arrays that hold the months of the year and the days of the week. Add the following code to your script file:
var days = new Array('Sunday','Monday','Tuesday',
'Wednesday','Thursday','Friday','Saturday');
var months = new Array('January',
'February','March','April',
'May','June','July','August','September',
'October','November','December');
function getFormattedDate(){
return days[this.day] + ', ' + months[this.month] +
' ' + this.date + ', ' + this.year;
// return this.month + '/' + this.date + '/' +
this.year;
}
If you'd prefer not to use the convenience arrays, you can get a formatted date from the calendar object itself. I've commented out the line in the
getFormattedDate() method that does just that. Don't delete the convenience arrays though, you'll need them later.
You know the old adage: "Thirty days hath September, April, June and November...." Calculating the length isn't quite that simple, but it's close.
|
|
You need to know the number of days in any particular month. The
getLength() method calculates that value, so the calendar's
length property represents the number of days in the currently displayed month. You know the old adage: "Thirty days hath September, April, June, and November...." Calculating the length isn't
quite that simple, but it's close. Add the following
getLength() method to your script:
function getLength(){
// thirty days has September...
switch(this.month){
case 1:
if ((this.dateObject.getFullYear()%4==0 &&
this.dateObject.getFullYear()%100!=0) ||
this.dateObject.getFullYear()%400==0)
return 29; // leap year
else
return 28;
case 3:
return 30;
case 5:
return 30;
case 8:
return 30;
case 10:
return 30
default:
return 31;
}
}
The
getLength() method correctly determines whether the currently displayed year is a leap year, and adjusts the return value accordingly.
Although the writeCalendar() method looks daunting, remember that you only have to write it once!
|
|
The
writeCalendar() method is the guts of the calendar object application. It's responsible for writing the HTML that displays the calendar on the Web page. Essentially, it generates a very long string built from the properties of the calendar object. Although it looks daunting, remember that you only have to write it once! Here's the
writeCalendar() method:
function writeCalendar(){
var calString = '<div id="calContainer">';
// write month and year at top of table
calString += '<table id="cal' + this.id +
'" cellspacing="0" width="200"' +
' style="border:1px black solid;">';
// write the image -- comment out to hide images
calString += '<tr><th colspan="7"><img src="' +
this.pix[this.month].src + '"/></th></tr>';
// write the month
calString += '<tr><th colspan="7" class="month">' +
months[this.month] + ', ' + this.year +
'</th></tr>';
// write a row containing days of the week
calString += '<tr>';
for(i=0;i<days.length;i++){
calString += '<th class="dayHeader">' +
days[i].substring(0,3) + '</th>';
}
// write the body of the calendar
calString += '<tr>';
// create 6 rows so the calendar doesn't resize
for(j=0;j<42;j++){
var displayNum = (j-this.firstDay+1);
if(j<this.firstDay){
// write the leading empty cells
calString += '<td class="empty"> </td>';
}else if(displayNum==this.date){
calString += '<td id="' + this.id +
'selected" class="date" ' +
'onClick="javascript:changeDate(this,\'' +
this.id + '\')">' + displayNum + '</td>';
}else if(displayNum > this.length()){
// Empty cells at bottom of calendar
calString += '<td> </td>';
}else{
// the rest of the numbered cells
calString += '<td id="" class="days" ' +
'onClick="javascript:changeDate(this,\'' +
this.id + '\')">' + displayNum + '</td>';
}
if(j%7==6){
calString += '</tr><tr>';
}
}
// close the last number row
calString += '</tr>';
// write the nav row
calString += '<tr>';
calString += '<td class="nav" ' +
'style="text-decoration:underline;"' +
' onClick="changeMonth(-12,\'' + this.id +
'\')"><</td>';
calString += '<td class="nav" ' +
'onClick="changeMonth(-1,\'' + this.id +
'\')"><</td>';
calString += '<td class="month" ' +
'colspan="3"> </td>';
calString += '<td class="nav"' +
' onClick="changeMonth(1,\'' + this.id +
'\')">></td>';
calString += '<td class="nav" ' +
'style="text-decoration:underline;text-' +
'align:right;" onClick="changeMonth(12,\'' +
this.id + '\')">></td>';
calString += '</tr>';
calString += '</table>';
calString += '</div>';
return calString;
}
There's a lot going on in this method. The first few lines write out containers and then the image to display as well as the Month, Year banner. You can comment out the line that writes the image if you'd like to create a traditional date picker. The code loops through the days array and picks off the first three letters of each day name to display the days of the week. Next, the method writes out the body of the calendar using the calendar object's
firstDay property to determine how many leading empty cells are required. Next, it creates table cells that represent each day of the month, applying the appropriate CSS style for the current day. Finally, it creates the navigation bar at the bottom of the calendar.