Полезная информация

Chapter 2

What Can You Do with JavaScript?


CONTENTS

JavaScript offers you much more expressive power than HTML alone. This chapter touches on a few of the things you can do with JavaScript, such as create multipart documents, build dynamic documents that take you through a Web site from one document to another, and generate documents that interact with the user. It is by no means exhaustive, as you can see by checking out some of the URLs listed in the Quick Reference at the end of this book.

Multipart documents with frames

You can create documents that split the browser window into pieces-you have probably seen such documents while surfing the Web. The pieces are called frames, and much of JavaScript's power derives from what it can do with frames.

Frames give you more control over the layout of your document than conventional HTML allows, and frames let you keep parts of your documents on the screen while other parts change. For example, in one frame you can place a corporate logo, copyright information, and so forth; in another frame, you can place a document describing some particularly interesting information about your company. As the user pages through your Web site, the frame that holds your logo and copyright can remain visible while the information in the other frame changes.

Frames also give you the power to create and present HTML on the fly. JavaScript code in the document of one frame can clear another frame and write new HTML or even more JavaScript code into another frame. Before JavaScript, it was enormously complicated to create, on the fly, a new page tailored to the user's wishes. Now you can do it yourself.

You define frames within a frame document, or layout document. A typical Web page is made up of an HTML element that contains a HEAD element and a BODY element. A frame document is usually made up of an HTML element that contains a HEAD element and a FRAMESET element.

FRAME elements are contained within FRAMESET elements, and FRAMESET elements can also contain other FRAMESET elements, allowing you to divide and subdivide the browser window. Be careful with this capability, however: You can easily subdivide the browser window to the point that nothing of value is visible.

Each FRAME element is loaded with its own Web page document. A frame document requires several separate documents; the one in Figure 2.1 requires four documents: one for the frame document itself, and one for each of the three frames.

Figure 2.1 : A typical frame document.

Here are the HTML file listings for the frame document in Figure 2.1. What follows is the file main.htm.

<HTML>
    <HEAD>
        <TITLE>Sample Frame Document</TITLE>
    </HEAD>
    <FRAMESET ROWS="2Ø%,*">
        <FRAME SRC="welcome.htm" NAME="Welcome" SCROLLING="auto"
            MARGINWIDTH=1 MARGINHEIGHT=1 NORESIZE>
        <FRAMESET COLS="2Ø%,8Ø%">
            <FRAME SRC="dir.htm" NAME="Directory" SCROLLING="auto"
                MARGINWIDTH=1 MARGINHEIGHT=1 NORESIZE>
            <FRAME SRC="contents.htm" NAME="Contents" SCROLLING="auto"
                MARGINWIDTH=1 MARGINHEIGHT=1 NORESIZE>
        </FRAMESET>
    </FRAMESET>
</HTML>

The outermost FRAMESET element breaks the window into rows; the top row is given 20 percent of the screen, and the bottom row is given the remainder of the screen. The top row will contain the document welcome.htm. The bottom row contains a FRAMESET element that divides the row in two columns. The left column gets 20 percent of the row's width and contains dir.htm. The right column gets the other 80 percent of the row's width and contains contents.htm.

The next listing is welcome.htm. It displays a single line, "Welcome to My Frame Document." The line is centered, and the text is green on a black background.

<HTML>
    <HEAD>
        <TITLE>Welcome</TITLE>
    </HEAD>
    <BODY BGCOLOR="ØØØØØØ" TEXT="ØØ8ØØØ" >
        <P ALIGN=CENTER>Welcome to My Frame Document</P>
    </BODY>
</HTML>

Next is dir.htm. It contains a list of topics, with lists nested inside lists. Like welcome.htm, it uses green letters on a black background.

<HTML>
    <HEAD>
        <TITLE>Directory</TITLE>
    </HEAD>
    <BODY BGCOLOR="ØØØØØØ" TEXT="ØØ8ØØØ" >
        <UL>
            <LI>Multi-Part Documents
            <UL>
                <LI>Reload Part of the Window
                <LI>Interactive Documents
            </UL>
            <LI>More Control over User Interaction
            <LI>Documents with Memory
            <LI>Live Documents
            <UL>
                <LI>Scrolling Messages
                <LI>Clocks
                <LI>Countdown Timers
                <LI>Self-Updating Documents
            </UL>
        </UL>
    </BODY>
