CONTENTS
Up to this point in the book, you have learned about the major
objects and tools of JavaScript. Even so, this leaves several
useful objects undiscovered.
In this chapter you are going to take a detailed look at some
of the objects that you have been introduced to only briefly earlier
in the book. These include the string
object, the Math object,
and the history object.
Every string in JavaScript is an object. The string
object offers properties and methods to perform a variety of manipulations
on a given string. These include methods for searching a string,
extracting substrings, and applying HTML tags to the content of
the string.
The Math object provides
those functions and methods necessary to perform mathematical
calculations. These range from the PI
value to methods for all the trigonometric functions.
The history object is a bit
different in that it doesn't involve the manipulation of information
the way the string and Math
objects do. The history object
reflects the information in the browser's history list.
In this chapter you will learn the details of each of these object's
properties and methods plus:
- How to manipulate the content of strings
- How to perform advanced mathematical calculations with the
Math object
- How to build dynamic forward and back buttons-in any frame
You already have considerable experience working with strings.
You have used them throughout the book, you understand how to
represent string literals, and you even know some of the basic
techniques for examining the content of strings.
Even with the substring()
and indexOf() methods which
you saw earlier, though, you haven't reached the true possibilities
of working with the string
object.
The string object has only
one property: length. The
length property is an integer value reflecting the number of characters
in the string. Because the index of the first character in a string
is zero, this means the length
property is one greater than the index of the last character in
the string.
For example, the string "Hello"
has a length of five. The index of the first character ("H")
is 0, and the index of the
last character ("o")
is 4.
The flexibility and power of the string
object rest in the wide variety of methods available to manipulate
the content of the string. Table 10.1 outlines the methods available
in the string object.
Table 10.1. Methods of the string
object.
Name | Description
|
anchor()
| Surrounds the string with an anchor A tag.
|
big() |
Surrounds the string with the HTML BIG tag.
|
blink()
| Surrounds the string with the HTML BLINK tag.
|
bold()
| Surrounds the string with the HTML B tag.
|
charAt()
| Given an index as an argument, returns the character at the specified index.
|
fixed()
| Surrounds the string with the HTML TT tag to make it display as a fixed-width font.
|
fontcolor()
| Surrounds the string with the HTML <FONT COLOR=color> and </FONT> tags to make it display in the specified color.
|
fontsize()
| Surrounds the string with the HTML <FONT SIZE=size> and </FONT> tags to make it display in the desired font size.
|
indexOf()
| Given a string and an initial index, returns the index of the next occurrence of the string after the initial index.
|
italics()
| Surrounds the string with the HTML I tag.
|
lastIndexOf()
| Given a string and a starting index, returns the index of the last occurrence of the string starting the search backwards at the starting index.
|
link()
| Given a URL, surrounds the string with an A tag to create a hypertext link.
|
small()
| Surrounds the string with the HTML SMALL tag.
|
split()
| Returns an array of strings by splitting the string into substrings at a separator passed to the method as an argument.
|
strike()
| Surrounds the string with the HTML STRIKE tag.
|
sub() |
Surrounds the string with the HTML SUB tag.
|
substring()
| Given two indexes, returns the substring starting at the first index and ending with the character before the last index. If the second index is greater, the substring starts with the second index and ends with the character before the
first index; if the two indexes are equal, returns the empty string.
|
sup() |
Surrounds the string with the HTML SUP tag.
|
toLowerCase()
| Makes the entire string lowercase. |
toUpperCase()
| Makes the entire string uppercase. |
The HTML Methods
As you can see in Table 10.1, many of the methods of the string
object are designed to add HTML tags to the content of the string
so that when you display the string, it is suitably formatted.
This can make the JavaScript code easier to read than if all the
string assignments contained HTML tags, with the actual text to
be displayed using document.write()
or document.writeln().
The way these functions work is to return a new string containing
the additional HTML tags. So, if you have a string variable named
sample with the value "test",
sample.big() returns "<BIG>test</BIG>"
but sample still has a value
of "test".
For instance, the following JavaScript commands output the text
"Hello!" in large,
blinking, bold letters:
var sample = "Hello!";
var sampleBig = sample.big();
var sampleBlink = sampleBig.blink();
var sampleBold = sampleBlink.bold();
document.write(sampleBold);
The following text displays the same word but as a hypertext link
to the file: http://some.domain/some/file.html
var sample = "Hello!";
sample = sample.link("http://some.domain/some/file.html");
document.write(sample);
Because these methods return strings, you can also string together
a series of methods and rewrite the first example as
var sample = "Hello!";
document.write(sample.big().blink().bold());
To give you a better idea of what these methods actually do to
the content of your strings, the script in Listing 10.1 displays
the actual content of the strings using the XMP
tag to force the browser not to interpret any HTML in the output.
Listing 10.1. Applying HTML tags with JavaScript's string
object.
<HTML>
<HEAD>
<TITLE>HTML method example</TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
var sample = "hello";
document.write("<XMP>" + sample.italics() + "</XMP>");
document.write(sample.italics());
document.write("<XMP>" + sample.blink() + "</XMP>");
document.write(sample.blink());
document.write("<XMP>" + sample.anchor("test")
+ "</XMP>");
document.write(sample.anchor("test"));
document.write("<XMP>" + sample.fontsize(7) +
"</XMP>");
document.write(sample.fontsize(7));
document.write("<XMP>" + sample.bold().strike()
+ "</XMP>");
document.write(sample.bold().strike());
document.write("<XMP>" + sample.fontcolor("iceblue").big().sup()
+ "</XMP>");
document.write(sample.fontcolor("iceblue").big().sup());
// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>
</BODY>
</HTML>
The script produces results like those in Figure 10.1.
Figure 10.1 : The HTML methods of the string object return new strings containing the appropriate HTML tags.
 |
In this script, you are using various methods of the string object and the value returned by these methods. The script contains the examples in pairs of document.write() statements. The first output is the result of a method call
surrounded by the XMP HTML container tags. The XMP tag ensures that any content inside the container is displayed without any processing. In this way, any HTML inside the container is simply displayed as regular text rather than treated
as HTML.
|
The second line of each pair calls the same method but this time
without the surrounding XMP
tags so that the user can see what the result looks like when
treated as HTML.
The substring() Method
You have seen the substring()
method several times in previous chapters. You first saw the substring()
method in Exercise 6.3 when you used it to verify input in a form.
To review, the method takes two integer arguments and returns
the string starting at the first argument and ending at the character
before the second argument. Where the first argument is larger,
the process is reversed, and the substring starts at the second
argument and continues until one character before the first argument.
When both arguments are equal, an empty string is returned.
For instance, if you have a string named sample
with a value "Hello!",
then sample.substring(0,3)
is "Hel",
sample.substring(3,0) is "Hel",
and sample.substring(2,4)
has the value "ll".
The Case Methods
The string object has two
methods for changing the case of characters in a string. toLowerCase()
returns a new string with all characters in lowercase. Similarly,
toUpperCase() returns a copy
of the string with all characters uppercase.
For instance, if the variable sample
is "tEsT", then
sample.toLowerCase() is "test",
and sample.toUpperCase()
is "TEST".
Using a combination of these methods and the substring()
method, you can achieve more interesting results. If you want
to take a string and make the first character uppercase and the
rest lowercase, you could use the following technique:
var sample = "tEsT";
var newSample = sample.substring(0,1).toUpperCase() +
Âsample.substring(1,sample.length).toLowerCase();
Other Methods
The string object has three
other methods: indexOf(),
lastIndexOf(), and charAt().
You saw the indexOf() method
in Chapter 9, "Remember Where You've
Been with Cookies." Simply, given two arguments (a string
and an index) the method starts searching the string
object from the index and looks for the first occurrence of the
string that has been passed to it as an argument. It returns the
index of this occurrence.
This is best understood by example: If you have a string named
sample with the value "Greetings!
Welcome to Navigator 3.0! Enjoy!", then sample.indexOf("Wel",2)
would return a value of 13
and sample.lastIndexOf("!",sample.length
- 3) would return a value of 35.
What happens in the first example is that the method starts searching
the string sample from index 2
(the first "e"
in "Greetings").
It checks if the phrase "Wel"
starts at that index and if not, it moves to the next character
(index 3) and tries again.
This is repeated until the character at index 13,
where a match is found.
The send example is similar, but it moves backwards through the
string looking for a match. In this case it starts at the 3
character from the end ("o"
in "Enjoy")
and moves back until it finds a "!".
The other method, charAt(),
is almost the reverse of this process. Given an index as an argument,
it returns the character at that location. This is easier to use
than the substring() method
to extract a single character from a string.
For instance, with the above string, both sample.charAt(3)
and sample.substring(3,4)
have the value of "e".
With these methods, you can now develop tools to enable users
to play with HTML to see how it looks. Using two frames, you will
build an application that enables users to enter text in the left
frame and select from a list of HTML attributes. They will see
the text displayed with the combined attributes in the right frame,
along with the actual HTML code needed to produce the results.
Listings 10.2 through 10.4 contain the script files for the program.
In order to do this, you need a top-level frameset which looks
like Listing 10.2
.
Listing 10.2. Top-level frameset.
<HTML>
<HEAD>
<TITLE>Listing 10.2</TITLE>
</HEAD>
<FRAMESET COLS="50%,*">
<FRAME SRC="htmlform.html" NAME="choose">
<FRAME SRC="sample.html" NAME="output">
</FRAMESET>
</HTML>
The htmlform.html file is
where all the work is done.
Listing 10.3. The htmlform.html
file.
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
function display(form) {
var format = form.toDisplay.value;
var doc = parent.output;
format = (form.big.checked) ? format.big() : format;
format = (form.blink.checked) ? format.blink() : format;
format = (form.bold.checked) ? format.bold() : format;
format = (form.fixed.checked) ? format.fixed() : format;
format = (form.italics.checked) ? format.italics()
: format;
format = (form.small.checked) ? format.small() : format;
format = (form.strike.checked) ? format.strike() :
format;
format = (form.sup.checked) ? format.sup() : format;
format = (form.sub.checked) ? format.sub() : format;
format = (form.color.value == "") ? format.fontcolor("black")
:
Âformat.fontcolor(form.color.value);
format = (form.size.value == "") ? format.fontsize(3)
:
Âformat.fontsize(form.size.value);
var result = "<CENTER>The HTML code: <XMP>";
result += format;
result += "</XMP> looks like:<P>"
result += format;
result += "</CENTER>";
doc.document.open("text/html");
doc.document.write(result);
doc.document.close();
}
// STOP HIDING -->
</SCRIPT>
<BODY BGCOLOR="aquamarine">
<CENTER>
<H1>The HTML tester page</H1>
Please enter some text, select some attributes and
enter
a color and size (from 1 to 7).
The display will update dynamically.
<BR>
</CENTER>
<FORM METHOD=POST>
<TEXTAREA NAME="toDisplay" ROWS=10 COLS=35 WRAP=SOFT
onChange="display(this.form);">
Enter Text Here
</TEXTAREA><BR>
<INPUT TYPE="checkbox" NAME="big" onClick="display(this.form);">Big<BR>
<INPUT TYPE="checkbox" NAME="blink" onClick="display(this.form);">Blinking<BR>
<INPUT TYPE="checkbox" NAME="bold" onClick="display(this.form);">Bold<BR>
<INPUT TYPE="checkbox" NAME="fixed"
onClick="display(this.form);">Fixed
Width<BR>
<INPUT TYPE="checkbox" NAME="italics" onClick="display(this.form);">Italics<BR>
<INPUT TYPE="checkbox" NAME="small" onClick="display(this.form);">Small<BR>
<INPUT TYPE="checkbox" NAME="strike"
onClick="display(this.form);">Striked
Out<BR>
<INPUT TYPE="checkbox" NAME="sub" onClick="display(this.form);">Subscript<BR>
<INPUT TYPE="checkbox" NAME="sup" onClick="display(this.form);">SuperScript<BR>
Font Color: <INPUT TYPE="text" NAME="color"
VALUE="black"
onChange="display(this.form);"><BR>
Font Size (1 to 7): <INPUT TYPE="text" NAME="size"
VALUE="3"
onChange="display(this.form);">
</FORM>
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
display(document.forms[0]);
// STOP HIDING -->
</SCRIPT>
</BODY>
</HTML>
The file sample.html is just
a blank HTML file to fill the window when the frame is initially
loaded.
Listing 10.4. The source code for sample.html.
<HTML>
<BODY BGCOLOR="#FFFFFF">
</BODY>
</HTML>
This script produces results like those in Figure 10.2.
Figure 10.2 : Using methods from the string object to dynamically test different combinations of HTML attributes.
 |
