Chapter 21

Calendar of Events


CONTENTS

"Fan sites," or Web sites that are dedicated to an individual's favorite something, are an interesting and often amusing facet of the CyberScenery. If you have something that you're extremely fond of, and you're considering constructing a Web site in homage to it, you might want to offer on your site (among all the other interesting little tidbits you just know your visitors can't live without) some sort of calendar or chronology of events. This could include appearance dates, historical dates, and so on.

Scripting Text Animations

When you think of "animation," whether it's related to the Web or not, you normally think of graphics. While this is generally true, you're not limited to animating images. With a little creativity, you can also create animated text.

TIP
City home pages, that is, Web sites that serve as introductions to a particular city, often use events calendars to advertise upcoming events. One such city is Mankato, MN, whose page can be found at http://www.prairie.lakes.com/cgi-bin/db/cal/display_month.pl.

The <MARQUEE> Tag

Internet Explorer includes several new HTML tags. One of these tags, <MARQUEE>, lets you:

Scroll text from left to right, or right to left.
Start and end at specific locations.
"Loop" the text continuously.

Listing 21.1 is a code fragment that demonstrates the <MARQUEE> tag in action.


Listing 21.1  Using Microsoft's <MARQUEE>
<body bgcolor="White">
<hr>
<marquee behavior=slide 
         direction=right>This text slides from left to right.</marquee>
<hr>
<marquee behavior=slide 
         direction=left>This text slides from right to left.</marquee>
</body>

Part of a scripter's job is to take advantage of any and every built-in browser trick possible. For Explorer users, the <MARQUEE> tag fits the bill, but for the rest of the Web community, something else is required.

Scripted Marquees

JavaScript gives you the ability to control the messages displayed in the status bar. The status bar is that area at the bottom of the browser normally occupied by the URL of the currently selected hyperlink. Couple this with JavaScript's built-in timer functions, and you can create your own scrolling marquee easily.

The logic of a scrolling status bar is straightforward:

  1. Display the first character of the message at the far right of the window.
  2. Wait for a little bit.
  3. Shift the display to the left one character.
  4. Display the next character.
  5. Go back to step two and repeat the process over and over.

To "keep as much code under one roof" as possible, you can "wrap" much of the functionality-that is, bundling the data and functions that manipulate it, within a user-defined object, as demonstrated in listing 21.2.


Listing 21.2  A Marquee Object
function Marquee(str) {
   this.msg = str;

   for(var i=0; i<50; i++) {
      this.msg = " " + this.msg;
   }

   this.pos   = 1;
   this.delay = 500;
   this.reset = clearMessage;
   this.start = startMarquee;
}

The clearMessage and startMarquee references are examples of attaching functions to an object, creating methods. In this case, clearMessage() (listing 21.3) takes care of updating the status bar and keeps track of what part of the message is being displayed. The startMarquee() (also in listing 21.3) function simply gets everything going.

NOTE
Remember, when associating functions to objects, do not include the parentheses or any parameters in either the target function name or the method name within the object. By only specifying the name and nothing else, you create a link to the function without actually running it.


Listing 21.3  The clearMessage() Function
function clearMessage(obj) {
   if(obj == null) {
      obj = this;
   }

   if(obj.pos < obj.msg.length) {
      window.status = obj.msg.substring(obj.pos, obj.msg.length);

      obj.pos++;

      window.setTimeout("clearMessage("+obj+")", obj.delay);
   } else {
      window.status = " ";
      obj.pos = 0;
   }
}   

function startMarquee() {
   window.setTimeout("clearMessage("+this+")", this.delay);
}

Notice that startMarquee() relies on the special this keyword to reference the current object, while clearMessage() method takes the object as a parameter. This is necessary because clearMessage() is normally called from within the setTimeout() function, and it's not possible to use the this keyword as part of the setTimeout() command to execute. It is possible, however, to construct a setTimeout() command like the one shown:

window.setTimeout("clearMessage("+this+")", this.delay);

