-->
Bookmark and Share

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;">&nbsp;</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).