Now that you have learned the basics of JavaScript and how to work with forms, you are ready to look at another advanced feature of JavaScript: frames.
Frames provide the ability to divide a document window into distinct sections, each of which contains different HTML files and that can also be manipulated using JavaScript.
Besides the capability to manipulate frames, JavaScript also provides the document object which provides properties and methods for dealing with anchors, links and colors, and the window objectthe top level object of a web document window.
In this chapter we cover these topics:
Frames are one of the most widely used new features of Navigator 2.0.
Using a few simple extensions to the HTML standard, Web authors are able to achieve sophisticated control over the layout of information in the web browser window by dividing the window into rectangular sections and loading separate HTML files into each
section of the window.
In addition, links in one frame can update another frame, and the result of processing form data in a CGI script on a server can be targeted at another frame.
Even without the addition of JavaScript, frames have enabled the addition of a type of interactivity that wasn't possible before using regular HTML. For instance, sites now feature fixed tool bars and permanent search forms such as the one in Figure
8.1.
Figure 8.1. Using frames, The Dataphile On-line in Hong Kong has permanent search forms at its site.
A page is divided into frames using the FRAMESET tag. The tag is used in the top-level document defining a window containing frames and is used to specify how to divide the document window.
The FRAMESET container tag takes several attributes. The two basic ones are ROWS and COLS. A FRAMESET tag takes either one of these or both to divide a document into a set of rows or columns. For instance,
<FRAMESET COLS="25,*,25">
would define three columns. The two outer columns would each be 25 pixels wide, and the middle column would take the remaining space depending on the size of the window. In this example the asterisk (*) represents the remaining available space after the space is allocated for the other frames.
In addition to specifying the size of frames in pixels, the size of columns and rows can be defined using percentages relative to the space available to the document:
<FRAMESET ROWS="35%,*">
This FRAMESET tag would divide the display into two rows. The top row would be 35 percent of the height of the display area, and the bottom row would fill the remaining space (using the asterisk again).
Inside a FRAMESET container, the FRAME tag is used to specify which files should be displayed in each frame. The URLs
of the fileswhich can be relative or absoluteshould be specified using the SRC attribute in the same way as the IMG tag is used to include images in an HTML document.
For example, the following creates a document with two rows.
<FRAMESET ROWS="35%,*"> <FRAME SRC="menu.html"> <FRAME SRC="welcome.html"> </FRAMESET>
The top is 35 percent of the available space, and the bottom takes up the remaining 65 percent. The file menu.html is loaded into the top frame, and the file welcome.html is displayed in the lower frame.
In addition to the SRC attribute, the FRAME tag can take several other attributes as outlined in Table 8.1.
Attribute |
Description |
SRC |
Specifies the URL of the HTML file to be displayed in the frame. |
NAME |
Specifies the name of the frame so that it can be referenced by HTML tags and JavaScript scripts. |
NORESIZE |
Specifies that the size of a frame is fixed and cannot be changed by the user. |
SCROLLING |
Specifies if scroll bars are available to the user. This can take a value of YES, NO, or AUTO. |
MARGINHEIGHT |
Specifies the vertical offset in pixels from the border of the frame. |
|
|
To illustrate these attributes, look at the earlier example. The user can resize the frames by dragging on the border between the frames. By adding NORESIZE to either of the frames, this is
prevented:
<FRAMESET ROWS="35%,*"> <FRAME SRC="menu.html" NORESIZE> <FRAME SRC="welcome.html"> </FRAMESET>
or
<FRAMESET ROWS="35%,*"> <FRAME SRC="menu.html"> <FRAME SRC="welcome.html" NORESIZE> </FRAMESET>
Typically, if a document fills more space than the frame it is assigned to, Navigator 2.0 will add scroll bars to the frame. If you don't want scroll bars to appear, regardless of the size of the
frame, you can use SCROLLING=NO to prevent them from being used:
<FRAMESET ROWS="35%,*"> <FRAME SRC="menu.html"> <FRAME SRC="welcome.html" SCROLLING=NO> </FRAMESET>
As you can see in Figure 8.2, by using SCROLLING=NO, no scroll bars appear in the lower frame, even though the graphic is larger than the frame.
Figure 8.2. Preventing scroll bars in a frame, even when the document is larger than the frame
Looking at examples of frames on the Web, it quickly becomes obvious that many sites have more complex layouts than simply dividing the window into rows or columns. For instance, in Figure 8.1 you
saw an example of a site which has rows and columns combined to produce a very complex layout.
This is achieved by nesting, or embedding, FRAMESET containers within each other. For instance, if you want to produce a document with three frames where you have two rows and the bottom row is
further divides in two columns (to produce three frames), you could use a structure like this:
<FRAMESET ROWS="30%,*"> <FRAME SRC="menu.html"> <FRAMESET COLS="50%,50%"> <FRAME SRC="welcome.html"> <FRAME SRC="pic.html" SCROLLING=AUTO> </FRAMESET> </FRAMESET>
A similar result can be achieved by using separate files. For instance, if the first file contains
<FRAMESET ROWS="30%,*"> <FRAME SRC="menu.html"> <FRAME SRC="bottom.html"> </FRAMESET>
and the file bottom.html contains
<FRAMESET COLS="50%,50%"> <FRAME SRC="welcome.html"> <FRAME SRC="pic.html" SCROLLING=AUTO> </FRAMESET>
then you would get the same result as the previous example where both FRAMESET containers appeared in the same file.
To get a better idea of how this works, you can look at the source code for The Dataphile On-line which you saw in Figure 8.1. The following source code in Listing 8.1 combines the nested framesets from multiple files into a single file:
Input
<FRAMESET ROWS="100,*"> <FRAMESET COLS="500,*"> <FRAME SRC="banner.htm" NORESIZE MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING="no"> <FRAMESET ROWS="30,*"> <FRAME SRC="constant.htm" NORESIZE MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING="no"> <FRAME SRC="menu.htm" NORESIZE MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING="auto"> </FRAMESET> </FRAMESET> <FRAMESET COLS="*,250"> <FRAMESET ROWS="*,50"> <FRAME SRC="welcome.htm" NAME="middle" SCROLLING="auto"> <FRAME SRC="search.htm" MARGINHEIGHT=2 MARGINWIDTH=2 SCROLLING="auto"> </FRAMESET> <FRAMESET ROWS="50,*"> <FRAME SRC="newshead.htm" SCROLLING="no" MARGINHEIGHT=0 MARGINWIDTH=0> <FRAME SRC="newstory.htm" SCROLLING="auto" MARGINGHEIGHT=2 MARGINWIDTH=2> </FRAMESET> </FRAMESET> </FRAMESET>
Analysis
You start by dividing the window into two rows. The top row is divided into two columns, and the right column is further divided into two rows. Likewise, the bottom row is divided into two columns. The left column is divided into two rows, as is the
right column.
End of Analysis
You may have noticed that the one problem with files containing FRAMESET containers is that they will go undisplayed on a non-Netscape browser because other browsers don't support this extension to
HTML.
This is addressed by the NOFRAMES container tag. Any HTML code contained between the NOFRAMES tags is ignored by the Navigator 2.0 browser but will be displayed by any other browser.
For instance,
<HTML> <HEAD> <TITLE>NOFRAMES Example</TITLE> </HEAD> <FRAMESET ATTRIBUTES> <FRAME SRC="filename"> <FRAME SRC="filename"> </FRAMESET> <NOFRAMES> HTML code for other browsers </NOFRAMES> </HTML>
could be used to produce output like Figure 8.3 in Navigator 2.0 but like Figure 8.4 in another browser.
Figure 8.3. Only Navigator 2.0 recognizes the FRAMESET tag.
Figure 8.4. Using the NOFRAMES tag provides an alternative page for users of other browsers.
In order to place (or target) the result of links or form submissions in specific frames, you can name frames using the NAME attribute of the FRAME tag. For instance
<FRAMESET COLS="50%,*"> <FRAME SRC="menu.html" NAME="menu"> <FRAME SRC="welcome.html" NAME="main"> </FRAMESET>
would create two named frames called menu and main. In the file menu.html, you could have hypertext references target the main frame using the TARGET attribute:
<A HREF="choice1.html" TARGET="main">
Likewise, the result of a form submission could be targeted the same way:
<FORM METHOD=POST ACTION="/cgi-bin/test.pl" TARGET="main">
The TARGET attribute can also be used in the BASE tag to set a global target for all links in a document. For
instance, if an HTML document has this BASE tag in its header
<BASE TARGET="main">
then all hypertext and results of form processing will appear in the FRAME named "main". This global targetting is over-ridden by using a TARGET attribute in an A tag or FORM tag in the body of the HTML document.
In addition to targeting named frames, there are several special terms which can be used in the TARGET attributes. These are outlined in Table 8.2.
Value |
Description |
_blank |
Causes a link to load in a new, unnamed window. |
_self |
Causes a link to load in the same window the anchor was clicked in. (This can be used to override a target specified in a BASE tag.) |
_parent |
Causes a link to load in the immediate FRAMESET parent. |
|
|
JavaScript provides the frames property of the window object for working with different frames from a script.
The frames property is an array of objects with an entry for each child frame in a parent frameset. The number of frames is provided by the length property.
For instance, in a given window or frameset with two frames, you could reference the frames as parent.frames[0] and parent.frames[1] and the index of the last frame as parent.frames.length.
Using the frames array, you can access the functions and variables in another frame, as well as objects, such as forms and links contained in another frame. This is useful when building an
application that spans multiple frames but must be able to communicate between the frames.
For example, if you have two frames, you could create a form in the first frame to provide the user with a field to enter an expression. Then you could display the results in a form in the other frame.
This cross-frame communication is achieved by referencing the document object's forms[] array in the second frame with parent.frames[1].document.forms[0]. In Listing 8.3 you build a simple calculator to evaluate expressions entered by users and use
frames to display the output.
<!-- HTML CODE FOR PARENT FRAMESET (this is a separate file) --> <HTML> <HEAD> <TITLE>Listing 8.3</TITLE> </HEAD> <FRAMESET COLS="50%,*"> <FRAME SRC="input.html"> <FRAME SRC="output.html"> </FRAMESET> </HTML> <!-- HTML FOR INPUT FRAME (this is a separate file called input.html--> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS function update(field) { var result = field.value; var output = "" + result + " = " + eval(result); parent.frames[1].document.forms[0].result.value = output; } // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </HEAD> <BODY> <FORM METHOD=POST> <INPUT TYPE=text NAME="input" onChange="update(this);"> </FORM> </BODY> </HTML> <HTML> <!-- HTML FOR OUTPUT FRAME (this is a separate file called output.html)--> <BODY> <FORM METHOD=POST> <TEXTAREA NAME=result ROWS=2 COLS=20 WRAP=SOFT></TEXTAREA> </FORM> </BODY> </HTML>
In this example, it is important to note two things in the update() function. First, the eval() function used to evaluate the expression provided by the user doesn't work properly on the Windows 3.11
version of Navigator 2. Second, when you evaluate the expression and store the result in the variable output
var output = "" + result + " = " + eval(result);
you start the expression with "" to ensure a string value is assigned to the variable output.
In addition to specifying frames using the frames array, if you name the frames, you can specify certain frames using the form parent.framename. In the example you just saw, if you name the frames input and output, you could rewrite the update()
function:
function update(field) { var result = field.value; var output = "" + result + " = " + eval(result); parent.output.form[0].result.value = output; }
The frameset in this example would look like
<FRAMESET COLS="50%,*"> <FRAME SRC="input.html" NAME="input"> <FRAME SRC="output.html" NAME="output"> </FRAMESET>
<!-- HTML FOR INPUT FRAME (this is a separate file called input.html--> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS function update(field) { var result = field.value; var output = "" + result + " = " + eval(result); parent.output.document.outputForm.result.value = output; } // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </HEAD> <BODY> <FORM METHOD=POST NAME="inputForm"> <INPUT TYPE=text NAME="input" onChange="update(this);"> </FORM> </BODY> </HTML> <HTML> <!-- HTML FOR OUTPUT FRAME (this is a separate file called output.html)--> <BODY> <FORM METHOD=POST NAME="outputForm"> <TEXTAREA NAME=result ROWS=2 COLS=20 WRAP=SOFT></TEXTAREA> </FORM> </BODY> </HTML>
Notice, then, how the output field can be referred to with parent.output.document.outputForm.result.
With nested frames, cross-frame communication get a little bit more complicated.
When building nested framesets, it is possible to use sub-documents for each frameset. When you do this, the parent will only refer back to the document containing the parent frameset
and not the top-level frameset.
For example, referring to the previous expression evaluation example, if you want to divide the display into four equal quarters (as shown in Figure 8.5) and then use only two of them, you would have to change the FRAMESET to be something like this:
<FRAMESET ROWS="50%,*"> <FRAME SRC="top.html"> <FRAME SRC="bottom.html"> </FRAMESET>
Where top.html and bottom.html contain further nested framesets:
<!-- HTML FOR top.html --> <FRAMESET COLS="50%,*"> <FRAME SRC="input.html" NAME="input"> <FRAME SRC="logo.html"> </FRAMESET> <!-- HTML FOR bottom.html --> <FRAMESET COLS="50%,*"> <FRAME SRC="about.html"> <FRAME SRC="output.html" NAME="output"> </FRAMESET>
Figure 8.5. Using nested frameset produces complex screen layouts.
If input.html and output.html are still the files where the work is being done (logo.html and about.html are cosmetic), then you can't use the update() function you were using, because parent.frame[1] in the script will be referring to the frame
containing logo.htmlthe parent of the input frame is the first nested frameset. You want to be referencing the frame containing output.html, which is in the second nested frameset. To reference this document, you need to go up two parent levels and
then down two frames to reach output.html:
parent.parent.frame[1].frame[1]
With the named frame, this would become parent.parent.frame[1].output.
In addition to referring to variables and objects in other frames, the same technique can be used to invoke functions in other frames. For instance, you could add a function to output.html to handle displaying the results in the appropriate text field.
Then, in input.html you could simply call the function and pass it the value of the variable output:
<!-- HTML FOR INPUT FRAME (this is a separate file called input.html--> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS function update(field) { var result = field.value; var output = "" + result + " = " + eval(result); parent.output.displayResult(output); } // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </HEAD> <BODY> <FORM METHOD=POST NAME="inputForm"> <INPUT TYPE=text NAME="input" onChange="update(this);"> </FORM> </BODY> </HTML> <HTML> <!-- HTML FOR OUTPUT FRAME (this is a separate file called output.html)--> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS function displayResult(output) { document.ouputForm.result.value = output; } // STOP HIDING --> </SCRIPT> </HEAD> <BODY> <FORM METHOD=POST NAME="outputForm"> <TEXTAREA NAME=result ROWS=2 COLS=20 WRAP=SOFT></TEXTAREA> </FORM> </BODY> </HTML>
Now that you know how to work with frames, you are going to produce a testing tool that teachers can use to easily produce a test in any given subject.
To do this, you will use nested framesets. The top-level frameset will produce three rows: one for the title, one for the work area, and one for a level selector.
The middle row, the work area, will be split into two equal columns. The left side will contain a form for the student to enter his answer as well as a field to display the current score. The right column will be used to display the questions and the
result of a student's answer.
For these purposes, you only need to look at the source code for the student entry form and the level selection tool in the bottom frame. You will use Bill Dortch's hIdaho Frameset to make working with the nested framesets easier.
The frameset is defined by two files: the top-level test.htm (Listing 8.4) and work.htm (Listing 8.5) which defines the workspace in the middle row. work.htm contains the nested frameset referred to in test.htm (<FRAME SRC="work.htm"
NAME="work">):
Input
<!-- FRAMESET FROM test.htm --> <FRAMESET ROWS="20%,*,20%"> <FRAME SRC="title.htm"> <FRAME SRC="work.htm" NAME="work"> <FRAME SRC="level.htm" NAME="level"> </FRAMESET>
Input
<!-- FRAMESET FROM work.htm --> <FRAMESET COLS="50%,*"> <FRAME SRC="form.htm" NAME="form"> <FRAME SRC="output.htm" NAME="output"> </FRAMESET>
Both test.htm and work.htm would include the source code of the hIdaho Frameset so that the programs can easily call functions in other frames. In the file test.htm, amTopFrameset should be set to true with the statement amTopFrameset = true.
All of the functions and information is kept in the file form.htm (Listing 8.6). form.htm is one of the frames in the nested frameset.
Input
<!-- SOURCE CODE OF form.htm --> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS var currentLevel=1; var currentQuestion=1; var toOutput = ""; // DEFINE LEVEL ONE q1 = new question("1 + 3",4); q2 = new question("4 + 5",9); q3 = new question("5 - 4",1); q4 = new question("7 + 3",10); q5 = new question("4 + 4",8); q6 = new question("3 - 3",0); q7 = new question("9 - 5",4); q8 = new question("8 + 1",9); q9 = new question("5 - 3",2); q10 = new question("8 - 3",5); levelOne = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE LEVEL TWO q1 = new question("15 + 23",38); q2 = new question("65 - 32",33); q3 = new question("99 + 45",134); q4 = new question("34 - 57",-23); q5 = new question("-34 - 57",-91); q6 = new question("23 + 77",100); q7 = new question("64 + 32",96); q8 = new question("64 - 32",32); q9 = new question("12 + 34",46); q10 = new question("77 + 77",154); levelTwo = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE LEVEL THREE q1 = new question("10 * 7",70); q2 = new question("15 / 3",5); q3 = new question("34 * 3",102); q4 = new question("33 / 2",16.5); q5 = new question("100 / 4",25); q6 = new question("99 / 6",16.5); q7 = new question("32 * 3",96); q8 = new question("48 / 4",12); q9 = new question("31 * 0",0); q10 = new question("45 / 1",45); levelThree = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE TEST test = new newTest(levelOne,levelTwo,levelThree); function newTest(levelOne,levelTwo,levelThree) { this[1] = levelOne; this[2] = levelTwo; this[3] = levelThree; } function level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10) { this[1] = q1; this[2] = q2; this[3] = q3; this[4] = q4; this[5] = q5; this[6] = q6; this[7] = q7; this[8] = q8; this[9] = q9; this[10] = q10; } function question(question,answer) { this.question = question; this.answer = answer; } parent.Register(self.name,"startTest"); function startTest(newLevel) { currentLevel=newLevel; currentQuestion=1; document.forms[0].answer.value=""; document.forms[0].score.value=0; displayQuestion(); } function displayQuestion() { ask = test[currentLevel][currentQuestion].question; answer = test[currentLevel][currentQuestion].answer; toOutput = "" + currentQuestion + ". What is " + ask + "?"; document.forms[0].answer.value = ""; window.open("display.htm","output"); } parent.Register(self.name,"output"); function output() { return toOutput; } function checkAnswer(form) { answer = form.answer.value; if (answer == "" || answer == null) { alert("Please enter an answer."); return; } correctAnswer = test[currentLevel][currentQuestion].answer; ask = test[currentLevel][currentQuestion].question; score = form.score.value; if (eval(answer) == correctAnswer) { toOutput = "Correct!"; score ++; form.score.value = score; } else { toOutput = "Sorry! " + ask + " is " + correctAnswer + "."; } window.open("display.htm","output"); if (currentQuestion < 10) { currentQuestion ++; setTimeout("displayQuestion()",3000); } else { toOutput = "You're Done!<BR>You're score is " + score + " out of 10."; setTimeout("window.open('display.htm','output')",3000); form.answer.value=""; form.score.value="0"; } } function welcome() { toOutput = "Welcome!"; window.open("display.htm","output"); } // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </HEAD> <BODY BGCOLOR="#FFFFFF" TEXT="#0000FF" onLoad="welcome();"> <FORM METHOD=POST> <CENTER> <STRONG>Type You're Answer Here:</STRONG><BR> <INPUT TYPE=text NAME=answer SIZE=30><P> <INPUT TYPE=button NAME=done VALUE="Check Answer" onClick="checkAnswer(this.form);"><P> Correct Answers So Far:<BR> <INPUT TYPE=text NAME=score VALUE="0" SIZE=10> </FORM> </BODY> </HTML>
The file level.htm (Listing 8.7) provides users with three buttons to select different levels. level.htm is the bottom frame in the parent frameset:
Input
<!-- SOURCE CODE OF level.htm --> <HTML> <BODY BGCOLOR="#000000" TEXT="#FFFFFF"> <CENTER> <STRONG> Select a level here: <FORM METHOD=POST> <INPUT TYPE=button NAME="one" VALUE="Level One" onClick="parent.Exec('startTest',1);"> <INPUT TYPE=button NAME="two" VALUE="Level Two" onClick="parent.Exec('startTest',2);"> <INPUT TYPE=button NAME="three" VALUE="Level Three" onClick="parent.Exec('startTest',3);"> </FORM> </STRONG> </CENTER> </BODY> </HTML>
All display in the frame named output is done by reloading the file display.htm (Listing 8.8):
Input
<!-- SOURCE CODE OF display.htm --> <HTML> <BODY BGCOLOR="#0000FF" TEXT="#FFFFFF"> <H1> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS document.write(parent.Exec("output")); // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </H1> </BODY> </HTML>
Finally, title.htm (Listing 8.9) contains the information displayed in the top frame of the parent frameset:
Input
<!-- SOURCE CODE OF title.htm --> <HTML> <BODY BGCOLOR="#000000" TEXT="#00FFFF"> <CENTER> <H1> <STRONG> The Math Test </STRONG> </H1> </CENTER> </BODY> </HTML>
Output
The final product would look something like Figure 8.6.
Figure 8.6. Using nested framesets to produce a multi-level math test.
End of Output
Analysis
As you can see in the source code listings, the file form.htm (Listing 8.6) is the centerpiece of the entire application. It is in this file that all the work of checking answers, displaying questions and results, and resetting the test is done.
Let's look at the document section by section.
var currentLevel=1; var currentQuestion=1; var toOutput = "";
These are the key global variables in the script which are used to keep track of the current level being tested, the current question being tested and what should next be displayed in the output
frame.
Next the questions and answers for the three levels are defined:
// DEFINE LEVEL ONE q1 = new question("1 + 3",4); q2 = new question("4 + 5",9); q3 = new question("5 - 4",1); q4 = new question("7 + 3",10); q5 = new question("4 + 4",8); q6 = new question("3 - 3",0); q7 = new question("9 - 5",4); q8 = new question("8 + 1",9); q9 = new question("5 - 3",2); q10 = new question("8 - 3",5); levelOne = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE LEVEL TWO q1 = new question("15 + 23",38); q2 = new question("65 - 32",33); q3 = new question("99 + 45",134); q4 = new question("34 - 57",-23); q5 = new question("-34 - 57",-91); q6 = new question("23 + 77",100); q7 = new question("64 + 32",96); q8 = new question("64 - 32",32); q9 = new question("12 + 34",46); q10 = new question("77 + 77",154); levelTwo = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE LEVEL THREE q1 = new question("10 * 7",70); q2 = new question("15 / 3",5); q3 = new question("34 * 3",102); q4 = new question("33 / 2",16.5); q5 = new question("100 / 4",25); q6 = new question("99 / 6",16.5); q7 = new question("32 * 3",96); q8 = new question("48 / 4",12); q9 = new question("31 * 0",0); q10 = new question("45 / 1",45); levelThree = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE TEST test = new newTest(levelOne,levelTwo,levelThree); function newTest(levelOne,levelTwo,levelThree) { this[1] = levelOne; this[2] = levelTwo; this[3] = levelThree; } function level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10) { this[1] = q1; this[2] = q2; this[3] = q3; this[4] = q4; this[5] = q5; this[6] = q6; this[7] = q7; this[8] = q8; this[9] = q9; this[10] = q10; } function question(question,answer) { this.question = question; this.answer = answer; }
The test consists of three levels with 10 questions each. You store all this information in a series of objects. The question object has two properties: question and answer. The level object consists of 10 questions as properties. The test object has
three propertieseach level of the test.
Notice that you only name the properties in the question object. This is because you will want to access the level and particular question using numeric indexes
rather than names. For instance, you could refer to level one as test[1] and question three of level one as test[1][3] (notice the use of two indexes next to each other) and the answer to question 3 of level one as test[1][3].answer.
The structure described here is known as a nested object construct. In this example, test is an object. It has a set of properties (all objects in this case)
which can be referred to by their numerical index. So, test[1] is a property of test and an object in its own right. Because test[1] is an object, it can also have properties, in this case, referred to by numerical index. So, test[1][3] is a property of
test[1] and, again, this property is itself an object. Once again, as an object, test[1][3] can have propertiesin this case, answer, referenced by name as test[1][3].answer.
The next function in Listing 8.6 is the startTest() function:
parent.Register(self.name,"startTest"); function startTest(newLevel) { currentLevel=newLevel; currentQuestion=1; document.forms[0].answer.value=""; document.forms[0].score.value=0; displayQuestion(); }
The startTest() function is one of the functions you register with the parent.Register() function from the hIdaho Frameset. You do this because you want to be able to call the function from the level frame.
The function accepts a single argumentthe level of the new test and sets currentLevel and currentQuestion appropriately as well as clearing the fields of the form. Then the function calls displayQuestion() to start the test.
function displayQuestion() { ask = test[currentLevel][currentQuestion].question; answer = test[currentLevel][currentQuestion].answer; toOutput = "" + currentQuestion + ". What is " + ask + "?"; document.forms[0].answer.value = ""; window.open("display.htm","output"); }
This function is used to display each successive question. It takes no arguments but gets its information from the global variables currentLevel and currentQuestion. In this way, it can get the current the text of the question by using
test[currentLevel][currentQuestion].question.
The function then stores the complete output in toOutput and uses the method window.open() to open display.htm in the frame named output. As you will learn later in the section on the window
object, open() can be used to open files in named frames and windows.
parent.Register(self.name,"output"); function output() { return toOutput; }
Like the startTest() function, you register the output() function with parent.Register(). The function simply returns the value of toOutput and is used to update the display in the output frame as you will see when you look at the source code of the
file display.htm.
function checkAnswer(form) { answer = form.answer.value; if (answer == "" || answer == null) { alert("Please enter an answer."); return; } correctAnswer = test[currentLevel][currentQuestion].answer; ask = test[currentLevel][currentQuestion].question; score = form.score.value; if (eval(answer) == correctAnswer) { toOutput = "Correct!"; score ++; form.score.value = score; } else { toOutput = "Sorry! " + ask + " is " + correctAnswer + "."; } window.open("display.htm","output"); if (currentQuestion < 10) { currentQuestion ++; setTimeout("displayQuestion()",3000); } else { toOutput = "You're Done!<BR>You're score is " + score + " out of 10."; setTimeout("window.open('display.htm','output')",3000); form.answer.value=""; form.score.value="0"; } }
checkAnswer() is where the bulk of the work is done in the script.
Because checkAnswer() is called from the form, it takes a single argument for the form object. The function compares the student's answer stored in the field form.answer with the correct answer
taken from the test object.
If the student answered correctly, an appropriate message is stored in toOutput, and the score is incremented and displayed. If the answer is wrong, an appropriate message is stored in toOutput, but the score is left untouched. Once the answer is
checked, the message is displayed using window.open() to open display.htm in the output frame.
The function then uses the condition currentQuestion < 10 to check if the question just answered is the last question in the test. If it is not the last question, then the currentQuestion variable is increased by one to go to the next question and
setTimeout() is used to wait three seconds (3000 milliseconds) before displaying the new question with displayQuestion().
Otherwise, the function stores the results of the test in toOutput, displays them with a similar three second delay using setTimeout() and then clears the answer and score fields of the form.
function welcome() { toOutput = "Welcome!"; window.open("display.htm","output"); }
The function welcome() stores a welcome message in toOutput and then displays it by loading display.htm into the output frame.
<BODY BGCOLOR="#FFFFFF" TEXT="#0000FF" onLoad="welcome();">
After the document finishes loading, the welcome() function is called using the onLoad event handler.
<FORM METHOD=POST> <CENTER> <STRONG>Type You're Answer Here:</STRONG><BR> <INPUT TYPE=text NAME=answer SIZE=30><P> <INPUT TYPE=button NAME=done VALUE="Check Answer" onClick="checkAnswer(this.form);"><P> Correct Answers So Far:<BR> <INPUT TYPE=text NAME=score VALUE="0" SIZE=10 onFocus="this.blur();"> </FORM>
This form is where most user interaction takes placewith the exception of the level frame. It has a text entry field named answer where users type their answers to each question, a button they click on to check their answers, and a text field to
display the current score.
Only two event handlers are used: onClick="checkAnswer(this.form);" to check the users' answer and onFocus="this.blur;" to ensure users don't try to cheat by changing their own scores.
The file level.htm (Listing 8.7) contains a simple three button form to start a new test at any of the three levels:
<FORM METHOD=POST> <INPUT TYPE=button NAME="one" VALUE="Level One" onClick="parent.Exec('startTest',1);"> <INPUT TYPE=button NAME="two" VALUE="Level Two" onClick="parent.Exec('startTest',2);"> <INPUT TYPE=button NAME="three" VALUE="Level Three" onClick="parent.Exec('startTest',3);"> </FORM>
Each button has a similar onClick event handler which uses parent.Exec() to call the startTest() function from the form frame and pass it a single integer argument for the level.
The only other file involving JavaScript scripting is display.htm which sets up the body of the document and then uses document.write() to display the result returned by output() from the form frame. The function is called using parent.Exec(). In this
way, every time the main script in form.htm reloads display.htm, the current value of toOutput is returned by output() and displayed as the body text for display.htm.
In any given window or frame, one of the primary objects is the document object. The document object provides the properties and methods to work with numerous aspects
of the current document, including information about anchors, forms, links, the title, the current location and URL, and the current colors.
You already have been introduced to some of the features of the document object in the form of the document.write() and
document.writeln() methods, as well as the form object and all of its properties and methods.
The document object is defined when the BODY tag is evaluated in an HTML page and the object remains in existence as long as the page is
loaded. Because many of the properties of the document object are reflections of attributes of the BODY tag, it is important to have a complete grasp of all the attributes available in the BODY tag in Navigator 2.0.
The BODY tag defines the main body of an HTML document. Its attributes enable the HTML author to define colors for text and links, as well as background colors or patterns for the document.
In addition, as you have already learned, there are two event handlers, onLoad and onUnload, that can be used in the BODY tag.
The following is a list of available attributes for the BODY tag:
Table 8.3 outlines the properties of the document object.
Property |
Description |
alinkColor |
The RGB value for the color of activated links expressed as a hexadecimal triplet. |
anchors |
Array of objects corresponding to each named anchor in a document. |
bgColor |
The RGB value of the background color as a hexadecimal triplet. |
cookie |
Contains the value of the cookies for the current document. Cookies are discussed in depth in Chapter 9. |
fgColor |
The RGB value of the foreground color as a hexadecimal triplet. |
forms |
Array of objects corresponding to each form in a document. |
lastModified |
A string containing the last date the document was modified. |
linkColor |
The RGB value of links as a hexadecimal triplet. |
links |
An array of objects corresponding to each link in a document. |
location |
An object defining the full URL of the document. |
referrer |
Contains the URL of the document which called the current document. |
title |
A string containing the title of the document |
|
|
Some of these properties are obvious. For instance, in a document containing the tag
<BODY BGCOLOR="#FFFFFF" FGCOLOR="#000000" LINK="#0000FF">
document.bgColor would have a value of "#FFFFFF", document.fgColor would equal "#000000" and document.linkColor would be "#0000FF".
In addition, you have already learned to use the forms array.
The anchors and links arrays, along with the location object, however, deserve a closer look.
While the <A> tag in HTML is usually used to define hypertext links to other documents, it can also be used to define named anchors
in a document, so that links within a document can jump to other places in the document.
For instance, in the HTML page
<HTML> <HEAD> <TITLE>Anchors Example</TITLE> </HEAD> <BODY> <A NAME="one">Anchor one is here HTML Code <A NAME="two">Anchor two is here More HTML Code <A HREF="#one">Go back to Anchor One</A><BR> <A HREF="#two">GO back to Anchor Two</A> </BODY> </HTML>
two anchors are defined using <A NAME="anchorName"> (<A NAME="one"> and <A NAME="two">)and links to those anchors are created using <A HREF="#anchorName"> (<A
HREF="#one"> and <A HREF="#two">).
JavaScript provides the anchors array as a means to access information and methods related to anchors in the current document. Each element in the array is an anchor object, and like all arrays, the array has a length property.
The order of anchors in the array follows the order of appearance of the anchors in the HTML document.
Therefore, in the example, document.anchors.length would have a value of 1 (since the anchors array, like the forms array and frames array starts with a zero index) and document.anchors[0] would refer to the anchor named one.
Just as the anchors array provides a sequential list of all the anchors in a document, the links array offers an entry for each hypertext link defined by <A HREF="URL"> in
an HTML document.
Also like the anchors array, each element in the links array is a link object, and the array has a length property.
The link object has a single property, target, which contains a string with the name of the window or frame indicated in the link's TARGET attribute in the HTML file. For instance, in the
following simple HTML file, document.links[0].target would have a value of "test":
<HTML> <HEAD> <TITLE>Links Example</TITLE> </HEAD> <BODY> <A HREF="URL" TARGET="test">Just Testing</A> </BODY> </HTML>
The location object provides several properties and methods for working with the location of the current object.
Table 8.4 outlines these properties and methods.
Name |
Description |
hash |
The anchor name (the text following a # symbol in an HREF attribute) |
host |
The hostname and port of the URL |
hostname |
The hostname of the URL |
href |
The entire URL as a string |
pathname |
The file path (the portion of the URL following the third slash) |
port |
The port number of the URL (if there is no port number, then the empty string) |
protocol |
The protocol part of the URL (such as http:, gopher: or ftp:including the colon) |
search |
The form data or query following the question mark (?) in the URL |
assign() |
Sets location.href |
|
|
In addition to the write() and writeln() methods which you have been using throughout the book, the document object provides three other methods: open(), close(), and clear().
The open() method is used to open the document window for writing a MIME type. It takes a single argument: the MIME type (such as text/html). You can also use the window.open() method to open a
window or frame for writing a document, as you will see in the section on the window object.
By comparison, close() closes the document window for writing, and the clear() method clears the current document window. Document output is not actually rendered (displayed) until document.close() is called.
For this example, you are going to build a simple utility to demonstrate what different combinations of text, link, and background colors
look like.
The application will use two frames: the top frame contains five text entry fields for the background color, text color, link color, active link color, and followed link color, plus a button to enable users to test their color combinations.
When users press the button, the script loads a simple document, using the specified colors into the lower frame. The users should be able to specify colors by hexadecimal triplets or by name.
To do this, you don't need to use the hIdaho Frameset you used in Listings 8.4 through 8.9, because you won't be using nested framesets or making cross-frame function calls.
The parent frameset is defined as follows:
Input
<HTML> <HEAD> <TITLE>Example 8.2</TITLE> </HEAD> <FRAMESET ROWS="45%,*"> <FRAME SRC="pick.htm"> <FRAME SRC="blank.htm" NAME="output"> </FRAMESET> </HTML>
The source code for the file pick.htm, where all the processing occurs, is in Listing 8.11.
Input
<HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FORM OTHER BROWSERS function display(form) { doc = open("","output"); doc.document.write ('<BODY BGCOLOR="' + form.bg.value); doc.document.write ('" TEXT="' + form.fg.value); doc.document.write ('" LINK="' + form.link.value); doc.document.write ('" ALINK="' + form.alink.value); doc.document.write ('" VLINK="' + form.vlink.value); doc.document.writeln ('">'); doc.document.write("<H1>This is a test</H1>"); doc.document.write("You have selected these colors.<BR>"); doc.document.write('<A HREF="#">This is a test link</A>'); doc.document.write("</BODY>"); doc.document.close(); } // STOP HIDING SCRIPT --> </SCRIPT> </HEAD> <BODY> <CENTER> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS document.write('<H1>The Colour Picker</H1>'); document.write('<FORM METHOD=POST>'); document.write('Enter Colors:<BR>'); document.write('Background: <INPUT TYPE=text NAME="bg" VALUE="' + document.bgColor + '"> ... '); document.write('Text: <INPUT TYPE=text NAME="fg" VALUE="' + document.fgColor + '"><BR>'); document.write('Link: <INPUT TYPE=text NAME="link" VALUE ="' + document.linkColor + '"> ...'); document.write('Active Link: <INPUT TYPE=text NAME="alink" VALUE="' + document.alinkColor + '"><BR>'); document.write('Followed Link: <INPUT TYPE="text" NAME="vlink" VALUE ="' + document.vlinkColor + '"><BR>'); document.write('<INPUT TYPE=button VALUE="TEST" onClick="display(this.form);">'); document.write('</FORM>'); display(document.forms[0]); // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </CENTER> </BODY> </HTML>
Output
The program produces results like those in Figure 8.7.
Figure 8.7. With JavaScript, you can dynamically test color combinations.
End of Output
Analysis
As you can see in this example, all the work is being done in the top frame, which contains the document pick.htm.
The file has two main components: a JavaScript function and the body of the document which is almost entirely generated by another JavaScript script using the document.write() and document.writeln() methods.
The interface consists of a single form containing five fields for each of the color values, plus a button which calls the function display().
function display(form) { doc = open("","output"); doc.document.write ('<BODY BGCOLOR="' + form.bg.value); doc.document.write ('" TEXT="' + form.fg.value); doc.document.write ('" LINK="' + form.link.value); doc.document.write ('" ALINK="' + form.alink.value); doc.document.write ('" VLINK="' + form.vlink.value); doc.document.writeln ('">'); doc.document.write("<H1>This is a test</H1>"); doc.document.write("You have selected these colors.<BR>"); doc.document.write('<A HREF="#">This is a test link</A>'); doc.document.write("</BODY>"); doc.document.close(); }
The function is fairly simple: an empty document is opened in the output frame using the window.open() method, and the name doc is assigned for JavaScript to refer to
that window (frame).
The commands doc.document.write() and doc.document.writeln() can then be used to write HTML to the newly opened window. The values of the five form fields are then used to build a custom BODY tag which defines all the colors for the document. After the
text has been output, the method doc.document.close() is used to close the open document and finish displaying it in the frame.
With this single function, you can build a simple form in the body of the document. The form is built by a JavaScript script that assigns initial values to the five fields using properties of the document object to set the values to the current browser
defaults. Then the script calls display() so that an initial sample is displayed in the lower frame.
As with many programs, there is more than one way to achieve a desired effect. For instance, the display() function could be rewritten to change the colors dynamicallywithout rewriting the content of the frameby
using the color properties of the document object:
function display(form) { parent.output.document.bgColor = form.bg.value; parent.output.document.fgColor = form.fg.value; parent.output.document.linkClor = form.link.value; parent.output.document.alinkColor = form.alink.value; parent.output.document.vlinkColor = form.vlink.value; }
Then you simply can remove the call to display() in the body of the HTML document, make the content of the output frame a separate HTML document and load the sample document into the lower frame in the parent frameset.
As you learned in Chapter 1, "Where Does JavaScript Fit In?" when you were first introduced to the Navigator Object Hierarchy, the window object is the parent object of each loaded
document.
Because the window object is the parent object for loaded documents, you usually do not explicitly refer to the window object when referring to its properties or invoking its methods. For this
reason, window.alert() can be called by using alert().
Table 8.5 outlines the properties and methods of the window object. You have seen many of these including the frames array and the parent
object, as well as the alert(), confirm(), open(), prompt(), and setTimeout() methods.
Name |
Description |
frames |
Array of objects containing an entry for each child frame in a frameset document. |
parent |
The FRAMESET in a FRAMESET-FRAME relationship |
self |
The current windowuses this to distinguish between windows and forms of the same name. |
top |
The top-most parent window. |
status |
The value of the text displayed in the window's status bar. This can be used to display status messages to the user. |
defaultStatus |
The default value displayed in the status bar. |
alert() |
Display a message in a dialog box with an OK button. |
confirm() |
Display a message in a dialog box with OK and CANCEL buttons. This returns true when the user clicks on OK, false otherwise. |
close() |
Closes the current window. |
open() |
Opens a new window with a specified document or opens the document in the specified named window. |
prompt() |
Displays a message in a dialog box along with a text entry field. |
setTimeout() |
Sets a timer for a specified number of milliseconds and then evaluates an expression when the timer has finished counting. Program operation continues while the timer is counting down. |
|
|
Using the status barthe strip at the bottom of the Navigator window where you are told about the current status of document transfers and connections to remote sitescan be used by JavaScript programs to display
custom messages to the user.
This is primarily done using the onMouseOver event handler, which is invoked when the user points at a hypertext link. By setting the value of self.status to a string, you can assign a value to
the status bar (you could also use window.status or status here). In the program
<HTML> <HEAD> <TITLE>Status Example</TITLE> </HEAD> <BODY> <A HREF="home.html" onMouseOver="self.status='Go Home!'; return true;">Home</A> <A HREF="next.html" onMouseOver="self.status='Go to the next Page!'; return true;">Next</A> </BODY> </HTML>
two different messages are displayed when the user points the mouse at the links. This can be more informative than the URLs that Navigator normally displays when a user points at a link.
Using the open() and close() methods, you have control over what windows are open and which documents they contain.
The open() method is the more complex of the two. It takes two required arguments and an optional feature list in the following form:
open("URL", "windowName", "featureList");
Here the featureList is a comma-separated list containing any of the entries in Table 8.6.
Name |
Description |
toolbar |
Creates the standard toolbar |
location |
Creates the location entry field |
directories |
Creates the standard directory buttons |
status |
Creates the status bar |
menubar |
Creates the menu at the top of the window |
scrollbars |
Creates scroll bars when the document grows beyond the current window |
resizable |
Enables resizing of the window by the user |
width |
Specifies the window width in pixels |
|
|
For example, to open a document called new.html in a new window named newWindow and to make the window 200 pixels by 200 pixels with all window features available except resizable, you could use the command
window.open("new.html","newWindow","toolbar=yes,location=1,directories=yes,status=yes,menubar=1,scrollbars=yes,resizable=0,copyhistory=1,width=200,height=200");
which would produce a window like the one in Figure 8.8.
Figure 8.8. You control the size of new windows, as well as which elements to display.
It is interesting to note that you can open a window and then write HTML into that window using document.writeln() and document.write(). You saw an example of this in
Example 8.2.
For instance, the function newwindow() opens a new window and writes several lines of HTML into it.
function newwindow() { newWindow = open("","New_Window"); newWindow.document.write("<H1>Testing ...</H1>"); newWindow.document.writeln("1... 2... 3..."); newWindow.document.close(); }
The close() method is simpler to use:
window.close();
simply closes the current window.
You already saw an example of using setTimeout() in Bill Dortch's hIdaho Frameset earlier in this chapter where he suggests using a
setTimeout() call to make sure a function is registered before trying to call the function.
The setTimeout() method takes the form
ID=setTimeout("expression",milliseconds)
where expression is any string expression, including a call to a function, milliseconds is the number of millisecondsexpressed as an integerto wait before evaluating the expression, and ID is an identifier which can be
used to cancel the setTimeout() before the expression is evaluated.
clearTimeout() is passed a single argument: the identifier of the timeout setting to be canceled.
For instance, if you want to create a page that displays a welcome message to the user and then automatically goes to a new page five seconds later if the user hasn't clicked on the appropriate button, you could write a script like this:
Input
<HTML> <HEAD> <TITLE>Timeout Example</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS function go() { open("new.html","newWindow"); } // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </HEAD> <BODY onLoad="timeout = setTimeout('go()',5000);"> <IMG SRC="welcome.gif"> <H1>Click on the button or wait five seconds to continue ...</H1> <FORM METHOD=POST> <INPUT TYPE=button VALUE="Continue ..." onClick="clearTimeout(timeout); go();"> </FORM> </BODY> </HTML>
In this example, you produce a simple function to implement status bar help in any HTML document. The function can be called from any
event handler and will display a message in the status bar.
function help(message) { self.status = message; return true; }
With this function, you can then implement full on-line pointers and help systems. For instance, if you use this in the math test from Listing 8.4 through 8.9, you can add help messages with only slight modifications to both form.htm and level.htm.
Input
<!-- SOURCE CODE OF form.htm --> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS var currentLevel=1; var currentQuestion=1; var toOutput = ""; // DEFINE LEVEL ONE q1 = new question("1 + 3",4); q2 = new question("4 + 5",9); q3 = new question("5 - 4",1); q4 = new question("7 + 3",10); q5 = new question("4 + 4",8); q6 = new question("3 - 3",0); q7 = new question("9 - 5",4); q8 = new question("8 + 1",9); q9 = new question("5 - 3",2); q10 = new question("8 - 3",5); levelOne = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE LEVEL TWO q1 = new question("15 + 23",38); q2 = new question("65 - 32",33); q3 = new question("99 + 45",134); q4 = new question("34 - 57",-23); q5 = new question("-34 - 57",-91); q6 = new question("23 + 77",100); q7 = new question("64 + 32",96); q8 = new question("64 - 32",32); q9 = new question("12 + 34",46); q10 = new question("77 + 77",154); levelTwo = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE LEVEL THREE q1 = new question("10 * 7",70); q2 = new question("15 / 3",5); q3 = new question("34 * 3",102); q4 = new question("33 / 2",16.5); q5 = new question("100 / 4",25); q6 = new question("99 / 6",16.5); q7 = new question("32 * 3",96); q8 = new question("48 / 4",12); q9 = new question("31 * 0",0); q10 = new question("45 / 1",45); levelThree = new level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10); // DEFINE TEST test = new newTest(levelOne,levelTwo,levelThree); function newTest(levelOne,levelTwo,levelThree) { this[1] = levelOne; this[2] = levelTwo; this[3] = levelThree; } function level(q1,q2,q3,q4,q5,q6,q7,q8,q9,q10) { this[1] = q1; this[2] = q2; this[3] = q3; this[4] = q4; this[5] = q5; this[6] = q6; this[7] = q7; this[8] = q8; this[9] = q9; this[10] = q10; } function question(question,answer) { this.question = question; this.answer = answer; } parent.Register(self.name,"startTest"); function startTest(newLevel) { currentLevel=newLevel; currentQuestion=1; document.forms[0].answer.value=""; document.forms[0].score.value=0; displayQuestion(); } function displayQuestion() { ask = test[currentLevel][currentQuestion].question; answer = test[currentLevel][currentQuestion].answer; toOutput = "" + currentQuestion + ". What is " + ask + "?"; document.forms[0].answer.value = ""; window.open("display.htm","output"); } parent.Register(self.name,"output"); function output() { return toOutput; } function checkAnswer(form) { answer = form.answer.value; correctAnswer = test[currentLevel][currentQuestion].answer; ask = test[currentLevel][currentQuestion].question; score = form.score.value; if (eval(answer) == correctAnswer) { toOutput = "Correct!"; score ++; form.score.value = score; } else { toOutput = "Sorry! " + ask + " is " + correctAnswer + "."; } window.open("display.htm","output"); if (currentQuestion < 10) { currentQuestion ++; setTimeout("displayQuestion()",3000); } else { toOutput = "You're Done!<BR>You're score is " + score + " out of 10."; setTimeout("window.open('display.htm','output')",3000); form.answer.value=""; form.score.value="0"; } } function welcome() { toOutput = "Welcome!"; window.open("display.htm","output"); } parent.Register(self.name,"help"); function help(message) { self.status = message; return true; } // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </HEAD> <BODY BGCOLOR="#FFFFFF" TEXT="#0000FF" onLoad="welcome();"> <FORM METHOD=POST> <CENTER> <STRONG>Type You're Answer Here:</STRONG><BR> <INPUT TYPE=text NAME=answer SIZE=30 onFocus="help('Enter your answer here.');"><P> <A HREF="#" onClick="checkAnswer(document.forms[0]);"onMouseOver="return help('Click here to check your answer.');">Check Answer</A><P> <INPUT TYPE=text NAME=score VALUE="0" SIZE=10 onFocus="this.blur();"> </FORM> </BODY> </HTML>
Similarly, level.htm requires changes:
Input
<!-- SOURCE CODE OF level.htm --> <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- HIDE FROM OTHER BROWSERS function help(message) { self.status = message; return true; } // STOP HIDING FROM OTHER BROWSERS --> </SCRIPT> </HEAD> <BODY BGCOLOR="#000000" TEXT="#FFFFFF" LINK="#FFFFFF" ALINK="#FFFFFF" VLINK="#FFFFFF"> <CENTER> <STRONG> Select a level here:<BR> <A HREF="#" onClick="parent.Exec('startTest',1);"onMouseOver="return parent.Exec('help','Start test at level one.');">LEVEL ONE</A> <A HREF="#" onClick="parent.Exec('startTest',2);"onMouseOver="return parent.Exec('help','Start test at level two.');">LEVEL TWO</A> <A HREF="#" onClick="parent.Exec('startTest',3);"onMouseOver="return parent.Exec('help','Start test at level three.');">LEVEL THREE</A> </STRONG> </CENTER> </BODY> </HTML>
Output
These changes produce results like those in Figure 8.9.
Figure 8.9. Using onMouseOver and the status property to display help messages in the Navigator window's status bar.
End of Output
Analysis
In order to implement the interactive help in the math test, you have to make only minor changes to both HTML files.
In form.htm, you have added the help() function to the header and made two changes in the body of the document. You have added an onFocus event handler to the answer field. The event handler
calls help() to display a help message.
You have also changed the button to a hypertext link so that you can use the onMouseOver event handler to display another help message. There are several points to note in the following line:
<A HREF="#" onClick="checkAnswer(document.forms[0]);"onMouseOver="return help('Click here to check your answer.');">Check Answer</A>
First, in the call to checkAnswer(), you can't pass the argument this.form because the hypertext link is not a form element. For this reason, you use document.forms[0] to explicitly identify the form.
The second point to notice is that you have an empty anchor in the attribute HREF="#". When a user clicks on the link, only the onClick event handler executes, but because there is no
URL specified, the page doesn't change.
In level.htm, you make similar changes. You simply have added the help function to the file's header and changed the three form buttons to three hypertext links with appropriate onMouseOver event handlers.
The various HTML color attributes and tags (BGCOLOR, FGCOLOR, VLINKCOLOR, ALINKCOLOR, LINKCOLOR, FONT COLOR) and their related JavaScript methods (bgColor(), fgColor(), vlinkColor(), alinkColor(), linkColor(), fontColor())
can take both RGB triplets and selected color names as their values.
Table 8.7 is a list of select Netscape color words and their corresponding RGB triplets. The complete list of color words can be found in the JavaScript document at the Netscape Web site (see
Appendix A).
Color Name |
RGB Triplet |
antiquewhite |
FA EB D7 |
aqua |
00 FF FF |
azure |
F0 FF FF |
beige |
F5 F5 DC |
black |
00 00 00 |
blue |
00 00 FF |
brown |
A5 2A 2A |
chartreuse |
7F FF 00 |
cornflowerblue |
64 95 ED |
crimson |
DC 14 3C |
darkcyan |
00 8B 8B |
darkgray |
A9 A9 A9 |
darkgreen |
00 64 00 |
darkpink |
FF 14 93 |
firebrick |
B2 22 22 |
floralwhite |
FF FA F0 |
fuchsia |
FF 00 FF |
gold |
FF D7 00 |
greenyellow |
AD FF 2F |
hotpink |
FF 69 B4 |
indigo |
4B 00 82 |
ivory |
FF FF F0 |
lemonchiffon |
FF FA CD |
lightblue |
AD D8 E6 |
lightyellow |
FF FF E0 |
magenta |
FF 00 FF |
maroon |
80 00 00 |
mediumpurple |
93 70 DB |
mediumturquoise |
48 D1 CC |
moccasin |
FF E4 B5 |
navy |
00 00 80 |
orange |
FF A5 00 |
papayawhip |
FF EF D5 |
pink |
FF C0 CB |
rosybrown |
BC 8F 8F |
salmon |
FA 80 72 |
silver |
C0 C0 C0 |
slateblue |
6A 5A CD |
tan |
D2 B4 8C |
tomato |
FF 63 47 |
|
|
In this chapter you have covered several significant topics.
You now know how to divide the Navigator window into multiple independent sections and to work with functions and values in different windows using the hIdaho Frameset.
In addition, you have taken a detailed look at the document object and learned about its properties, which give you information about colors used in a document, as well as information about the last modification date of a document, and the location of a
document.
The window object, which is the parent object of the document object, provides you the ability to work with various aspects of windows and frames, including altering the text displayed in the window's status bar, setting timeouts to pause before
evaluating expressions or calling functions, and opening and closing named windows.
In the Chapter 9, "Remember Where You've Been with Cookies," you are going to take a look at Cookiesa feature of Navigator 2.0 that enables you to store information about a page and recall it later when the user returns to the page.
Command/Extension |
Type |
Description |
FRAMESET |
HTML tag |
Defines a window or frame containing frames |
ROWS |
HTML attribute |
Defines the number of rows in a FRAMESET tag |
COLS |
HTML attribute |
Defines the number of columns in a FRAMESET tag |
FRAME |
HTML tag |
Defines the source document for a frame defined in a FRAMESET container |
SRC |
HTML attribute |
Indicates the URL of a document to load into a frame |
NORESIZE |
HTML attribute |
Specifies that a frame is fixed in size and cannot be resized by the user |
SCROLLING |
HTML attribute |
Indicates if scroll bars are to be displayed in a frame (takes the value YES, NO or AUTO) |
MARGINHEIGHT |
HTML attribute |
Specifies the vertical offset in pixels from the border of the frame |
MARGINWIDTH |
HTML attribute |
Specifies the horizontal offset in pixels from the border of the frame |
TARGET |
HTML attribute |
Indicates the frame or window for a document to load intoused with the A, FORM, BASE and AREA tags |
NOFRAMES |
HTML tag |
Indicates HTML code to be displayed in browsers that don't support frames; used in documents containing the FRAMESET container tags |
frames |
JavaScript property |
Array of objects for each frame in a Navigator window |
parent |
JavaScript property |
Indicates the parent frameset document of the currently loaded document |
BODY |
HTML Tag |
Defines the main body of an HTML document |
BACKGROUND |
HTML attribute |
Specifies URL of a background image in the BODY tag |
BGCOLOR |
HTML attribute |
Specifies the background color for a document as a hexadecimal triplet or color name |
FGCOLOR |
HTML attribute |
Specifies the foreground color for a document as a hexadecimal triplet or color name |
LINK |
HTML attribute |
Specifies the color of link text |
ALINK |
HTML attribute |
Specifies the color of active link text |
VLINK |
HTML attribute |
Specifies the color of followed link text |
alinkColor |
JavaScript property |
The color value of active links |
anchors |
JavaScript property |
Array of objects corresponding to each named anchor in a document |
bgColor |
JavaScript property |
The background color value of a document |
fgColor |
JavaScript property |
The foreground color value of a document |
forms |
JavaScript property |
Array of objects corresponding to each form in a document |
lastModified |
JavaScript property |
As a string, the last date the document was modified |
linkColor |
JavaScript property |
The color value of link text |
links |
JavaScript property |
Array of objects corresponding to each link in a document |
location |
JavaScript property |
Object defining the full URL of the document |
title |
JavaScript property |
Title of the document represented as a string |
vlinkColor |
JavaScript property |
The color value of followed links |
hash |
JavaScript property |
An anchor name (location object) |
host |
JavaScript property |
Hostname and port of a URL (location object) |
href |
JavaScript property |
Hostname of a URL (location object) |
pathname |
JavaScript property |
File path from the URL (location object) |
port |
JavaScript property |
Port number from the URL (location object) |
protocol |
JavaScript property |
Protocol part of the URL (location object) |
search |
JavaScript property |
Form data or query from the URL (location object) |
assign() |
JavaScript method |
Sets location.href (location object) |
toString() |
JavaScript method |
Returns location.href as a string (location object) |
open() |
JavaScript method |
Opens a document for a particular MIME type (document object) |
close() |
JavaScript method |
Closes a document for writing (document object) |
clear() |
JavaScript method |
Clears a document window (document object) |
self |
JavaScript property |
Refers to the current window |
top |
JavaScript property |
The top-most parent window |
status |
JavaScript property |
Text displayed in the status bar represented as a string |
defaultStatus |
JavaScript property |
Default text displayed in the status bar |
close() |
JavaScript method |
Closes the window (window object) |
open() |
JavaScript method |
Opens a document in a named window (window object) |
setTimeout() |
JavaScript method |
Pauses for a specified number of milliseconds and then evaluates an expression |
clearTimeout() |
JavaScript method |
Cancels a previously set timeout |
onMouseOver |
Event handler |
Specifies script to execute when the mouse pointer is over a hypertext link |
|
|
|
Q: If I use frames in my documents, will users of any other Web
browsers be able to view my documents.
A: At the present time, only Netscape Navigator 2.0 supports the
FRAMESET and FRAMES tags. If you make effective use of the
NOFRAMES tag, it is possible to design perfectly reasonable
non-frame alternatives for the users of other browsers'
software. Of course, if you are using JavaScript, your users
must be using Navigator.
Q: Is it possible to force changes in the relative size of frames
using JavaScript?
A: No. There are no mechanisms to force resizing of frames in
JavaScript without reloading the document and dynamically
changing the value of the ROWS and COLS attributes of the
FRAMESET tag using document.write() or document.writeln().
Q: Is it possible to set the status bar when the user points at a
form button?
A: No. At the present time, the <INPUT TYPE=button> tag does not
support the onMouseOver event, which you use in the <A> tag to
set the status bar when the mouse points at the link.