where this (because it's outside the parentheses) is resolved to the object itself. To make certain clearMessage() also works if called as an object method, the parameter is tested to see if it's "null," which it would be if called as:

"myMarquee.reset();clearMessage()" determines how much of the current message to display and transfers that much to the status bar. If the message hasn't been totally displayed, the timer is reset to repeat the process until the entire message has been scrolled. By making clearMessage() a method of the marquee object, you can refer to the various properties of the marquee object directly, without having to reference the particular object. This also makes it possible to create multiple marquees, each with its own properties that clearMessage() will manipulate.

Implementing this object involves nothing more than creating a Marquee object and launching it by calling its start() method:

myMarquee = new Marquee("Your message here");
myMarquee.start();

Now, with the basis for your scrolling display finished, it's time to tie it into a database of available messages to display.

The Events Database

Chapter 8 "Advertising with Billboards" introduces the concept of using a JavaScript array to hold a large collection of information-a scripted database. If you wanted to display one of several different messages as a marquee, storing those messages as a database would make the most sense. In addition, the database needed here is much simpler-there's only one field per record (the text to display). Therefore, all that's really needed is an array of strings.

As before, start with creating the array (see listing 21.4), and populate it with the strings you want to display.


Listing 21.4  A "Scrollbase"
function initArray(iSize) {
   this.length = iSize;

   for(var i=1; i<=iSize; i++)
      this[i] = null;

   return this;
}
Messages    = new initArray(3);
Messages[1] = new Marquee("Visit your bookstore!");
Messages[2] = new Marquee("Buy this book!");
Messages[3] = new Marquee("Tell your friends!");
...

Then write a little control code to scroll one Marquee object after another. The pos property of the marquee object becomes important at this point, because when the message has completed scrolling, the value of pos is reset to zero. With this information, you can have a master timing loop that watches what's happening in the Marquee objects and reacts appropriately, as demonstrated in listing 21.5.


Listing 21.5  Controlling Multiple Marquees
var iWhichMarquee = 1;
var currMarquee  = null;

function MarqueeMaster(marqueeArray) {
   if(currMarquee == null || currMarquee.pos == 0) {
      if(++iWhichMarquee > marqueeArray.length) {
         iWhichMarquee = 1;
      }

      currMarquee = marqueeArray[iWhichMarquee];

      currMarquee.start();
   }

   setTimer("MarqueeMaster(" + marqueeArray + ")", 500);
}

The MarqueeMaster() function relies on two global variables to keep track of which marquee is currently running. When first called, "iCurrMarquee" is "null," so the process is initialized. Once "currMarquee" is set to a particular object, it then watches the object's pos property to see when it has reset itself (meaning the entire message has been displayed), and moves to the next marquee when done.

As with "seeding" an individual marquee, starting the master control requires only one JavaScript call:

MarqueeMaster(Messages);

JavaScript's internal timing functions take care of the rest.

By using the Date object, you determine what the "minute" was when the page was loaded. If you assume that every 15 minutes you have a small demonstration, the script compares the current time to when the next demonstration is. Based on that, you can change the scrolling text as needed.

HTML-Based Marquees

You're not limited to scrolling the text in the status bar to display upcoming events. If you frame your site, you can dedicate one frame to display new messages in much the same way.

Starting with a simple <FRAMESET> configuration:

<FRAMESET ROWS="*,50">
   <FRAME NAME="main" SRC="index2.html">
   <FRAME NAME="marquee" SRC="marquee.html" NORESIZE SCROLLING=NO>
</FRAMESET>

You can use the lower frame to display your messages. The actual code that drives the lower frame, however, must be located in the parent (the <FRAMESET>) document.

NOTE
Because Navigator wipes the memory of a frame whenever a new document is loaded, any JavaScript code you may place within it is lost with each reload. If you want to perform JavaScript manipulation within a dynamically created document, you must locate the JavaScript code elsewhere, such as in the parent frame.

In fact, you can use much of the same code just created to handle scrollbar marquees. The only thing that really needs to change is the function that handles the displaying of the message. Listing 21.6 demonstrates a slightly different clearMessage() function that handles writing to a different frame.


Listing 21.6  HTML Messages
function clearMessage() {
   tStr = "";

   if(pos < msg.length) {
      tStr += "<HTML><HEAD></HEAD>"
            + "<BODY BGCOLOR=#000000>"
            + "<H2>"
            + msg.substring(pos, msg.length)
            + "</H2>"
            + "</BODY></HTML>";

      pos++;

      window.setTimeout("clearMessage()", delay);
   } else {
      tStr += "<HTML><HEAD></HEAD>"
            + "<BODY BGCOLOR=#000000>"
            + "</BODY></HTML>";

      pos = 0;
   }

   theFrame.document.write(tStr);
   theFrame.document.close();
}   

The theFrame variable is actually a new property you add to the Marquee object, which points to the frame where you want to display the messages. This isn't strictly necessary, as you could always use:

window.frames['marqueeFrame']...;

but creating a property to contain this reference makes coding easier.

If you wanted to get fancy, you could have the text and background color change dynamically as well. By adjusting the tStr variable that builds the new page to:

tStr += "<HTML><HEAD></HEAD><BODY BGCOLOR=" + PickColor() + ">"
      + "<H2><FONT COLOR=" + PickColor() +
      + msg.substring(pos, msg.length) + 
      + "</FONT></H2></BODY></HTML>";

You can implement a simple color picker function that returns one of the redefined text color strings that browsers recognize.


Listing 21.7  Pick a Color
function PickColor() {
   iWhich = RandInt(colorArray.length) + 1;
   return colorArray[iWhich];
}

function LoadArray() {
   this.length = LoadArray.arguments.length;

   for(var i=1; i<=LoadArray.arguments.length; i++) {
      this[i] = LoadArray.arguments[i-1];
   }

   return this;
}

colorArray = new LoadArray("Black", "Olive", "Teal", "Red", 
                           "Blue", "Maroon", "Navy", "Gray", 
                           "Lime", "Fuchsia", "White", "Green", 
                           "Purple", "Silver", "Yellow", "Aqua");

function RandInt(num) {
   var n = (Math.random() * num).toString();
   return parseInt(n.substring(1, n.indexOf(".")-1));
}

This code block also demonstrates a different way of array initilization-that of creating the array and loading it with data in one statement.

NOTE
The RandInt() function utilizes the built-in random() function to generate a random integer within the range of 0 and num-1. Because random() generates a floating-point number between 0 and 1, it's necessary to parse out the decimal part of the result before returning the value for processing by other functions.

Perl Driving

With the code presented in the previous sections, you can display marquees scrolling across the bottom of the screen or display them within a separate frame. If you have a large database of possible events (or anything) that you want to scroll through, you may decide to store the database on the server as a Perl-readable file and have Perl do the following:

  1. Pull a subset of information-for example, all the events scheduled for this month.
  2. Format and generate both the HTML code and the JavaScript code to have the event generator run on the user's browser once the data has been retrieved.

You'll find the source code for the Perl implementation on the companion CD-ROM.

From Here…

This chapter takes a common concept, that of a calendar of upcoming events, and presents it in a slightly different manner: an animated "TelePrompTer" for your Web site. For more information about the concepts that relate to what you've learned here, check out: