Mark-up languages such as HTML can become unwieldy when used to create complex layouts. For example, when creating a table that contains a large amount of uniform data, but displays many small graphics elements-each using an alternate image tag (e.g. descriptive text), status bar display hint, and URL link-repeated HTML can quickly fill the pages. These repeats create ever-larger HTML files, which of course take up more bandwidth.
By letting the client render the HTML using JavaScript, the size of the HTML source transported over the network can be dramatically reduced.
Consider the following example in which I created a calendar that users could check to see whether a specific date was available. The original page was around 70K, and required reloading with each visit in order to provide up-to-date information. Also, the calendar was presented in two ways, one for online viewing and the other in a printer-friendly format.
For my first attempt at creating this calendar, I created static pages from a small application, and uploaded them to a web-server. In this case, the data was no more recent than the last upload.
On my second attempt, I used Java Server Pages (JSP) and a database. Now the most current information was online, but it was still slow since the size of each calendar cell was almost 300 bytes.
For my third attempt, I once again used JSP, but this time, I let the client render the HTML output.
Because each element contained a lot of data that needed to be presented in clear format, but most of that information was a repeat, I figured that by letting the browser generate the output, I could considerably reduce the size of the file transferred over the network.
In choosing my data structure, I considered the following data criteria:
- It must be easy to process.
- It must be re-usable on several pages.
- It must hold just enough information for the client to produce the desired output.
I used a multidimensional array to hold the year, month, and cells for each month. Each cell in the calendar was described with only two values: the date, which was set to '0' for cells before the first and after the last day of a month; and the status, which was set to '0' for past dates, '1' for available dates, and '2' for dates already booked. This reduced the amount of data used to present a single cell to 6 bytes.
Since the data was reusable, some of the code for rendering it was reusable as well. The JavaScript used for this specific project is listed below.
The first step was to create a JSP that would output an array as follows: (Only March and April 2001 are shown here for simplicity.)
var array =
[2001, // (The year)
[2, // (The month)
[
[[0,0],[0,0],[0,0],[1,0],[2,0],[3,0],[4,0]], // (A row in a month)
[[5,0],[6,0],[7,0],[8,0],[9,0],[10,0],[11,0]],
[[12,0],[13,0],[14,2],[15,1],[16,1],[17,2],[18,2]],
[[19,1],[20,1],[21,1],[22,2],[23,1],[24,2],[25,2]],
[[26,2],[27,1],[28,1],[29,1],[30,2],[31,2],[0,0]]
]
],
[3,
[
[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[1,2]],
[[2,1],[3,1],[4,1],[5,2],[6,2],[7,2],[8,1]],
[[9,1],[10,2],[11,2],[12,1],[13,1],[14,2],[15,1]],
[[16,1],[17,2],[18,1],[19,1],[20,2],[21,2],[22,1]],
[[23,1],[24,1],[25,1],[26,1],[27,2],[28,2],[29,2]],
[[30,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]
]
]
];
The array was then parsed with the following functions:
function parseYear(yearArray) {
// First element in the array is the year.
var year = yearArray[0];
// The following is month arrays
for(m=1;m<yearArray.length;m++) {
parseMonth(yearArray[m],year);
}
}
function parseMonth(monthArray,year) {
// First element in the monthArray is the month number
var month = monthArray[0];
document.write("<div id='kal'>");
document.write("<a name='" + months[month] + "'></a>");
// Second element in the monthArray is the month table
parseTable(monthArray[1],year,month);
document.write("</div>");
}
function parseTable(tableArray,year,month) {
document.write("<table id='kal' border='1' ");
document.write("cellspacing='0' cellpadding='0' width='100%'>");
document.write("<caption>"+ months[month] + " " + year + "</caption>");
document.write("<tr align='middle' valign='middle'>");
for(th=0;th<7;th++) {
document.write("<th width='14%'>"+days[th]+"</th>");
}
document.write("</tr>");
// The number of rows in the tableArray is not fixed.
for(tr=0;tr<tableArray.length;tr++) {
parseRow(tableArray[tr],year,month);
}
document.write("</table>");
};
function parseRow(row,year,month) {
// Each row contains sevel cells
document.write("<tr align='left' valign='top'>");
for(td=0;td<7;td++) {
parseCell(row[td],year,month);
}
document.write("</tr>");
}
function parseCell(tc,year,month) {
document.write("<td>");
// A cell can either be blank (e.g. has a value of 0)
if (tc[0] == 0) {
kalBlank();
} else {
// Or it can have a status set
switch(tc[1]) {
case 0:
kalBeforeToday();
break;
case 1:
document.write(dayFormat(tc[0])+": ");
kalFree(year,month,tc[0]);
break;
case 2:
document.write(dayFormat(tc[0])+": ");
kalBusy(year,month,tc[0]);
break;
}
}
document.write("</td>");
return docCell;
}
function dayFormat(day) {
if (day < 10)
return "0"+day;
else
return day;
}
The above code was then placed in a separate file, and reused in several places. (Parsing the array can be done in one function, but in this case several functions were used for clarity.)
To make the above code run, the following functions were used: kalBlank(), kalBeforeToday(), kalFree(), and kalBusy(). These functions were the only ones needed to customize the output. These functions were implemented as follows to present the output online:
function kalBlank() {
document.write("<img align='TOP' src='blank.gif' alt=''>");
}
function kalBeforeToday() {
document.write("<img align='TOP' src='blank.gif' alt='Before today'>");
}
function kalFree(year,month,day) {
var wDate = day+". "+months[month]+" "+year;
var popStr = "The "+wDate+" is vacant. Click here to contact TopHat.";
document.write("<a target='f_tekst' href='../sendMail.jsp?msg=");
document.write("I would like to be contacted regarding the ");
document.write(wDate+"&sendSMS=true' ");
document.write("onMouseOver=\"window.status='"+popStr+"';return true;\" ");
document.write("onMouseOut=\"window.status='';return true;\" ");
document.write("><img align='TOP' border='0' src='ledig.gif' ");
document.write("alt='"+popStr+"'></a>");
}
function kalBusy(year,month,day) {
document.write("<img align='TOP' border='0' src='optaget.gif' ");
document.write("alt='This date is occupied.'>");
}
Rendering the above into a document was done in the body as follows:
<body>
<script type="text/javascript" language="javascript">
parseYear(array);
</script>
</body>
If you want the source, please contact me directly at sglasius@silverstream.com.
|