</HTML>

Finally, below is contents.htm. It displays one of the topics for this page, and does so in green letters on a black background.

<HTML>
    <HEAD>
        <TITLE>Contents</TITLE>
    </HEAD>
    <BODY BGCOLOR="ØØØØØØ" TEXT="ØØ8ØØØ" >
        <P>
            <B>JavaScript</B> offers you <I>much</I> more expressive
            power than HTML alone. This chapter will touch on a few of 
            the things you can do with <B>JavaScript</B>, and is by no
            means exhaustive.
        </P>
    </BODY>
</HTML>

Reloading Part of the Window

So what can you do, once you've subdivided the browser window? Well, you can update one frame, loading it with a new document while the other frames remain unchanged. In the document shown in Figure 2.1, the top frame contains information about the overall purpose of the Web site. The lower-left frame contains a directory of pages that pertain to the purpose expressed by the top frame's document. The lower-right frame contains a page that the user has selected from the directory in the lower-left frame. The top and lower-left frames never change, but the user can change pages in the lower-right frame.

Creating Interactive Documents

You can also write JavaScript code that can rewrite the contents of a frame in response to the user's actions. You can't modify a frame's contents, but you can rewrite the frame contents from scratch. Here are three frame documents that demonstrate this capability:

Here is main2.htm; it simply divides the screen into two rows.

<HTML>
    <HEAD>
        <TITLE>Self-Modifying Document</TITLE>
    </HEAD>
    <FRAMESET ROWS="6Ø%,*">
        <FRAME SRC="input.htm" NAME="input" SCROLLING="auto" 
            MARGINWIDTH=1 MARGINHEIGHT=1 NORESIZE>
        <FRAMESET ROWS="78%">
            <FRAME SRC="output.htm" NAME="output" SCROLLING="auto" 
                MARGINWIDTH=1 MARGINHEIGHT=1 NORESIZE>
        </FRAMESET>
    </FRAMESET>
</HTML>

This is input.htm:

<HTML>
    <HEAD>
        <TITLE>Input</TITLE>
        <SCRIPT>
<!-- hide script
function sayHello(form)
    {
    parent.output.document.open();
    parent.output.document.open();
    var gt = unescape("%3E");
    parent.output.document.write("<HTML" + gt);
    parent.output.document.write("<BODY BGCOLOR='ØØ4ØØØ' TEXT='FFFFFF'" 
        + gt);
    parent.output.document.write("Hello " + form.firstName.value + " " + 
        form.middleName.value + " " + form.lastName.value);
    parent.output.document.write("</BODY" + gt);
    parent.output.document.write("</HTML" + gt);
    parent.output.document.close();
    }
// -->
        </SCRIPT>
    </HEAD>
    <BODY BGCOLOR="ØØ4ØØØ" TEXT="FFFFFF" >
        <FORM NAME="form">
            <INPUT TYPE=TEXT SIZE=2Ø NAME="firstName"> First Name
            <BR>
            <INPUT TYPE=TEXT SIZE=2Ø NAME="middleName"> Middle Name
            <BR>
            <INPUT TYPE=TEXT SIZE=2Ø NAME="lastName"> Last Name
            <BR>
            <INPUT TYPE=BUTTON VALUE="Say Hello" 
                ONCLICK="sayHello(this.form)">
        </FORM>
    </BODY>
</HTML>

input.htm creates a form into which you can write your first name, middle name, and last name. When you're done, you click on the button labeled "Say Hello." When you click on that button, the JavaScript function "sayHello" is called, with a reference to the form as a parameter. The function "sayHello" opens the document in the output frame and creates and displays a new page in the output frame. It uses the form to get the names you entered and incorporates them into the new page. To accomplish this trivial task without JavaScript would require writing a program that runs on a server-a much more difficult task than putting together this little piece of JavaScript.

The following is output.htm:

<HTML>
    <BODY BGCOLOR="ØØ4ØØØ" TEXT="FFFFFF" >
    </BODY>
</HTML>

