reptile7's JavaScript blog
Wednesday, November 11, 2009
RAM ? Clock : Freeze
Blog Entry #162

You may recall that in the course of going through the HTML Goodies JavaScript Script Tips, we analyzed several JavaScript clock scripts:
(1) In Script Tips #25-28, we discussed a script that codes a basic, text-based digital clock.
(2) In Script Tips #84-86, we deconstructed a script that codes an image-based digital clock.
(3) In Script Tips #87-90, we dissected a script coding a "world clock" that could display times for various cities around the world.
The "So, You Want A JavaScript Clock, Huh?" tutorial in HTML Goodies' Beyond HTML : JavaScript sector presents yet another clock script, which is as well written as (if not more so than) any of the Script Tips clock scripts and which we'll briefly check over in today's post.

Demo #1, and giving credit

The "So, You Want A JavaScript Clock, Huh?" tutorial begins, A clock on your home page? Why, yes! I'll have one too, please. The thing at the top center of the page is what you can get here, i.e., the tutorial page should host a demo, which is nowhere to be seen. The key to the missing demo lies in the following sentences in the tutorial's "How To Do It..." section: You'll notice toward the bottom of the text page that there is a </script> command and then a small form program. Get that, too. It gives you the box that goes around the clock. The person who posted the current "So, You Want A JavaScript Clock, Huh?" page did not "get that, too" - he or she put the script that codes the clock in the tutorial source, but did not bring along the document body HTML that houses the clock. So I guess it's up to me to give you a demo.

At the tone the time will be:

Via the Internet Archive, I was able to track down an earlier version of the "So, You Want A Java[Script] Clock, Huh?" page (ah, back in the good ol' days, when Joe himself was at the helm of his ship). Unlike the current tutorial page, the older tutorial page
(a) sports a functioning demo,
(b) discusses in a "First Things First" subsection the 'system requirements' for the tutorial script (not so important in this day and age), and
(c) gives credit to the script's author: My special thanks to Mr. Madison Bryan for providing me with this script. You're a gentleman. Let me second Joe's gratitude: wherever you are, Madison, we thank you for your efforts.

Script deconstruction

The "So, You Want A JavaScript Clock, Huh?" script is accessed by following the tutorial's Click here to get it link. Let's begin our analysis with a look at the script's document body HTML:

<body onload="startclock( );">
<form name="clock" onsubmit="0" action="">
<input type="text" name="face" size="11" value="....Initializing...." />

The clock display will be loaded into a text box named face held by a form named clock.

The text box's size attribute should be set to at least 13; the clock display comprises twelve or thirteen characters depending on the time of day, and thus the size="11" attribute would cut off the display's last one or two characters if the user's default font preference were set to a monospace font (e.g., Courier).

The clock form's onsubmit="0" attribute serves no purpose and can be removed. Moreover, the name attribute of the form element was deprecated by XHTML 1.0. But only the earliest browsers need a form container for the input element anyway; you might prefer to ditch the form element, give the input element an id="clockbox" attribute, and then access the input element via a document.getElementById("clockbox") reference. (N.B. Removing the form element will change the clock's 'formatting flow' from block-level to inline.)

For that matter, an <input type="text"> is semantically an odd container for the clock display given that no user 'input' is involved. A more state-of-the-art way to render the clock would be to put it in a div or span element via the DOM innerHTML property, e.g.:

<!-- To give the clock a block-level rendering per the original script, put it in a -->
<div id="clockdiv"></div>
// via
document.getElementById("clockdiv").innerHTML = timeValue;

As of this writing, innerHTML is a widely-supported but nonstandard property; however, the W3C apparently plans to 'bring it on board' for HTML 5. Alternatively, the not-quite-as-widely-supported* but standard DOM textContent property can likewise be used to load the clock into the textual element of your choice. (*On my computer, textContent is supported by Firefox, Safari, and Opera, but not by MSIE 5.2.3.)

The <!----------> comment line between the body and form element start-tags is there to improve the readability of the code, but is otherwise unnecessary and can be removed.

