Tuesday, February 8, 2011

Encountering the Whitespace Incident

Last week, I encountered an interesting issue while coding something at work.

Essentially, there's some JavaScript hard-coded on one page that's triggered with the page content handled with the CMS. What that piece of code does is essentially running through an inline list of years and changing the CSS code of the links inside the list items (and tables below) depending on what was done using a for loop (from start_year to end_year). You can see this here.

Originally, the start and end values for the loop were hard-coded as constants. This worked well until I had to add 2011 to the list. The list is part of the page content, which can be modified with the CMS, but the JavaScript is not. Changing the constant every year is simply not practical.

I decided to make the JavaScript smarter.

This is a candid post. If you don't understand JavaScript and the DOM model, you're not going to understand this.

The start_year constant can remain hard-coded, for the simple reason that there's no content before that date. The end_year needs to change, heavily.

The way the JavaScript code was triggered was when clicking on a year in the inline list, a function was called that toggles the styles of list items and toggles the visibility (display) of the tables under the list. The addition is to logically have the toggle function call another one that counts the number of direct children nodes of the ul node.
var eyr = 2008;
var lyr;

function CountNodes() {
var count = 0;
var parent;
var child;

parent = document.getElementById("yearMenu");
child = parent.childNodes.length;

while (count < child) {
count++;
}

return count;
}

function ToggleTables(thisYear) {
lyr = (eyr + CountNodes()) - 1;

for (i=eyr; i <= lyr; i++) {
// change li's links styles
}

// toggle styles for current year items and table
}
This created a problem. The count was always higher than the number of actual direct child to the ul node. It took quite some research until I stumbled onto this. Whitespace are counted. Since they are node-type 3, we just need to do an if check to exclude them. Fix was simple, separating the loop counter and the actual child-node count resulted in this:
function CountNodes() {
var count = 0;
var n = 0;
var parent;
var child;

parent = document.getElementById("yearMenu");
child = parent.childNodes.length;

while (n < child) {
if (parent.childNodes[n].nodeType != 3) {
count++;
}

n++;
}

return count;
}
With this, now I can just add an item in the ul list from the CMS and the JavaScript will follow.