This code does nothing at all except make the background of its frame match the background of the other frame. It doesn't have to do anything else; it's just a placeholder. Figure 2.2 shows the frame document when it's first loaded. Figure 2.3 shows the frame document after data has been entered in the form in the lower-left frame.

Figure 2.2 : Frame before data is entered.

Figure 2.3 : Frame after data is entered.

More control over user interaction

JavaScript recognizes several events that a user can cause within a document. You can create JavaScript code that reacts to those events, providing interaction with the user.

Within a FORM element, there are SELECT, INPUT, and TEXTAREA elements, which act as input fields. The user can typically move the cursor from one input field to another by using the Tab key or by clicking the pointing device in an input field. When the user moves the cursor from one field (the source) to another (the destination), the destination field is said to have acquired focus; the user can now modify that field's contents. At the same time, the source field has lost focus. In Netscape terminology, the destination field has experienced a focus event and the source field has experienced a blur event.

Another kind of event takes place when the user highlights text in a field; this is called a select event. A change event occurs when text within a field is changed and focus is moved to another field. A click event occurs when certain fields are clicked on with the pointing device.

You can write JavaScript expressions or functions that are executed when any one of these events occurs on a field. The following code demonstrates how these events and their event handlers work. Each of the input fields has event handlers that handle focus, blur, select, change, or click events. Each event handler calls the announce function, passing it the name of the input field and the name of the event. The announce function displays that information in the window's status area.

<HTML>
    <HEAD>
        <TITLE>Focus, Blur, Select, Change, Click Test</TITLE>
        <SCRIPT>
<!--
function announce(widgetName, eventType)
    {
    status = "The " + widgetName + " field just experienced a " +
                eventType + " event";
    return true;
    }
//-->
        </SCRIPT>
    </HEAD>
    <BODY >
        <FORM ONSUBMIT="return false">
            <INPUT TYPE=BUTTON NAME="button" VALUE="button" 
                ONCLICK="announce('button','click')">
            <INPUT TYPE=CHECKBOX NAME="checkbox" 
                ONCLICK="announce('checkbox','click')">A
            <INPUT TYPE=CHECKBOX NAME="checkbox" 
                ONCLICK="announce('checkbox','click')">B
            <INPUT TYPE=CHECKBOX NAME="checkbox"
                ONCLICK="announce('checkbox','click')">C
            <INPUT TYPE=RADIO NAME='radio' 
                ONCLICK="announce('radio','click')">AM
            <INPUT TYPE=RADIO NAME='radio' 
                ONCLICK="announce('radio','click')">FM
            <BR>
            <INPUT TYPE=RESET NAME="reset" 
                ONCLICK="announce('reset','click')">
            <BR>
            <INPUT TYPE=SUBMIT NAME="submit" 
                ONCLICK="announce('submit','click')">
            <BR>
            <INPUT TYPE=TEXT NAME="text" SIZE=1Ø 
                ONBLUR="announce('text','blur')" 
                ONCHANGE="announce('text','change')" 
                ONFOCUS="announce('text','focus')" 
                ONSELECT="announce('text','select')">
            <BR>
            <TEXTAREA NAME="textArea" COLS="2Ø" ROWS="2" 
                ONBLUR="announce('textarea','blur')" 
                ONCHANGE="announce('textarea','change')" 
                ONFOCUS="announce('textarea','focus')" 
                ONSELECT="announce('textarea','select')"
                Sample Text
            </TEXTAREA>
            <BR>
            <SELECT NAME="select"
                ONBLUR="announce('select','blur')" 
                ONCHANGE="announce('select','change')" 
                ONFOCUS="announce('select','focus')">
                <OPTION>Option 1
                <OPTION>Option 2
                <OPTION>Option 3
            </SELECT>
        </FORM>
    </BODY>
</HTML>

A word of caution: You can accidentally force the browser into a loop that never ends by creating chains of events that repeat themselves. Pop-up windows, created using the alert, confirm, or prompt methods, can interact badly when created by a focus event handler. As an example, the following code pops up an alert window when the text field receives focus:

<HTML>
    <HEAD>
        <TITLE>Endless Loop</TITLE>
    </HEAD>
    <BODY>
        <FORM>
            <INPUT TYPE=TEXT NAME="text" SIZE=1Ø
                ONFOCUS="alert('Here we go again...')">
        </FORM>
    </BODY>
