Redo From Start - Calendar Script

You can rewrite JavaScript every so often so as to take advantage of both the changes in what JavaScript the current browsers can handle and also your own growing knowledge of JavaScript. Eventually though you are going to reach the point where it is better to start over from the beginning rather than trying to patch what you already have. You may end up plugging some completely rewritten code into the existing script just to replace part of the script or you may end up rewriting the entire script depending on just how much of the script is in need of updating.

One example of a script that has reached the point where it needs to be rewritten rather than just updated is my calendar script originally written in 2001. This script underwent a number of changes over the years to add further functionality to what started out as a basic popup calendar with the last update being done in 2007. An example script that I wrote to show the simplest way to create a table in JavaScript prompted me to revisit the concept of a calendar script and to use that table example code as the starting point for completely rewritten version of my calendar script.

Now one of the disadvantages of starting over rather than just rewriting sections of a script is that if the original script has developed a lot of flexibility in its functionality over time then you are not going to have all of that functionality in the new script until quite a way into the development process. With any new script you need to build up the functionality gradually. With a calendar script the obvious place to start is to be able to display a calendar for the current month with today's date highlighted. The original calendar script applied all the code to set the appearance of the calendar within the script itself however that script originated before browsers properly supported CSS. o keep the JavaScript as simple as possible and to provide maximum flexibility in how the new calendar looks we'll keep the actual styling of the calendar in the CSS rather than applying it from the script. Since this first version is set up to add the calendar to a specific id within the web page we'll simply apply the styles to the content of that id. Here's the CSS I used to style this first version of my new calendar script.

#cal table {border-collapse:collapse;}
#cal td {border:1px #000 solid;text-align:center;width:2em;}
#cal thead {font-weight:bold;background-color:#ccc;}
#cal caption {font-weight:bold;;font-size:1.5em;}
#cal .today {background-color:#6cc;}

With a simple empty div tag in the page supplying the id="cal" that both the CSS and JavaScript will reference in adding and styling the calendar we simply need the following script at the bottom of our page to display a calendar for the current month.

(function() {
"use strict";
var tabl, row, i, j, r, dow, mth, d, n, w, e, x;
d = new Date();
e = new Date(d.getFullYear(), d.getMonth()+1,0);
x = e.getDate();
w = 1;
n = (36+d.getDay()-d.getDate())%7;
r = 1+((n+x)/7);
dow = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
mth = ['January','February','March','April','May','June','July', 'August','September','October','November','December'];
tabl = document.createElement('table');
tabl.createCaption();
tabl.caption.innerHTML = mth[d.getMonth()]+' '+d.getFullYear();
tabl.createTHead();
row = tabl.tHead.insertRow(-1);
for (i=0; i < 7; i++) {
  row.insertCell(i);
  row.cells[i].innerHTML = dow[i];
  }
tabl.appendChild(document.createElement('tbody'));
for (j=1; j < r; j++) {
  row = tabl.tBodies[0].insertRow(-1);
  for (i=0; i < 7; i++) {
  row.insertCell(i);
  if (w < n+1 || w-n > x)
    row.cells[i].innerHTML = '&nbsp;';
  else row.cells[i].innerHTML = w-n;
  if (d.getDate()===w-n)
    row.cells[i].className='today';
  w++;
  }
}
document.getElementById('cal').appendChild(tabl);
})();

Now in writing this script the one thing I noticed most was the amount of code that I needed that I had already built into my extended date object and so the obvious next step was to convert this script into a toCalendar() method to add to that object and so make use of the functionality already in that object to reduce the amount of code quite significantly that is required to actually produce the calendar. This wasn't the direction that I intended to take the script when I started writing the new version but by the time the above code had been written it seemed the obvious next step.

By making this a method of an extended date object we automatically gain the ability to display a calendar for any month at all with a specific date highlighted simply by setting the date object to that date and calling that method. Just doing this gives us most of the functionality of the previous script with much greater flexibility in alternative ways we can use it. Of course my $D object is quite large as it provides a lot of other methods for making date processing easier and while you are likely to find these useful for a lot of the situations where you might want to display a calendar, there may be times when you don't want all that overhead of extra code. So let's look at how we might just add a toCalendar() method to the regular Date object.

Date.prototype.toCalendar = function() {
"use strict";
var tabl, row, i, j, r, dow, mth, n, w, e, x;
e = new Date(this.getFullYear(), this.getMonth()+1,0);
x = e.getDate();
w = 1;
n = (36+this.getDay()-this.getDate())%7;
r = 1+((n+x)/7);
dow = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
mth = ['January','February','March','April','May','June','July', 'August','September','October','November','December'];
tabl = document.createElement('table');
tabl.createCaption();
tabl.caption.innerHTML = mth[this.getMonth()]+' '+this.getFullYear();
tabl.createTHead();
row = tabl.tHead.insertRow(-1);
for (i=0; i < 7; i++) {
  row.insertCell(i);
  row.cells[i].innerHTML = dow[i];
  }
tabl.appendChild(document.createElement('tbody'));
for (j=1; j < r; j++) {
  row = tabl.tBodies[0].insertRow(-1);
  for (i=0; i < 7; i++) {
  row.insertCell(i);
  if (w < n+1 || w-n > x)
    row.cells[i].innerHTML = '&nbsp;';
  else row.cells[i].innerHTML = w-n;
  if (this.getDate()===w-n)
    row.cells[i].className='today';
  w++;
  }
}
return tabl;
};

Now that code allows us to take any date we have in our JavaScript and display a calendar for that month simply by using:

var d = new Date(2012, 1, 17);
document.getElementById('cal').appendChild(d.toCalendar());

This example would display the calendar for February 2012 with the 17th hightlighted. You would of course supply whatever value you want in order to display the required calendar.

All of the rest of the calendar processing that the original script provided can now be added as required simply by changing the value in the date field and replacing the content of the calendar using:

calid = document.getElementById('cal');
calid.removeChild(calid.getElementsByTagName('table')[0]);
calid.appendChild(d.toCalendar());

The end result is both a much smaller piece of code to create a calendar and far more flexibility in how we can use the calendar.

 

This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow
Donate