Calendar
See the demo page for the finished version of the code.The Column Loop
Now the function can fill in the cells of the current row. For each cell, it sets up handles to the cell's TD element and the link (A tag) element within it.
// Loop through a week. for (j = 0; j < rowEl.cells.length; j++) { cellEl = rowEl.cells[j]; linkEl = cellEl.firstChild; if (tmpDate.getMonth() == targetDate.getMonth()) { linkEl.date = new Date(Date.parse(tmpDate)); s = tmpDate.toString().split(" "); linkEl.title = s[0] + " " + s[1] + " " + s[2] + ", " + s[s.length - 1]; linkEl.firstChild.nodeValue = tmpDate.getDate(); linkEl.style.visibility = ""; } else linkEl.style.visibility = "hidden";
If the date falls within the target month the link is set for display. First
a user-defined property called date
is set to the date in
question. This will be used in the onclick
event handler so the
target date can be changed to this date if the user clicks on the link.
Next, the TITLE attribute of the link element is set to display the date when hovered over. This is not necessary, but it gives the user a little more visual confirmation. Then the text of the link is set to the day of the month. Finally, the link is made visible, in case it was hidden by the last call to the function.
When the date does not fall within the target month, the link is simply
hidden from view by setting its visibility
style.
The function then checks to see if the date matches the target date. If so, it adds a style class to the cell element in order to highlight it.
// Highlight the current date. if (cellEl.oldClass == null) cellEl.oldClass = cellEl.className; if (Date.parse(tmpDate) == Date.parse(targetDate)) cellEl.className = cellEl.oldClass + " target"; else cellEl.className = cellEl.oldClass;
Here, it adds a class named "target." Again, you could set up any style scheme you want. In the demo this class just gives the date a different background color. If it is not the target date, the function restores the cell's original CLASS attribute.
The last step within this inner loop is to move the date to the next day.
// Go to the next day. tmpDate.addDays(1);
This sets it up for the next cell. Once the inner and outer loops complete, the function restores the page display before exiting.
// Restore the page display. document.body.style.display = "";
Now let's look at the event handlers set up for all the links in the calendar display.
Event Handlers
If you recall, each date link had an onclick event handler set up for it in the form
<td> <a href="" onclick="setTargetDate(event, this); return false;"> </a> </td>
setTargetDate()
changes the target date to that day and
updates the calendar display.
function setTargetDate(event, link) { // Change the target date and update the calendar. if (link.date != null) { targetDate = new Date(Date.parse(link.date)); setCalendar(event); } }
Here you see where the date
property that was set for the link
is used. The global targetDate
is set to match that date and
setCalendar()
is called to update the display.
The arrow links at the bottom of the calendar are also set with
onclick
event handlers to call either addMonths()
or
addYears().
function addMonths(event, n) { // Advance the calendar month and update the display. targetDate.addMonths(n); setCalendar(event); } function addYears(event, n) { // Advance the calendar year and update the display. targetDate.addYears(n); setCalendar(event); }
Again, these alter the targetDate
global, this time using our
custom Date
methods, and update the calendar.
The "Reset" link uses this code in its onclick event handler:
targetDate = new Date(); setCalendar(event); return false;
Which sets targetDate
to the current date and updates the
display.
Lastly, the "Select" link will call displayDate()
when clicked.
This function simply shows targetDate
in an alert.
function displayDate(event) { // Display the current target date as a formatted string. alert(formatDate(targetDate)); } function formatDate() { var mm, dd, yyyy; // Return the target date in "mm/dd/yyyy" format. mm = String(targetDate.getMonth() + 1); while (mm.length < 2) mm = "0" + mm; dd = String(targetDate.getDate()); while (dd.length < 2) dd = "0" + dd; yyyy = String(targetDate.getFullYear()); while (yyyy.length < 4) yyyy = "0" + yyyy; return mm + "/" + dd + "/" + yyyy; }
Obviously, this could be changed to do something more useful, like filling
in a form field with the value of targetDate.
Conclusion
As mentioned, this example script could be put to good use with a little more work. But its main purpose was to demonstrate how you can extend a predefined JavaScript object using prototypes.
You can also use prototypes with user-defined objects. This is especially useful if you define an object in an external script for reuse but then want to change for some particular use.
Review the W3C DOM2 HTML standard recommendation.Incidentally, it also demonstrates some useful features of the document
object model. Specifically, the use of the row
and
cell
array properties of the TABLE and TR elements
respectively.
Many elements have specialized properties and methods that you can use and it's worth reviewing the standard to see what's available (see link at right).