</HTML>

If the alert window happens to be displayed over the text field, we have a problem. Here's what happens:

  1. The text field receives focus.
  2. The onFocus event handler begins executing.
  3. The alert window pops up, acquiring focus from the text field.
  4. The user dismisses the alert window.
  5. The alert window is erased. Focus returns to the text field.
  6. The onFocus event handler begins executing.
  7. The alert window pops up….

And on and on it goes. To avoid this kind of endless loop, place messages in a text input field, on the status area of the window, or in another window or frame altogether.

Within the FORM element, another kind of event, the submit event, occurs when the user clicks on a submit button. Before there was JavaScript, clicking on the submit button sent the form data to a CGI process on a remote server. The CGI process would then process the data and send back a new page of data. With JavaScript, you can write an event handler for the submit event. Within the submit event handler, you can do whatever you like. Most of the input field contents are accessible to your JavaScript code (password fields are the exception); you can modify the data and you can decide not to send it out at all. You can create a document and display it in another frame or window. And you can still send it to a CGI process.

In addition to form and field event handlers, you can write event handlers to be executed when the pointing device moves over certain elements; such an event is called a mouseover event. You can also define event handlers that are executed when the document is loaded (a load event) and when the document is exited (an unload event).

Documents with memory

Through the use of a feature called a cookie, documents can share information with each other. Cookies are small data objects that reside on the user's machine. You can write JavaScript code to create, modify, and delete cookies.

The power of cookies is that they offer persistence. When the document that created or modified a cookie is no longer loaded, the data in the cookie is still there. Other documents that know about the cookie can access and modify its data, so the data can be shared between documents.

One potential use for cookies is in online catalogs. A store with an extensive inventory would not want to put its entire catalog in a single document. Instead, they would probably break up the catalog into manageable pieces, with each separate document focusing on a particular class of merchandise.

The user of such an online catalog could then select items from several pages. Each page could record the user's selection in a cookie. When the user was finally ready to send in the order, the cookie would be read back into a form for the user to verify. The entire list, containing items from several different documents, would then be submitted to the store.

Using the ability to write frame contents on the fly, you can also use cookies to remember things about the user and to tailor the contents of your document's frames to that user. An example might be a personalized greeting, combined with an indication of how long it has been since the user last loaded the document.

You might want to display some information at the beginning of the day. Using a cookie, your document can remember whether it is being loaded for the first time that day (by a particular user) or a subsequent time. For example, on the first visit of the day you might load a document containing the day's weather forecast, which you probably would not want to see later that same day. You could display a favorite online cartoon; once you've seen that day's cartoon, there's no reason to look at it again and again.

Live documents

Live documents are Web pages that change as time passes. You can create timers in your code. When the timer counts down, a JavaScript expression is executed. You can do many things with timers, such as scroll messages on the screen or load a document when the timer counts down.

Scrolling Messages

You've probably seen those cute little messages that scroll along the status portion of the browser window. They're all done with timers. The basic concept is simple.

You start the message by appending it to some arbitrary number of spaces. (The example that follows uses 200.) The message, with its leading spaces, is then written to the window's status bar. A timer starts that, when timed out, starts the process over again, but with one less space than the previous iteration. When the number of spaces before the message becomes zero, the strategy changes: Instead of appending the message to a string of spaces, a substring of the message is displayed. With each iteration, the starting point of the substring moves one character to the right, making the message appear to move to the left. When the message has disappeared from view, the entire cycle usually starts over.

Here's an example of how to create a scrolling message:

<HTML>
    <HEAD>
        <TITLE>Scrolling Message</TITLE>
        <SCRIPT>
<!--
var winLength = 2ØØ; // guess at how many spaces wide the status bar is
var speed = 1ØØ; // number of milliseconds between updates
function scroll(count)
    {
    var msg = "Hi! This is my scrolling message in the status bar.";
    var out = " ";
    var cmd = "scroll(";

    if (count <= winLength && Ø < count)
        {
        var c = Ø;
        for (c = Ø ; c < count ; c++)
            {
            out += " ";
}
        out += msg;
        }
    else if (count <= Ø)
        {
        if (-count < msg.length)
            {
            out += msg.substring(-count,msg.length);
        }
        else
            {
            count = winLength + 1;
            }
        }
    window.status = out;
    count--;
    cmd += count + ")";
    window.setTimeout(cmd,speed);
    }