This program not only highlights the effect of the previous example but also some of the methods and techniques you learned in previous chapters.
|
All the work is done in the file htmlform.html
(Listing 10.3). The program only really does one task-displays
information based on the content of a form-so only one function,
display(), is necessary.
function display(form) {
var format = form.toDisplay.value;
var doc = parent.output;
You start by setting up the global variable format.
You use this variable to hold the entire text and HTML tags to
be tested. You start by assigning the content of the textarea
input field, which contains the text you are going to test.
You also define doc to be
equal to the object parent.output.
parent.output refers to the
second frame in the frameset and is effectively the window
object for that frame. In this way, you can use doc
instead of parent.output.
For instance, doc.document.write()
is the same as parent.output.document.write().
format = (form.big.checked)
? format.big() : format;
format = (form.blink.checked) ? format.blink() : format;
format = (form.bold.checked) ? format.bold() : format;
format = (form.fixed.checked) ? format.fixed() : format;
format = (form.italics.checked) ? format.italics()
: format;
format = (form.small.checked) ? format.small() : format;
format = (form.strike.checked) ? format.strike() :
format;
format = (form.sup.checked) ? format.sup() : format;
format = (form.sub.checked) ? format.sub() : format;
format = (form.color.value == "") ? format.fontcolor("black")
:
format.fontcolor(form.color.value);
format = (form.size.value == "") ? format.fontsize(3)
:
format.fontsize(form.size.value);
This section of code looks complex at first glance, but in reality,
it is simple. You start by checking whether any of the checkboxes
are checked. Because the checkbox
object's checked property
is a Boolean value, you can use it as the condition for a conditional
expression, which performs the appropriate method and then assigns
the result back to format.
Next, you apply the appropriate fontcolor()
and fontsize() methods based
on the form content. If either field is empty, you use a default
value.
var result = "<CENTER>The
HTML code: <XMP>";
result += format;
result += "</XMP> looks like:<P>"
result += format;
result += "</CENTER>";
doc.document.open("text/html");
doc.document.write(result);
doc.document.close();
The final task is to output the results. The string result
holds the complete output for the second frame. Then you use document.open()
to open a new output stream in the second frame for the HTML MIME
type. You write the results to the frame and close the stream
with document.close().
<FORM METHOD=POST>
<TEXTAREA NAME="toDisplay" ROWS=10 COLS=35 WRAP=SOFT
onChange="display(this.form);">
Enter Text Here
</TEXTAREA><BR>
<INPUT TYPE="checkbox" NAME="big" onClick="display(this.form);">Big<BR>
<INPUT TYPE="checkbox" NAME="blink" onClick="display(this.form);">Blinking<BR>
<INPUT TYPE="checkbox" NAME="bold" onClick="display(this.form);">Bold<BR>
<INPUT TYPE="checkbox" NAME="fixed"
onClick="display(this.form);">Fixed
Width<BR>
<INPUT TYPE="checkbox" NAME="italics" onClick="display(this.form);">Italics<BR>
<INPUT TYPE="checkbox" NAME="small" onClick="display(this.form);">Small<BR>
<INPUT TYPE="checkbox" NAME="strike"
onClick="display(this.form);">Striked
Out<BR>
<INPUT TYPE="checkbox" NAME="sub" onClick="display(this.form);">Subscript<BR>
<INPUT TYPE="checkbox" NAME="sup" onClick="display(this.form);">SuperScript<BR>
Font Color: <INPUT TYPE="text" NAME="color"
VALUE="black"
onChange="display(this.form);"><BR>
Font Size (1 to 7): <INPUT TYPE="text" NAME="size"
VALUE="3"
onChange="display(this.form);">
The form is simple. When any text field changes, you call display()
and when any checkbox is clicked, you also call display().
No buttons are needed.
Note
|
When using a form with no buttons like this, realize that in the version of Navigator currently available, it is necessary to remove focus from a text field for a change event to be triggered.
|
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
display(document.forms[0]);
// STOP HIDING -->
</SCRIPT>
You end the body of the HTML file with a one-line script that
calls display() for the first
time to update the second frame with the contents of the form.
This also could have been done in the onLoad
event handler.
Anyone familiar with UNIX will miss many of the powerful text
searching and matching tools found in the operating system and
in scripting languages such as Perl, Awk, and sed. Although JavaScript
provides the indexOf(), lastIndexOf(),
charAt(), and substring()
methods to help manipulate string contents, it doesn't provide
powerful search and replace capabilities.
In this example, you extend the functionality of JavaScript's
text manipulation capabilities with simple search
and replace functions.
The search function should
be able to search for words both in a case sensitive and case
insensitive manner and should be able to search for whole words
or substrings in words. Likewise, the replace
function should be able to replace a word or substring, paying
attention to case in the original text or ignoring it.
The search function should
return true or false,
and the replace function
should return a new string with the result of the replace.
Listing 10.5 is the source code for these search and replace functions.
Listing 10.5. Searching and replacing in JavaScript.
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
// SET UP ARGUMENTS FOR FUncTION CALLS
//
var caseSensitive = true;
var notCaseSensitive = false;
var wholeWords = true;
var anySubstring = false;
// SEARch FOR A TERM IN A TARGET STRING
//
// search(targetString,searchTerm,caseSensitive,wordOrSubstring)
//
// where caseSenstive is a boolean value and wordOrSubstring is
a boolean
// value and true means whole words, false means substrings
//
function search(target,term,caseSens,wordOnly) {
var ind = 0;
var next = 0;
if (!caseSens) {
term = term.toLowerCase();
target = target.toLowerCase();
}
while ((ind = target.indexOf(term,next)) >= 0)
{
if (wordOnly) {
var before = ind - 1;
var after = ind + term.length;
if (!(space(target.charAt(before))
&& space(target.charAt(after)))) {
next = ind + term.length;
continue;
}
}
return true;
}
return false;
}
// SEARch FOR A TERM IN A TARGET STRING AND REPLACE IT
//
// replace(targetString,oldTerm,newTerm,caseSensitive,wordOrSubstring)
//
// where caseSenstive is a boolean value and wordOrSubstring is
a boolean
// value and true means whole words, false means substrings
//
function replace(target,oldTerm,newTerm,caseSens,wordOnly) {
var work = target;
var ind = 0;
var next = 0;
if (!caseSens) {
oldTerm = oldTerm.toLowerCase();
work = target.toLowerCase();
}
while ((ind = work.indexOf(oldTerm,next)) >= 0)
{
if (wordOnly) {
var before = ind - 1;
var after = ind + oldTerm.length;
if (!(space(work.charAt(before))
&& space(work.charAt(after)))) {
next = ind + oldTerm.length;
continue;
}
}
target = target.substring(0,ind) + newTerm
+
target.substring(ind+oldTerm.length,target.length);
work = work.substring(0,ind) + newTerm
+
work.substring(ind+oldTerm.length,work.length);
next = ind + newTerm.length;
if (next >= work.length) { break; }
}
return target;
}
// chECK IF A chARACTER IS A WORD BREAK AND RETURN A BOOLEAN VALUE
//
function space(check) {
var space = " .,/<>?!`';:@#$%^&*()=-|[]{}"
+ '"' + "\\\n\t";
for (var i = 0; i < space.length; i++)
if (check == space.charAt(i)) { return
true; }
if (check == "") { return true; }
if (check == null) { return true; }
return false;
}
// STOP HIDING -->
</SCRIPT>
To demonstrate how these functions work, you can set up a simple
search and replace application using the functions in Listing
10.6.
Listing 10.6. Using the search and replace functions.
<HTML>
<HEAD>
<TITLE>Listing 10.6</TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
// SET UP ARGUMENTS FOR FUncTION CALLS
//
var caseSensitive = true;
var notCaseSensitive = false;
var wholeWords = true;
var anySubstring = false;
// SEARch FOR A TERM IN A TARGET STRING
//
// search(targetString,searchTerm,caseSensitive,wordOrSubstring)
//
// where caseSenstive is a boolean value and wordOrSubstring is
a boolean
// value and true means whole words, false means substrings
//
function search(target,term,caseSens,wordOnly) {
var ind = 0;
var next = 0;
if (!caseSens) {
term = term.toLowerCase();
target = target.toLowerCase();
}
while ((ind = target.indexOf(term,next)) >= 0)
{
if (wordOnly) {
var before = ind - 1;
var after = ind + term.length;
if (!(space(target.charAt(before))
&& space(target.charAt(after)))) {
next = ind + term.length;
continue;
}
}
return true;
}
return false;
}
// SEARch FOR A TERM IN A TARGET STRING AND REPLACE IT
//
// replace(targetString,oldTerm,newTerm,caseSensitive,wordOrSubstring)
//
// where caseSenstive is a boolean value and wordOrSubstring is
a boolean
// value and true means whole words, false means substrings
//
function replace(target,oldTerm,newTerm,caseSens,wordOnly) {
var work = target;
var ind = 0;
var next = 0;
if (!caseSens) {
oldTerm = oldTerm.toLowerCase();
work = target.toLowerCase();
}
while ((ind = work.indexOf(oldTerm,next)) >= 0)
{
if (wordOnly) {
var before = ind - 1;
var after = ind + oldTerm.length;
if (!(space(work.charAt(before))
&& space(work.charAt(after)))) {
next = ind + oldTerm.length;
continue;
}
}
target = target.substring(0,ind) + newTerm
+
target.substring(ind+oldTerm.length,target.length);
work = work.substring(0,ind) + newTerm
+
work.substring(ind+oldTerm.length,work.length);
next = ind + newTerm.length;
if (next >= work.length) { break; }
}
return target;
}
// chECK IF A chARACTER IS A WORD BREAK AND RETURN A BOOLEAN VALUE
//
function space(check) {
var space = " .,/<>?!`';:@#$%^&*()=-|[]{}"
+ '"' + "\\\n\t";
for (var i = 0; i < space.length; i++)
if (check == space.charAt(i)) { return
true; }
if (check == "") { return true; }
if (check == null) { return true; }
return false;
}
// STOP HIDING -->
</SCRIPT>
</HEAD>
<BODY>
<TABLE WIDTH=100%>
<TR>
<TD VALIGN=TOP>
<DIV ALIGN=CENTER>
<H1>Search</H1>
<FORM METHOD=POST>
<SCRIPT LANGUAGE="JavaScript">
<!- HIDE FROM OTHER BROWSERS
function doSearch(form) {
var result = search(form.initial.value,form.term.value,
form.casesens.checked,form.word.checked);
alert ((result) ? "Found!" : "Not Found!");
}
// STOP HIDING -->
</SCRIPT>
<TEXTAREA NAME="initial" ROWS=2 COLS=30>Search
Text</TEXTAREA><BR>
Search For: <INPUT TYPE="text" NAME="term"><BR>
<INPUT TYPE="checkbox" NAME="casesens">
Case Sensitive
<INPUT TYPE="checkbox" NAME="word">
Whole Word Search<BR>
<INPUT TYPE="button" VALUE="SEARch" onClick="doSearch(this.form);">
</FORM>
</DIV>
</TD>
<TD VALIGN=TOP>
<DIV ALIGN=CENTER>
<H1>Replace</H1>
<FORM METHOD=POST>
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
function doReplace(form) {
form.result.value =
Âreplace(form.initial.value,form.oldterm.value,form.newterm.value,
Âform.casesens.checked,form.word.checked);
}
// STOP HIDING -->
</SCRIPT>
<TEXTAREA NAME="initial" ROWS=2 COLS=30>Search
Text</TEXTAREA><BR>
<TEXTAREA NAME="result" ROWS=2 COLS=30>Result
Text</TEXTAREA><BR>
Search For: <INPUT TYPE="text" NAME="oldterm"><BR>
Replace With: <INPUT TYPE="text" NAME="newterm"><BR>
<INPUT TYPE="checkbox" NAME="casesens">
Case Sensitive
<INPUT TYPE="checkbox" NAME="word">
Whole Word Search<BR>
<INPUT TYPE="button" VALUE="REPLACE" onClick="doReplace(this.form);">
</FORM>
</DIV>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>
This script produces results like those in Figure 10.3.
Figure 10.3 : The search and replace functions can be used in any JavaScript application.
 |
You use three functions to implement the search and replace system: search(), replace(), and space().
|
search() and replace()
use a similar approach to handling their tasks, but differ in
the specific actions they take when they find the term they are
looking for.
The replace() function takes
five arguments: the string to work on, the term to search for,
the term to replace it with, and two Boolean values. The two Boolean
values indicate whether to pay attention to the case of letters
in searching and whether to search only for whole words (if not,
substrings will be matched and replaced).
var work = target;
var ind = 0;
var next = 0;
As would be expected, you start by setting up the work variables.
if (!caseSens) {
oldTerm = oldTerm.toLowerCase();
work = target.toLowerCase();
}
Then you check whether you are paying attention to case. If not,
you change the search term and the string to search to lowercase,
using the toLowerCase() method.
This means that case is ignored in the searches because any variation
in case in either string has been removed.
while ((ind = work.indexOf(oldTerm,next))
>= 0) {
if (wordOnly) {
var before = ind - 1;
var after = ind + oldTerm.length;
if (!(space(work.charAt(before))
&& space(work.charAt(after)))) {
next = ind + oldTerm.length;
continue;
}
}
All the work is done in the preceding while
loop. In the condition of the while
loop, you search the target string for the next occurrence of
the search term, store the index in ind,
and see if it is greater than zero.
If you have found an occurrence of the term, you next check if
you are searching for whole words or substrings. If you are searching
for whole words, you use the space()
function to check if the characters before and after the word
boundary are word breaks. If they aren't, you update next
to the index of the character after the term you just found and
start the loop again.
target = target.substring(0,ind)
+ newTerm +
target.substring(ind+oldTerm.length,target.length);
work = work.substring(0,ind) + newTerm
+
work.substring(ind+oldTerm.length,work.length);
next = ind + newTerm.length;
if (next >= work.length) { break; }
}
If you reach this point in the loop, then you have found a term
you want to replace. You use the substring
method to update both the string itself and change the variable
next to the index of the
character after the term you have just added.
Finally, you check if you have reached the end of the target string,
and if not, you run the loop again to look for another occurrence.
This function is similar in structure to the replace()
function. The differences lie in the while
loop:
while ((ind = target.indexOf(term,next))
>= 0) {
if (wordOnly) {
var before = ind - 1;
var after = ind + term.length;
if (!(space(target.charAt(before))
&& space(target.charAt(after)))) {
next = ind + term.length;
continue;
}
}
return true;
}
return false;
As before, you perform the search for the search term using the
indexOf() method in the condition
of the while loop. Again,
you check if you are searching for whole words, and if you are,
you check for word boundaries. If you haven't found a complete
word, you prepare to search again and return to the top of the
loop with the continue statement.
If you get beyond the if
statements, you have found an occurrence of the term and return
a true value from the function.
If you finish the while loop
without returning true, then
you haven't found a match and you return a false
value.
The space() function plays
a support role for search()
and replace().
Given a character as an argument, the function checks whether
it is one of a series of characters considered word breaks or
delimiters. If it is, the function returns true-otherwise,
it returns a false value.
The way this is done is simple. All the possible word breaks are
stored in the string space.
A for loop goes through the
string, character by character and compares each character to
the argument. If there is a match, a true
result is returned.
After the loop, a comparison is made between the argument and
either the empty string or the null
value. If these are true,
the function returns a true
value as well.
If you have failed all these conditions, then a false
value is returned because the argument character is not a word
break.
If the programmer wants to change the definition of a word break,
he or she simply has to change the declaration of the variable
space.
Where the string object enables
you to work with text literals, the Math
object provides methods and properties to move beyond the simple
arithmetic manipulations offered by the arithmetic operators.
Among the features offered by the Math
object are several special values such as PI,
natural logarithms, and common square roots, trigonometric methods,
rounding methods, an absolute value method, and more.
Table 10.2 outlines all the properties and methods of the Math
object.
Table 10.2. Properties and methods of the Math
object.
Name | Description
|
E | Euler's constant-the base of natural logarithms (roughly 2.718).
|
LN10 |
The natural logarithm of 10 (roughly 2.302). |
LN2 |
The natural logarithm of 2 (roughly 0.693). |
PI |
The ratio of the circumference of a circle to the diameter of the same circle (roughly 3.1415).
|
SQRT1_2
| The square root of 1/2 (roughly 0.707). |
SQRT2 |
The square root of 2 (roughly 1.414). |
abs() |
Calculates the absolute value of a number. |
acos() |
Calculates the arc cosine of a number-returns result in radians.
|
asin() |
Calculates the arc sine of a number-returns result in radians.
|
atan() |
Calculates the arc tangent of a number-returns result in radians.
|
atan2()
| Calculates the angle of a polar coordinate that corresponds to a cartesian (x,y) coordinate passed to the method as arguments.
|
ceil() |
Returns the next integer greater than or equal to a number.
|
cos() |
Calculates the cosine of a number. |
exp() |
Calculates e to the power of a number. |
floor()
| Returns the next integer less than or equal to a number.
|
log() |
Calculates the natural logarithm of a number. |
max() |
Returns the greater of two numbers-takes two arguments.
|
min() |
Returns the least of two numbers-takes two arguments.
|
pow() |
Calculates the value of one number to the power of a second number-takes two arguments.
|
random()
| Returns a random number between zero and one.
|
round()
| Rounds a number to the nearest integer. |
sin() |
Calculates the sine of a number. |
sqrt() |
Calculates the square root of a number. |
tan() |
Calculates the tangent of a number. |
Some of these functions require further discussion.
You will notice that the trigonometric methods, such as acos()
and sin() use radians to
measure the size of angles instead of the more familiar degrees.
This isn't too difficult to handle. Where you have 360 degrees
in a circle, there are 2¥PI (or
roughly 6.283) radians in a circle.
So, where the arc tangent of 1 is 45 degrees, in radians, the
result is roughly 0.785398.
The log() and exp()
functions are related in that they use e, Euler's constant, as
their base.
The relationship between logarithms and exponential expressions
is that if log(a) = b, then
exp(b) = a.
The absolute value method returns the positive value of a number.
That is, it removes a negative sign from a number so that abs(4)
and abs(-4) both have a value
of 4.
To highlight some of these math functions, you are going to build
a simple calculator that calculates the angles and the lengths
of the sides of a right angle triangle and calculates the area,
diameter, and circumference of a circle.
In order to do this, you will use the trigonometric functions
and PI.
As a reminder, with a right angle triangle, if you want to calculate
the sine, cosine, or tangent of any of the other two angles, you
can use the following formulas:
sine = opposite side / hypotenuse
cosine = adjacent side / hypotenuse
tangent = opposite side / adjacent side
The script should be able to fill in all the information about
the shapes when there is sufficient information in the relevant
form. The results of Listing 10.7 look like Figure 10.4.
Figure 10.4 : Using the Math object to perform more complex mathematical calculations.
Listing 10.7. Using the trigonometric functions.
<HTML>
<HEAD>
<TITLE>Example 10.7</TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS
function circle(form,changed) {
with (Math) {
var area = form.area.value;
var diameter = form.diameter.value;
var circumference = form.circumference.value;
if (changed == "area") {
var radius = sqrt(area / PI);
diameter = 2 * radius;
circumference = PI * diameter;
}
if (changed == "diameter") {
area = PI * (diameter / 2)
* (diameter / 2);
circumference = PI * diameter;
}
if (changed == "circumference")
{
diameter = circumference /
PI;
area = PI * (diameter / 2)
* (diameter / 2);
}
form.area.value = area;
form.diameter.value = diameter;
form.circumference.value = circumference;
}
}
var toDegrees = 360 / (Math.PI * 2);
var toRadians = (Math.PI * 2) / 360;
function angle(form,changed) {
with (Math) {
var angle = (changed == "angleA")
? form.angleA.value *
toRadians
: form.angleB.value;
var otherAngle = (90 * toRadians) - angle;
var hypotenuse = form.hypotenuse.value;
var sine = sin(angle);
var opposite = sine * hypotenuse;
var cosine = cos(angle);
var adjacent = cosine * hypotenuse;
if (changed == "angleA") {
form.angleB.value = otherAngle
* toDegrees;
form.sideA.value = adjacent;
form.sideB.value = opposite;
} else {
form.angleA.value = otherAngle
* toDegrees;
form.sideB.value = adjacent;
form.sideC.value = opposite;
}
}
}
function side(form,changed) {
with (Math) {
var side = (changed == "sideA")
? form.sideA.value : form.sideB.value;
var hypotenuse = form.hypotenuse.value;
var otherSide = sqrt(pow(hypotenuse,2)
- pow(side,2));
var angle = acos(side/hypotenuse);
var otherAngle = acos(otherSide/hypotenuse);
if (changed == "sideA") {
form.sideB.value = otherSide;
form.angleA.value = angle
* toDegrees;
form.angleB.value = otherAngle
* toDegrees;
} else {
form.sideA.value = otherSide;
form.angleB.value = angle
* toDegrees;
form.angleA.value = otherAngle
* toDegrees;
}
}
}
function hyp(form) {
angle(form,"angleA");
}
// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>
</HEAD>
<BODY>
<TABLE WIDTH="100%">
<TR>
<TD>
<H1>Circle</H1>
<FORM METHOD=POST>
Area: <INPUT TYPE="text" NAME="area" VALUE=0
onChange="circle(this.form,this.name);"><BR>
Diameter: <INPUT TYPE="text" NAME="diameter"
VALUE=0
onChange="circle(this.form,this.name);"><BR>
Circumference: <INPUT TYPE="text" NAME="circumference"
VALUE=0
onChange="circle(this.form,this.name);">
</FORM>
</TD>
<TD>
<H1>Triangle</H1>
<FORM METHOD=POST>
Angle A: <INPUT TYPE="text" NAME="angleA"
VALUE=45
onChange="angle(this.form,this.name);"><BR>
Angle B: <INPUT TYPE="text" NAME="angleB"
VALUE=45
onChange="angle(this.form,this.name);"><BR>
Side A: <INPUT TYPE="text" NAME="sideA"
VALUE=1
onChange="side(this.form,this.name);"><BR>
Side B: <INPUT TYPE="text" NAME="sideB"
VALUE=1
onChange="side(this.form,this.name);"><BR>
Hypotenuse: <INPUT TYPE="text" NAME="hypotenuse"
VALUE=1.414
onChange="hyp(this.form);">
</FORM>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>
Figure 10.4 shows the result.
Figure 10.4 : Using the Math object to perform more complex mathematical calculations.
 |
This script is rather simple, but it shows how to use the methods and properties available in the Math object.
|
Of the two forms, the circle form is the simpler because it has
less information to deal with. The following two sections analyze
the two functions.
The circle() function takes
two arguments: the form object
and the name of the field that was just changed. The calculations
are based on the name of this field.
with (Math) {
var area = form.area.value;
var diameter = form.diameter.value;
var circumference = form.circumference.value;
You start by extracting whatever information is in the form and
storing it in local variables. Notice the use of the with
(Math) command. This enables all of the Math
properties and methods in the function to be used without the
Math prefix.
Note
|
The with command makes it easy to write command blocks that use properties and methods of a single object repeatedly. For instance, if you use with (object) { command block } then inside the command block, the methods and properties of
object can be referred to as methodName and propertyName without the leading object.
|
if (changed ==
"area") {
var radius = sqrt(area / PI);
diameter = 2 * radius;
circumference = PI * diameter;
}
if (changed == "diameter") {
area = PI * (diameter / 2)
* (diameter / 2);
circumference = PI * diameter;
}
if (changed == "circumference")
{
diameter = circumference /
PI;
area = PI * (diameter / 2)
* (diameter / 2);
}
The three if statement blocks
simply calculate the other two fields based on the value of the
changed field. All of these use two basic formulas:
Area of Circle = PI¥radius¥radius
Circumference of Circle = PI¥diameter
Notice the use of the sqrt()
method without the preceding Math
prefix, which is made possible with the earlier with
(Math) command.
form.area.value
= area;
form.diameter.value = diameter;
form.circumference.value
= circumference;
Once the calculation is done, you can reassign the results to
the form.
The triangle function assumes that you are working with a right
triangle. This means the angle across from the hypotenuse is always
90 degrees.
The relationship between the remaining angles and sides is that
sideA is adjacent to angleA
and sideB is adjacent to
angleB.
Before you can proceed to calculate the information in this form,
you need to be able to convert between degrees and radians. All
the trigonometric functions either take a radian value as a parameter
or return a radian value. Users, on the other hand, are likely
to prefer working in degrees.
You get around this by using the variables toDegrees
and toRadians which represent
the number of degrees per radian and the number of radians per
degree:
var toDegrees = 360 / (Math.PI * 2);
var toRadians = (Math.PI * 2) / 360;
The angle() function is called
whenever you change one of the two angle values. It uses the fact
that all the angles of a triangle add up to 180 degrees to calculate
the remaining angle. Then, using the sin()
and cos() methods and the
formulas for sine and cosine, the program calculates the length
of the opposite and adjacent sides for the changed angle.
Finally, based on which angle was changed, the results are assigned
to the correct form field.
The side() function plays
a similar role when either sideA
or sideB is changed. Using
the value of the changed side and the value of the hypotenuse,
you can calculate the value of the third side using the formula:
sideA¥sideA + sideB¥sideB
= hypotenuse¥hypotenuse
After you have the value for the three sides, you can use the
acos() method and the formula
for cosine to calculate the value of the two angles.
The hypotenuse function simply
calculates what the value of sideA
and sideB should be based
on the current angle settings by calling angle(form,"angleA").
You could just as easily have made the call angle(form,"angleB").
The forms in the body of the HTML file are fairly simple. They
call the appropriate function in the onChange
event handler for each text field.
When you use the Navigator browser, you will notice the history
list, which is accessible under the Go menu.
The history object makes
this list accessible in JavaScript. Early versions of JavaScript
made the actual URLs in the list available to the script, but
this was too large a security hole because it could be used by
malicious scripts to steal information to access some secure Web
sites. In addition, it could be used to breach privacy by supplying
a page author with information about what sites a visitor had
previously visited.
The history object provides
methods for working with the list without actually reflecting
the value of URLs and entries into a script.
Table 10.3 outlines the properties and methods available in the
history object.
Table 10.3. Properties and methods of the history
object.
Name | Description
|
length
| The length of the history list |
back()
| Loads the previous URL in the history list
|
forward()
| Loads the next URL in the history list |
go() |
Loads the URL indicated by an offset from the current place in the history list
|
For instance, history.back()
goes to the previous page while history.go(-3)
goes back to the page visited three pages ago (like clicking the
Back button three times on the Navigator toolbar) and history.go(2)
goes two URLs forward in the list.
The history.go() method can
also take a string instead of an integer as an argument. When
a string is used, the method loads the nearest entry in the history
that contains the string as part of its URL. The matching of the
string against the URL is case insensitive.
One of the more popular uses of the history
object is to provide back and forward buttons in individual frames
or dynamic back buttons, which take users back to the last page
they were on.
Manipulating data has been the focus of much of this chapter.
Using the string object,
you now know how to add HTML tags using methods, how to change
the case of a string, and how to search for the string and perform
basic search and replace functions.
The Math object enables you
to extend the type of mathematical calculations you can perform
to include trigonometry, logarithms, and square roots and also
provides several values as properties, including PI,
E, and LN2.
The history object is a little
different. By providing the ability to jump to URLs in the history
list (without breaching security by providing the actual URL information),
it is possible to build dynamic back and forward buttons into
documents.
In the next chapter you will put everything you have learned together
into producing a fun cartoon face drawing program.
Command/Extension | Type
| Description |
anchor()
| JavaScript method | Surrounds the string with an anchor A tag.
|
big() |
JavaScript method | Surrounds the string with the HTML BIG tag.
|
blink()
| JavaScript method | Surrounds the string with the HTML BLINK tag.
|
bold()
| JavaScript method | Surrounds the string with the HTML B tag.
|
charAt()
| JavaScript method | Given an index as an argument, returns the character at the specified index.
|
fixed()
| JavaScript method | Surrounds the string with the HTML TT tag to make it display as a fixed-width font.
|
fontcolor()
| JavaScript method | Surrounds the string with the HTML <FONT COLOR=color> and </FONT> tags to make it display in the specified color.
|
fontsize()
| JavaScript method | Surrounds the string with the HTML <FONT SIZE=size> and </FONT> tags to make it display in the desired font size.
|
indexOf()
| JavaScript method | Given a string and an initial index, returns the index of the next occurrence of the string after the initial index.
|
italics()
| JavaScript method | Surrounds the string with the HTML I tag.
|
lastIndexOf()
| JavaScript method | Given a string and a starting index, returns the index of the last occurrence of the string starting the search backward at the starting index.
|
link()
| JavaScript method | Given a URL, surrounds the string with an A tag to create a hypertext link
|
small()
| JavaScript method | Surrounds the string with the HTML SMALL tag.
|
split()
| JavaScript method | Returns an array by splitting a string at a specified separator.
|
strike()
| JavaScript method | Surrounds the string with the HTML STRIKE tag.
|
sub() |
JavaScript method | Surrounds the string with the HTML SUB tag.
|
substring()
| JavaScript method | Given two indexes, returns the substring starting at the first index and ending with the character before the last index. If the second index is greater, the substring starts with the second index and
ends with the character before the first index; if the two indexes are equal, returns the empty string.
|
sup() |
JavaScript method | Surrounds the string with the HTML SUP tag.
|
toLowerCase()
| JavaScript method | Makes the entire string lowercase.
|
toUpperCase()
| JavaScript method | Makes the entire string uppercase.
|
E |
JavaScript property | Euler's constant-the base of natural logarithms (roughly 2.718).
|
LN10 |
JavaScript property | The natural logarithm of 10 (roughly 2.302).
|
LN2 |
JavaScript property | The natural logarithm of 2 (roughly 0.693).
|
PI |
JavaScript property | The ratio of the circumference of a circle to the diameter of the same circle (roughly 3.1415).
|
SQRT1_2
| JavaScript property | The square root of 1/2 (roughly 0.707).
|
SQRT2 |
JavaScript property | The square root of 2 (roughly 1.414).
|
abs() |
JavaScript method | Calculates the absolute value of a number.
|
acos()
| JavaScript method | Calculates the arc cosine of a number-returns result in radians.
|
asin()
| JavaScript method | Calculates the arc sine of a number-returns result in radians.
|
atan()
| JavaScript method | Calculates the arc tangent of a number-returns result in radians.
|
atan2()
| JavaScript method | Calculates the angle of a polar coordinate based on a Cartesian coordinate.
|
ceil()
| JavaScript method | Returns the next integer greater than or equal to a number.
|
cos() |
JavaScript method | Calculates the cosine of a number.
|
exp() |
JavaScript method | Calculates e to the power of a number.
|
floor()
| JavaScript method | Returns the next integer less than or equal to a number.
|
log() |
JavaScript method | Calculates the natural logarithm of a number.
|
max() |
JavaScript method | Returns the greater of two numbers-takes two arguments.
|
min() |
JavaScript method | Returns the least of two numbers-takes two arguments.
|
pow() |
JavaScript method | Calculates the value of one number to the power of a second number-takes two arguments.
|
random()
| JavaScript method | Returns a random number between zero and one.
|
round()
| JavaScript method | Rounds a number to the nearest integer.
|
sin() |
JavaScript method | Calculates the sine of a number.
|
sqrt()
| JavaScript method | Calculates the square root of a number.
|
tan() |
JavaScript method | Calculates the tangent of a number.
|
length
| JavaScript method | The length of the history list. Also used in the string object to provide the value of the string.
|
back()
| JavaScript method | Loads the previous URL in the history list.
|
forward()
| JavaScript method | Loads the next URL in the history list.
|
go() |
JavaScript method | Loads the URL indicated by an offset from the current place in the history list.
|
- What would the output of the following code segment look like
assuming there were no HTML tags elsewhere in the file affecting
the output?
var sample = "test.";
sample.big();
sample.blink();
sample.bold();
sample.strike();
sample.fontsize(7);
document.write(sample.italics());
- In the text searching and replacing functions (refer to Listings
10.5 and 10.6), we have left out a critical feature: a wildcard.
Extend the search and replace script to add a simple wildcard
capability to the search()
function. Use the following criteria:
- Use the asterisk character for your wildcard.
- The wildcard represents zero or more of any letter.
- Only one wildcard is enabled in a search term.
- Wildcards are valid only in the middle of a search term: "text*"
and "*text" are
not valid-catch this and inform the user.
If you search the string "Hello
there" for "lo*e"
you should get a match as you would with "H*lo",
but "the*h" would
not succeed.
- What are the lines of code necessary to implement a dynamic
forward and back button in an HTML page. The buttons should work
just like the ones in the Navigator toolbar. (Hint: you need only
one form with two buttons to do this.)
- The phrase "test."
would print in italics. All the other method()
calls are useless. Remember that these methods return the new
value. They do not directly alter the string. So, the results
of all the other method calls went unassigned and unused. If we
change the code to read
var sample = "test.";
sample = sample.big();
sample = sample.blink();
sample = sample.bold();
sample = sample.strike();
sample = sample.fontsize(7);
document.write(sample.italics());
then all the attributes will be applied to the displayed
text.
- The new search function would look like this:
function search(target,term,caseSens,wordOnly)
{
var ind = 0;
var ind2 = 0;
var next = 0;
var wildcard = -1;
var firstTerm = "";
var secondTerm = "";
if (!caseSens) {
term = term.toLowerCase();
target = target.toLowerCase();
}
if ((wildcard = term.indexOf("*",0)) >=
0) {
if (!checkWildCards(term)) {
alert("Improper use of
the wildcard character.");
return false;
}
firstTerm = term.substring(0,wildcard);
secondTerm = term.substring(wildcard+1,term.length);
while ((ind = target.indexOf(firstTerm,next))
>= 0) {
var afterFirst = ind + firstTerm.length;
ind2 = target.indexOf(secondTerm,afterFirst);
if (ind2 < 0) { break;
}
if (wordOnly) {
for (var i = ind+firstTerm.length;
i <= ind2 - 1; i++)
if
(space(target.charAt(i))) {
next
= i + 1;
continue;
}
var before = ind
- 1;
var after = ind2
+ secondTerm.length;
if (!(space(target.charAt(before))
&& space(target.charAt(after))))
Â{
next = ind2 + secondTerm.length;
if
(next >= target.length) { break; }
continue;
}
}
return true;
}
return false;
}
while ((ind = target.indexOf(term,next)) >= 0)
{
if (wordOnly) {
var before = ind - 1;
var after = ind + term.length;
if (!(space(target.charAt(before))
&& space(target.charAt(after))))
 {
next = ind + term.length;
continue;
}
}
return true;
}
return false;
}
You would also need to add the checkWildCards()
function:
function checkWildCards(term) {
if (term.charAt(0) == "*") { return false;
}
if (term.charAt(term.length-1) == "*") {
return false; }
var first = term.indexOf("*",0);
if (term.indexOf("*",first+1) >= 0) {
return false; }
return true;
}
You have not changed the basic functionality of the
search() function. Rather,
you have added a component in the middle which handles the wildcard
searches. If there is no wildcard in the search term, the search
functions operate in the same way as they did before, simply bypassing
the wildcard section.
Assuming you have found a wildcard character, you perform an altered
search, which is based on the simple search performed when there
is no wildcard.
You start by checking that the use of the wildcard character is
valid by calling checkWildCards().
If everything is correct, then you split the search term into
two terms: the portion before the wildcard and the portion after
it.
You then search for the first term in the condition of the while
loop. If the first term occurs, you look for the second term.
If the second term isn't there, you have no match and break out
of the loop. Otherwise, you check if you are doing a whole word
search. If you are, the function performs a check on the character
before the occurrence of the first term and after the occurrence
of the second term for word delimiter characters using the space()
function. You also check that there are no word delimiters between
the two terms. If the search fails either of these tests, you
jump back to the top of the loop to continue searching the target
string.
Otherwise, if you get past the wordOnly
if statement, you know you
have found a match and return a true
value from the function.
- The code
<FORM METHOD=POST>
<INPUT TYPE=button VALUE="BACK" onClick="history.back();">
<INPUT TYPE=button VALUE="FORWARD" onClick="history.forward();">
</FORM>
will implement dynamic forward and back buttons.