reptile7's JavaScript blog
Monday, March 30, 2015
Beneath the Headers I
Blog Entry #347

Let's get back now to our ongoing analysis of the Java Goodies Calendar and Datebook script and its ampCalendar_Display( ) function. With the calTable table's caption and header row in place

September 1998 - Eat at Joe's

we turn our attention to the table's data rows in this and the next posts.

More table loops

The remaining rows are written out by a 5-iteration for loop, giving us 6 rows total for the table; a nested 7-iteration for loop writes out the cells of those rows.

// Now create each row. for (j = 0; j < 5; j++) { x = 0; document.writeln("<tr>"); for (i = 0; i < 7; i++) { ... } document.writeln("</tr>"); x += 7; }

Near the end of the inner loop body is a

this.m_myDate.setDate(this.m_myDate.getDate( ) + 1);

line that is key to understanding the script, specifically, this command will walk us through the display month on a day-by-day basis.

Dead cells

For a given display month, 0-6 second row cells will precede the beginning of the month and 0-7 sixth row cells will follow the end of the month: these cells are 'grayed out' by the if clause of an if...else statement that makes up the inner loop body.

for (i = 0; i < 7; i++) { if (this.m_myDate.getDay( ) > (i + x) || this.m_myDate.getMonth( ) != this.month - 1) document.writeln("<td width=\"14%\" bgcolor=\"#" + this.m_strDead + "\">&nbsp;</td>"); else { ... this.m_myDate.setDate(this.m_myDate.getDate( ) + 1); } }

September 1998 was a while ago, wasn't it? Suppose we pass this.month = m = 4 and this.year = y = 2015 to the ampCalendar( ) constructor function to create a calendar for April 2015, whose 1st day falls on a Wednesday and whose 30th day falls on a Thursday.

As detailed two entries ago, this.m_myDate initially points to the first day of the display month. For 1 April 2015, this.m_myDate.getDay( ) returns 3. If the outer loop's j counter is 0 and the inner loop's i counter is 0, 1, or 2, then the this.m_myDate.getDay( ) > (i + x) subcondition returns true and therefore the Sunday, Monday, and Tuesday cells in the second row are given a this.m_strDead (silver) background color but no visible content. (I don't know if removing the &nbsp; non-breaking spaces would cause a validation problem, but there's no harm in keeping them there, of course.)

When i hits 3 - i.e., when we hit 1 April - both if subconditions return false and the second row's Wednesday cell is colored by one of the conditionals described in the following sections. Re the second subcondition, this.m_myDate.getMonth( ) and this.month - 1 are both 3 and will remain so throughout the month of April.

At this point the aforenoted this.m_myDate.setDate(this.m_myDate.getDate( ) + 1); command, which concludes the if...else statement's else clause, begins to push this.m_myDate through the subsequent April days; it increments this.m_myDate.getDate( ) to 2, 3, 4, ... and causes this.m_myDate.getDay( ) to run in a 3-4-5-6-0-1-2 3-4-5-6-0-1-2 ... cycle until we get to the end of the month.

The x = 0, 7, 14, ... variable counts up the number of cells below the header row and - as far as I can tell - the role of the + x operation in the this.m_myDate.getDay( ) > (i + x) subcondition is to prevent i from falling below this.m_myDate.getDay( ) so as to prevent the below-the-second-row cells in the prior-to-the-1st-of-the-month table columns from being grayed out. However, i and this.m_myDate.getDay( ) are in fact equal throughout a given display month: in the same way that a new j row resets i to 0, this.m_myDate.getDay( ) is reset to 0 for the Sunday of that row. Consequently, the x counter is superfluous and can be thrown out.

At the end of the 30 April (j = 4, i = 4) iteration, the setDate( ) operation pushes this.m_myDate to 1 May. At the start of the 1 May (j = 4, i = 5) iteration, the this.m_myDate.getDay( ) > (i + x) subcondition returns false but the this.m_myDate.getMonth( ) != this.month - 1 subcondition returns true - this.m_myDate.getMonth( ) is now 4 for May, whereas this.month - 1 is still 3 - and as a result the Friday cell in the sixth row is grayed out. Although this.m_myDate is not pushed to 2 May for the next (j = 4, i = 6) iteration, the May ≠ April situation still applies and therefore the sixth row's Saturday cell is grayed out as well.