//-->
        </SCRIPT>
    </HEAD>
    <BODY ONLOAD="window.setTimeout('scroll(winLength)',speed);">
    </BODY>
</HTML>

Scrolling messages don't necessarily have to show up in the status area. You can create a form and place the message in a text field within that form.

Clocks

Clocks are really a variation on the scrolling message. They simply stay put and tell the time, like the clock on your VCR (except that it doesn't blink "12:00"-it actually displays the time of day). JavaScript understands dates and times, and creating a simple clock display is quite easy, as you can see from this code and Figure 2.4:

Figure 2.4 : A simple clock on the status bar.

    <HEAD>
        <TITLE>Clock</TITLE>
        <SCRIPT>
<!--
function updateTime()
    {
    var now = new Date();
    var time = "" + now.getHours() + ":";
    var minute = now.getMinutes();
    if (minute < 1Ø)
        {
        time += "Ø";
        }
    time += minute + ":";
    var second = now.getSeconds();
    if (second < 1Ø)
        {
        time += "Ø";
        }
    time += second;
    window.status = time;
    window.setTimeout("updateTime()",1ØØØ);
    }
//-->
        </SCRIPT>
    </HEAD>
    <BODY ONLOAD="window.setTimeout('updateTime()',1ØØØ);">
    </BODY>
</HTML>

This code gets the current time by creating a new Date object. It extracts the hours, minutes, and seconds and displays them on the status bar. In the case of the minutes and seconds, it also checks whether either value is a single digit. If one of them is, it adds the leading zero (a time of five after twelve would look odd displayed as "12:5:0"). After the time is displayed, a new timer is created that will time out in exactly 1,000 milliseconds. When the timer times out, it displays the time and sets up another timer. And on and on it goes, like sand through an hourglass.

Countdown Timers

Another variation on the theme of timers is a countdown timer-a timer that counts backward. You could use such a timer to let the user know that something is about to happen, and when. Again, it is easy to create countdown timers in JavaScript, as shown here:

<HTML>
    <HEAD>
        <TITLE>Count Down</TITLE>
        <SCRIPT>
<!--
function countDown(tick)

    {
    if (tick == Ø)
        {
        window.status = "We have liftoff...";
        return;
        }
    var time = "T minus ";
    var minute = Math.floor(tick / 6Ø);
    if (minute < 1Ø)
        {
        time += "Ø";
        }
    time += minute + ":";
    var second = tick % 6Ø;
    if (second < 1Ø)
        {
        time += "Ø";
        }
    time += second;
    window.status = time;
    --tick;
    var command = "countDown(" + tick + ")";
    window.setTimeout(command,1ØØØ);
    }
//-->
        </SCRIPT>
    </HEAD>
    <BODY ONLOAD="window.setTimeout('countDown(12Ø)',1ØØØ);">
    </BODY>
</HTML>

Here an integer holds the time in seconds. The time is divided by 60 to get the minutes (Math.floor() is used to make sure the quotient is an integer) and the modulus operator is used to get the seconds. The minutes and seconds are displayed in the status bar. At the end of the timer code, a new time-out is created that repeats the code with one less second, one second later. When the seconds get to zero, the status bar is changed and no further time-outs are created.

Self-Updating Documents

Finally, a document can update itself. For example, every five minutes a brokerage house might create a GIF image that displays a graph of the rise and fall of the Dow Jones during a five-minute span. You can create a document that includes the GIF file as an inline image, and the document can update itself every five minutes. This document calls history.go(0) every 300 seconds (five minutes). Recall that history.go(0) acts like a press of the reload button.

<HTML>
    <HEAD>
        <TITLE>The Dow Jones</TITLE>
    </HEAD>
    <BODY>
        <IMG SRC="http://www.mythical_brokerage_house.com/DJ.GIF" 
            ALT="Picture it..." HEIGHT="5ØØ" WIDTH="5ØØ">
    </BODY ONLOAD="window.setTimeout('history.go(Ø)',3ØØØØØ)">
</HTML>