We're ready to get the clock under way. When the script document has finished loading in the browser window, the body element's onload event handler calls the startclock( ) function in the script element in the document head:
function startclock( ) {
    stopclock( );
    showtime( );
The startclock( ) function first calls the stopclock( ) function that precedes it in the script element:
var timerID = null;
var timerRunning = false;

function stopclock( ) {
    if (timerRunning)
    timerRunning = false;
As the script stands, the stopclock( ) code is unnecessary and can be thrown out - the script will later set the Boolean timerRunning variable to true, but we won't be calling stopclock( ) again. But let's suppose we want to give the user the ability to stop the clock once it gets going via clicking a button:

<button type="button" onclick="stopclock( );">Stop the clock, now</button>

In this case, stopclock( )'s window.clearTimeout(timerID); command will effectively stop the clock by pulling the plug on the recursive function call that moves the clock along (vide infra).

startclock( ) then calls the showtime( ) function that follows it in the script element. The showtime( ) function initially creates a new Date object and then gets the hour, minute, and second parts of that object:
function showtime( ) {
    var now = new Date( );
    var hours = now.getHours( );
    var minutes = now.getMinutes( );
    var seconds = now.getSeconds( );
Mozilla's current Date object page, which links to separate pages for the getHours( ), getMinutes( ), and getSeconds( ) methods, is here.

We now build the clock display, which is given the identifier timeValue, from our Date object data. Data type-wise, timeValue will be a string containing numerals delimited by colons plus an A.M./P.M. part. As for any digital time display, timeValue begins with an hour value, which is installed by the next showtime( ) command:

var timeValue = "" + ((hours > 12) ? hours - 12 : hours);

Command comments
• We first discussed the ?: conditional operator in Blog Entry #101, which deconstructs the Script Tips #84-86 clock script.
• An empty string is prepended to the hour value in order to stringify it, i.e., to convert the hour value from a number data type to a string data type; this is unnecessary because the following showtime( ) command will append a string to (and thus stringify) the timeValue value.
• Like the Script Tips #25-28 and #84-86 clock scripts, the "So, You Want A JavaScript Clock, Huh?" script codes a 12-hour and not a 24-hour clock. Accordingly, 12 is subtracted from hours (now.getHours( )) values in the range 13-23, inclusive, i.e., for the hours spanning 1PM to midnight.
• For the midnight-to-1AM hour, the clock's hour value will be 0; if you would rather it be 12, then you should place an if (hours == 0) timeValue = 12; statement immediately after the above command.
• I was originally going to point out that both sets of parentheses are unnecessary (for reasons relating to JavaScript operator precedence and type conversion), but the parentheses do make the command more understandable, so never mind.

The next two showtime( ) commands respectively set the minute and second parts of the clock:

timeValue += ((minutes < 10) ? ":0" : ":") + minutes;
timeValue += ((seconds < 10) ? ":0" : ":") + seconds;

Other than their different variable names, these assignments are identical to the corresponding assignments in the Script Tips #87-90 clock script, which were detailed in (near the end of) Blog Entry #104.

Finally, we (a) complete the display by appending P.M. or A.M., depending on the hours value, to the timeValue string:

timeValue += (hours >= 12) ? " P.M." : " A.M.";

(b) load the display into the face text box:

document.clock.face.value = timeValue;

(c) provide a recursive function call for updating the clock:

timerID = window.setTimeout("showtime( );", 1000);
// The clock is updated every 1000 milliseconds.

and (d) set timerRunning to true:

timerRunning = true; }

Whether we do or don't keep the stopclock( ) function, neither the stopclock( ) function nor the showtime( ) function need be called via the intermediacy of the startclock( ) function; for its part, showtime( ) can be directly called by the body element start-tag

<body onload="showtime( );">

or by a

window.onload = showtime;

script command.

Two more practical points

(1) Something I didn't mention earlier: loading the clock into a textual element will allow you to more reliably style it per your preference.

And here's what time it is:

Here's the style rule set that I've applied to the clock:

#clockspan {
background-color: #b22222; /* firebrick */
color: #adff2f; /* green-yellow */
font-family: Courier, monospace;
font-weight: bold;
text-decoration: underline;

Modern browsers will apply most or all of the above style declarations to an input element. Nevertheless, the W3C warns here that [a]uthors are recommended to treat such support as experimental.

(2) The recursive showtime( ) call sets up an infinite loop without an exit condition, and I would think that allowing the clock to run indefinitely would give rise to a function stack overflow and cause the browser to hang, but I'm not sure about that.

Next up in the Beyond HTML : JavaScript sector is a "JavaScript Browser Test Scripts" set of tutorials that use browser/screen sniffing to do various things. These tutorials are of rather marginal utility, but I thought in the following entry we might begin a quick look at them, if only for 'archival purposes'.


Comments: Post a Comment

<< Home

Powered by Blogger

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