Like the other cells in the table, each m_strDead cell has a width that is 14% of its containing block, whatever that happens to be.

Leading up to today

As intimated above, the this.m_myDate.getDay( ) > (i + x) and this.m_myDate.getMonth( ) != this.month - 1 subconditions are both false and thus the if...else statement's else clause is operative for the dates of the display month. The else clause itself comprises an if...else if...else construct that prints
(a) date numbers
(b) and memos if appropriate
in the display month cells; in addition, it
(i) gives each display month cell a background color that depends on the this.m_myDate and this.m_now dates and months
(ii) and otherwise applies a common set of styles to the cells and their contents.

The construct's if clause

if (this.m_myDate.getDate( ) < this.m_now.getDate( ) && this.m_myDate.getMonth( ) <= this.m_now.getMonth( )) document.writeln("<td valign=\"top\" width=\"14%\" bgcolor=\"#" + this.m_strPast + "\"><b>" + "<font face=\"" + this.font + "\" size=\"" + this.fontSize + "\">" + this.m_myDate.getDate( ) + "</b><br>" + this.getText(this.m_myDate.getDate( )) + "</font></td>");

addresses this.m_myDate date numbers that are less than the this.m_now date number for this.m_myDate month numbers that are less than or equal to the this.m_now month number, regardless of year. For example, if today is 26 March 2015, then the if condition will return true for 1 January through 25 January, 1 February through 25 February, and 1 March through 25 March in 2014 or 2015 or 2016 or any other year. The cells for these dates are marked with a this.m_strPast (#e1e1d1) background color.

Content-wise, a this.m_myDate.getDate( ) date number and perhaps also a this.getText(this.m_myDate.getDate( )) memo are loaded into each this.m_strPast cell. The this.getText(this.m_myDate.getDate( )) command calls the ampcal.js script's ampCalendar_getText( ) function

function ampCalendar_getText(n) { var x = 0; while (x < this.m_rgDay.length) { if (n == this.m_rgDay[x]) return this.m_rgTxt[x]; x++; } return ""; }

and passes thereto this.m_myDate.getDate( ), which is given an n identifier. The ampCalendar_getText( ) function steps through the m_rgDay[ ] array in search of the n date number via an incrementing x index. If a this.m_rgDay[x] value that matches n is found, then the corresponding this.m_rgTxt[x] string in the m_rgTxt[ ] array is returned to the this.getText(this.m_myDate.getDate( )) call in the document.writeln( ) command; if n isn't present in the m_rgDay[ ] array, then an empty string is returned instead. For example, if n = 7, then n will match this.m_rgDay[3] and therefore the this.m_rgTxt[3] = "Take puppies to the vet" string is written to the cell.

Style-wise (over and above the cells' #e1e1d1 bgcolor and 14% width), the date number + memo content is pushed to the top of the cells via a valign='top' attribute and rendered according to the this.font = "Verdana, Arial, Helvetica" font family and this.fontSize = "2" font size; on my computer, a size='2' font element attribute maps onto a font-size:small; style declaration. Also, the date number but not the memo is bolded with a b element.

If we were to tag the this.m_strPast cells via a class='preDates' identifier, then we can recast the if clause as:

.preDates { vertical-align: top; width: 14%; background-color: #e1e1d1; font-family: Verdana, Arial, Helvetica; font-size: small; }
.preDates span { font-weight: bold; }

if (this.m_myDate.getDate( ) < this.m_now.getDate( ) && this.m_myDate.getMonth( ) <= this.m_now.getMonth( )) document.write("<td class='preDates'><span>" + this.m_myDate.getDate( ) + "<\/span><br>" + this.getText(this.m_myDate.getDate( )) + "<\/td>");

We'll deal with the remaining types of data cells in the following entry.

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)