Notice: This material is excerpted from Special Edition Using JavaScript, ISBN: 0-7897-0789-6. The electronic version of this material has not been through the final proof reading stage that the book goes through before being published in printed form. Some errors may exist here that are corrected before the book is published. This material is provided "as is" without any warranty of any kind.
This chapter describes the creation of dynamic documents and windows as well as the interaction between windows and their components. This chapter presumes that you now have a working knowledge of JavaScript syntax; the material covered is somewhat more complex than in earlier chapters (see chapter 4, "JavaScript Objects").
The first theme of the chapter is the creation of pop-up windows. The entire content of those windows is defined by a creation function, rather than a URL. We will examine various examples, including pop-ups with text, pop-ups with buttons, and editable pop-ups.
We will next examine the history, status, and location objects. You will see how to hurl the user to a specific URL on the history list, how to examine the various parts of the location object, and how to store and retrieve information using the search property of the location object. Finally, you will learn how to create dynamic documents. In fact, you will create a page entirely from JavaScript. You will also learn how to rewrite pages on-the-fly.
The "Browser and HTML Objects" section of Chapter 4 discusses the way in which JavaScript code accesses HTML and browser components.
You have already learned a lot about objects in JavaScript. In fact, the previous four chapters have been devoted to exploring the various JavaScript objects and their uses. You have already been exposed to the various built-in objects and HTML objects that JavaScript provides. To go further and explore dynamic HTML creation, we must first take a closer look at the hierarchy of objects in JavaScript.
If you are familiar with any object-oriented languages, you expect an object hierarchy to begin with a generic object from which all other objects are descendants or children. Unfortunately, the JavaScript object hierarchy does not really follow this model. It might be best described as a system of ownership, and, even then, the analogy is not really exact. For example, a window that creates another window could be thought of as the parent of the new window. However, if you try to refer to the original window from the child by saying parent.someobject, it will not work.
On the other hand, frames within a frameset have a parent-child relationship with the original window, and asking for parent.someobject will likely yield the object. Other ownership relationships are not characterized by a parent-child relationship at all. For example, form elements belong to a form, but to obtain the form, you use this.form-not this.parent. With these disconcerting thoughts in mind, let's attempt to sort out the dependencies among Netscape Navigator objects.
The Navigator is, in a way, the parent of all other JavaScript objects. It is the executable that runs the browser. The Navigator is responsible for the creation of all browser windows. It is also responsible for responding to general window events. The Navigator is not a visual object. You cannot see it. You only interact with it through its visual construct: its windows.
Most Navigator window components can only be manipulated in a yes/no fashion at the time of window creation. These include the menu, the button bar, the location display, the status display, history list display, and scroll bars. At time of window creation, you can also determine whether the window can be resized as well as finding its dimensions.
This might seem like a significant restriction. By rewriting the document, however, you can change the contents of a window. This technique enables you to change the values of form elements, the content of the status bar, the position of the pointer in the history list, and the location (the URL that the window contains) at any time. Table 8.1 lists these various elements, when they can be modified, and how they can be modified. Note that the last two items in this table are not really window elements: they control what is displayed, but are not explicitly displayed themselves.
Table 8.1 Modification Rules for JavaScript Controls | |||
---|---|---|---|
Object | When | How | Rewrite? |
Button bar | Window creation | Yes/No | NA |
Menu | Window creation | Yes/No | NA |
Location display | Window creation | Yes/No | NA |
Status Bar | Window creation | Yes/No | NA |
History | Window creation | Yes/No | NA |
Document | During rewrite | Complete | NA |
Many form | Any time | Complete | No |
Element properties | Any time | Complete | No |
Status bar content | Any time | Complete | No |
Location | Any time | Complete | Yes |
History list | Any time | Complete | Yes |
One of the more advanced projects later in this book is the creation of a sticky notes application (in the "Dynamic Documents" section). To do that, you need to have a small note window in which to present the note. Let's create a primordial note window now. To do that, you must already have a window open with an element that enables you to call a JavaScript function (such as a button with an onClick handler). This base window is the parent of the child note window. The child can always find its parent with self.parent but the parent can only refer to the child by its name. There is no self.child[] reference nor is there a windows array available to JavaScript because of security concerns.
Netscape Navigator is a mimic. If you create a window under JavaScript control, the next window that is created by Navigator will have the same dimensions as the last window created by JavaScript.
The element that we will use is an image that behaves as a button, which is triggered by a HREF=javascript:myfunc included in the LINK tag. This works very well if you need to call only one function and you need no return value. When you try to use this mechanism in a window constructed on-the-fly, however, the image refuses to display. In fact, any image that uses relative addressing refuses to display in a dynamic window.
The solution is to either use a completely static reference for the image or to set the base directory of your page with <BASE>path</BASE> in the header. This latter approach helps JavaScript find the image. If you need an object that will be accessed later, you might want to use a form input element, rather than one of these button images. JavaScript will have less trouble finding it.
The following three steps are necessary to use an image as a button for executing a JavaScript function:
These three steps are shown in listing 8.1.
Listing 8.1 Creating a Button Image <IMG WIDTH=23 HEIGHT= 22 VSPACE=2 HSPACE= 2 ALIGN=LEFT SRC="Images/gobtn.gif" BORDER=0> <A HREF='xxxxxx'><IMG WIDTH=23 HEIGHT= 22 VSPACE=2 HSPACE= 2 ALIGN=LEFT SRC="Images /gobtn.gif" BORDER=0><A> <A HREF='javascript: openNote'><IMG WIDTH=23 HEIGHT= 22 VSPACE=2 HSPACE= 2 ALIGN=LEFT SRC="Images/gobtn.gif" BORDER=0><A>
The function used in this example is the openNote() function, the source for which is given in listing 8.2. Before we plunge into this code, it is worthwhile to notice that the border has explicitly been set to zero. This is the only way you can keep Navigator from drawing a border around your image if it is within a reference statement. Listing 8.2 contains the HTML for the base window with the Image button. It includes the openNotes() function in a header script. . Once you open a note window, make sure you close it before it gets lost. Navigator will not open a second window by the same name: it just updates the first one. When this code is executed by pressing the Make Note button you will see something like figure 8.1.
Listing 8.2 Creating a New Window in JavaScript <HTML> <HEAD> <TITLE>Opening a Window with JavaScript</TITLE> <SCRIPT> //window globals var aNoteWin function openNote(topic) { aPopUp= window.open('','Note','toobar=no,location=no, ¬ directories=no,status=no,scrollbars=yes,resizable=yes, ¬ copyhistory=no,width=300,height=200') ndoc= aPopUp.document astr ='<HTML><HEAD><BR><TITLE>' + topic + '</TITLE>' astr +='</HEAD>' astr +='<BODY>' astr +=topic + '<BR>' astr +='</BODY></HTML>' ndoc.write(astr) ndoc.close() self.aNoteWin = aPopUp } function closeNote(which) { self.aNoteWin.close() } </SCRIPT> </HEAD> <BODY> <H3><BR><HR><BR></H3> <CENTER> <FONT SIZE=5 COLOR='darkred'><B>Example 1</B></FONT>: <FONT SIZE=5 ¬ COLOR='darkblue'><B>Opening a New Window</B></FONT> <FORM NAME='noteForm'> <INPUT TYPE='button' NAME='makeBtn' VALUE='Make Note' ¬ onclick='openNote(""JoAnn Murphy at 7:00; bring salad")'> <INPUT TYPE='button' NAME='closeBtn' VALUE='Close note' ¬ onclick='closeNote()'> </FORM> </CENTER> <H3><BR><HR><BR></H3> </BODY> </HTML>
In a windows.open statement, there are three things to bear in mind.
Fig. 8.1 Dynamically created window may be tied to button events in JavaScript.
This small script illustrates several points. First, you can set a window global by defining it outside of any function and preceding it with var. Here we set the window global aNoteWin with var aNoteWin. This variable is global so that you could use it to refer to aNoteWin in other functions. Although we did not do so here, you might want to save a number of notes in an array. Second, when you create a window de novo via a script and no URL is specified, the window document is still open and you can write to it. Here we wrote the note topic and then closed the document.
A window that you create can be as simple as the note window. However, you can also make this window quite complex. In order to do so, you must write everything to the document, including form elements, images, and JavaScript functions, before you close it. Listing 8.3 shows a second version of the openNote() function. This more elaborate version furnishes the note window with two buttons, including onClick handlers, the topic text, a warning message, and two JavaScript functions. Note that the save function is stubbed. The topic of data storage is discussed in Chapter 20. All the display elements are neatly wrapped in a table.
Data may be stored transiently in the location.search property and persisently in cookies; both topics are discussed in the "Persistent Data Storage" section of Chapter 20.
Listing 8.3 A More Sophisticated Notes Window function openNote(topic) { aPopUp= window.open('','Note','toobar=no,location=no,¬ directories=no,status=no,scrollbars=yes,resizable=yes, ¬ copyhistory=no,width=300,height=200') ndoc= aPopUp.document ndoc.close() ndoc.open() astr ='<HTML><HEAD><BR><TITLE>' + topic + '</TITLE>' astr +='</HEAD>' astr +='<SCRIPT>' astr +='function closeNote(aName){' astr +='self.close()' astr +='}' astr +='function saveNote(aName){' astr +='}' astr +='<\/SCRIPT>' astr +='<BODY>' astr +='<FORM>' astr +='<TABLE ALIGN=LEFT BORDER><TR ALIGN=CENTER><TD>' astr +='\<INPUT TYPE=button NAME=saveBtn VALUE="Save" ¬ ONCLICK="saveNote()" \>' astr +='</TD>' astr +='<TD ROWSPAN=4>' + topic astr +='</TD>' astr +='</TR><TR ALIGN=CENTER><TD>' astr +='\<INPUT TYPE=button NAME=closeBtn VALUE="Close" ¬ ONCLICK="closeNote()" \>' astr +='</TD></TR>' astr +='<TR><TD><BR></TD></TR>' astr +='<TR><TD><BR></TD></TR>' astr +='</TABLE>' astr +='</FORM>' astr +='<BR CLEAR=ALL><H3><BR></H3>' astr +='Note: Save button is not active yet' astr +='</BODY></HTML>' ndoc.write(astr) ndoc.close() self.aNoteWin = aPopUp }
Netscape Navigator keeps you appraised of which link or button your mouse pointer is over via its status bar. Occasionally, it sends you other messages via that method, too. Perhaps you have seen it busily scrolling text to catch your attention. The status (not the status bar itself) is a property of a window and is accessible to you as self.status = 'Some message'. When you change the status, Navigator immediately displays it in the status bar. You can also set a property called defaultStatus, which is the default message displayed in the status bar. Listing 8.4 illustrates the use of the status property in Netscape Navigator.
Listing 8.4 Manipulating the Status Bar <HTML> <HEAD> <TITLE>Manipulating the Status Bar</TITLE> <SCRIPT> // set up a window global so that the new window can be accessed // from all functions. var aStatWin = null function openStatus(defmsg,msg) { aStatWin=window.open('','statWin','toobar=no,location=no, ¬ directories=no,status=yes,scrollbars=no,resizable=yes, ¬ copyhistory=no,width=550,height=2') if (aStatWin != null) { aStatWin.document.write('<FORM NAME="dform"> ¬ <INPUT TYPE=TEXT NAME="dummy"></FORM>') aStatWin.document.close aStatWin.defaultStatus = defmsg aStatWin.status = msg setFocus() } } function setStatus() { if(self.aStatWin == null ) alert('Status window is closed!') else { self.aStatWin.status = document.statForm.statMsg.value setFocus() } } function setFocus() { self.aStatWin.document.dform.dummy.focus() } function close() { self.aStatWin.close() aStatWin = null } //This function is a work-around to make sure that the table // overlay is drawn correctly. function fixup() { blankWin=window.open('','blankWin','toobar=no,location=no, ¬ directories=no,status=yes,scrollbars=no,resizable=no, ¬ copyhistory=no,width=600,height=450') blankWin.close() } </SCRIPT> </HEAD> <!-- fixup forces redraw of window after everything, including images, has loaded. The redraw is necessary to enforce correct drawing of table overlays. --> <BODY onLoad='fixup()'> <H3><BR><HR><BR></H3> <CENTER> <FONT SIZE=5 COLOR='darkred'><B>Example : </B></FONT> ¬ <FONT SIZE=5 COLOR='darkblue'><B>Setting the Contents of the ¬ Status Bar</B></FONT> <H3><BR><HR><BR></H3> <H3><BR></H3> </CENTER> <CENTER> <FORM NAME='statForm'> <TABLE WIDTH=520 ALIGN=CENTER BORDER><TR ALIGN=CENTER><TD> <TABLE WIDTH=500 ALIGN=CENTER > <TR ALIGN=CENTER> <TD WIDTH=35 ALIGN=CENTER> <IMG WIDTH=485 HEIGHT=50 VSPACE=2 HSPACE= 2 ¬ ALIGN=CENTER SRC="Images/gotray.gif"> </TD> <TD> <!-- <INPUT TYPE=button VALUE='Make Status Window' ¬ onClick='openStatus("Status is GO!", ¬ document.statForm.statMsg.value)'> --> <A HREF='javascript: openStatus("Status is GO!", ¬ document.statForm.statMsg.value)'> <IMG WIDTH=23 HEIGHT=22 VSPACE=2 HSPACE=2 ALIGN=absMiddle ¬ SRC="Images/gobtn1.gif" BORDER=0> Open Status Window</A> </TD> <TD ALIGN=LEFT > <A HREF='javascript: setStatus()'> <IMG WIDTH=23 HEIGHT=22 VSPACE=2 HSPACE=2 ALIGN=absMiddle ¬ SRC="Images/gobtn2.gif" BORDER=0> Set Status</A> </TD> <TD ALIGN=CENTER > <A HREF= 'javascript: close()'> <IMG WIDTH=31 HEIGHT=30 VSPACE=2 HSPACE= 2 ALIGN=absMiddle BORDER=0 ¬ SRC="Imagesokbtn.gif"> Close Status </A> </TD> </TR> <TR ALIGN=CENTER> <TD ALIGN=CENTER COLSPAN=4> Msg <INPUT TYPE=text NAME='statMsg' VALUE='Howdy!' ¬ SIZE= 50 MAXLENGTH=80> </TD> </TR> </TABLE> </TD></TR></TABLE> </FORM> </CENTER> <H3><BR></H3> </BODY> </HTML>
This example builds a window with a status bar included. Just to make things interesting, we will set the content of the status bar from the parent window. In addition, this script provides an example of the advanced HTML concept of table overlays, and an onLoad() handler, which provides a work-around for Netscape's unpredictable order of drawing images. We will say a little more about table overlays below, when we discuss the fixup() function.
The status window is created with a 'javascript: openStatus(defMsg,msg)' link attached to an image. This function, openStatus(defMsg, msg), performs the following tasks:
We will set the status of the status window with a call to setStatus(). This call is made from a 'javascript: setStatus(document.statForm.statMsg.value)' link attached to an image.
The setStatus() function also checks to see if aStatWin exists before it tries to address one of its objects. If aStatWin does exist, setStatus changes the content of its status bar. setStatus() then sets the focus on the dummy button in aStatWin to bring the window to the front. This is done by a call to the setFocus() method. The resulting window is shown in figure 8.2. When you are done with the window you can close it using an image button linked with a call to close(). The close() function. simply closes aStatWin and makes sure that its value is reset to null.
Fig. 8.2 A status bar window may be created dynamically by the parent window.
The function fixup() is worth looking at in more detail. The order in which Netscape Navigator draws images depends upon where the images are coming from, whether they are in the cache, and whether their height and width are given explicitly. It can also depend on the size of the images. Extremely attractive presentations can be made by overlaying text and graphics on other graphics via the overlay feature of Netscape tables.
However, Netscape will invariably draw your bottom image last when the page first loads. Scrolling the screen causes the correct redraw, but you cannot expect or require your users to do that. One way to force the redraw is to open and quickly close another window over your page. You need to do this after all of the page elements have been loaded. When this occurs, Navigator sends an onLoad event, which you can capture in the <BODY> tag. The fixup() function insures that all of the image buttons are visible. Although this is far from an ideal solution, it is effective.
Always check that a newly created window exists before you try to address its properties or methods. Do this by checking to see if the window is null. If it is null, use an alert to inform the user.
The location object essentially holds information about the URL to which the browser points. The browser reads this marked up text from the server's disk and interprets it just like Microsoft Word reads and interprets a file on your disk. In addition to the URL, the location object also contains any post parameters of an HTML form submitted via a Submit button or your call to submit(). Because of this, you can use the location object for temporary storage. In Netscape, the location consists of the following parts:
protocol//hostname: (port) pathname search hash
Protocol is the type of protocol used for this file. Examples are http, ftp, gopher, telnet, and file (for files on the local disk). Hostname and port are only valid when the document is on a remote server. They contain the domain name/IP address of the server and the server port, respectively. They are not usually a visible part of a URL. The Web port is a number denoting the type of service, and is usually 80 for http. The pathname is the path to the file that the browser displays. Search includes any post parameters that are compiled when a form is submitted. Hash is usually a link to a local anchor.
The location object also has a host property, which consists of the combination of hostname and port. The location object also has an extremely important property, known as href, which contains the entire URL.
This next example is a page that has no body. It is written entirely by the header script. As the page is written, it dissects the location object and lists all of its properties in a table. To see a non-empty location.search, you have to submit the little form included after the table. To see a non-empty location.search, click the dummy link and then Netscape's Reload button. The host, port, and hostname properties will be non-empty only if you have loaded some page from a server. Listing 8.5 shows the code for the Location Display script.
Listing 8.5 Displaying the Properties of the Location Object <HTML> <HEAD> <!- Created 08 Feb 1996 a2:41 PM 02:41 PM --> <TITLE>Parts of the Location Object</TITLE> <SCRIPT> var aline = '<H3><BR></H3><HR><H3><BR></H3>' var skip='<H3><BR></H3>' document.write('<CENTER>') document.write('<FONT SIZE=5 COLOR="darkred"><B>Example : </B></FONT> ¬ <FONT SIZE=5 COLOR="darkblue"> ¬ <B>What\'s in the Location Object?</B></FONT>') ¬ document.write('<BR>') document.write('<BLOCKQUOTE><BLOCKQUOTE>If you are viewing this ¬ document from your hard disk, host, hostname, and port will ¬ be empty.</BLOCKQUOTE></BLOCKQUOTE>') document.write('<BR>') document.write('<CENTER><TABLE ALIGN= CENTER BORDER CELLPADDING=3>') document.write('<TR><TD><B>Property</B></TD><TD ALIGN=CENTER> ¬ <B>Value</B></TD></TR>') document.write('<TR><TD>href</TD><TD>' + location.href + '</TD></TR>') document.write('<TR><TD>protocol</TD><TD>' + location.protocol ¬ + '</TD></TR>') document.write('<TR><TD>hostname</TD><TD>' + location.hostname ¬ + '</TD></TR>') document.write('<TR><TD>host</TD><TD>' + location.host + '</TD></TR>') document.write('<TR><TD>port</TD><TD>' + location.port + '</TD></TR>') document.write('<TR><TD>pathname</TD><TD>' + location.pathname ¬ + '</TD></TR>') document.write('<TR><TD>search</TD><TD>' + location.search ¬ + '</TD></TR>') document.write('<TR><TD>hash</TD><TD>' + location.hash + '</TD></TR>') document.write('</TABLE></CENTER>') document.write(aline) document.write('<CENTER>') document.write('<FORM NAME="nameForm" >') document.write('Your name\: <INPUT TYPE=text NAME="yourName" ¬ VALUE="John Smith" WIDTH=30 MAXLENGTH=30>') document.write('<INPUT TYPE=submit VALUE="Click Me to Add a ¬ Search Parameter!" >') document.write('</FORM>') document.write('<A HREF=' + location.href + '#myAnchor >Click on me ¬ and then RELOAD to enter a hash parameter!</A>') document.write(aline) </SCRIPT> </HEAD> </HTML>
Not only can you obtain useful information by examining the location object, you can also modify it and send the user elsewhere. This is useful if you should want to dynamically generate a URL or a reference to an anchor. The example shown in listing 8.6 builds a URL dynamically and sends the current browser to that URL. This code implements a "Message Center," which retrieves messages from URLs created via button clicks. Five users have been created to demonstrate this aspect of the location object.
Listing 8.6 Modifying the Current URL Dynamically <HEAD> <!- Created 08 Feb 1996 a4:08 PM 04:08 PM --> <TITLE>Message Center</TITLE> <SCRIPT> function getMessage(who) { loc = self.location document.forms[0].translate.value = loc loc = document.forms[0].translate.value k = loc.lastIndexOf('/') loc = loc.substring(0,k+1) nloc = loc.substring(0,k+1)+ who.value + '.htm' self.location=nloc } </SCRIPT> </HEAD> <BODY> <CENTER><HR> <FONT SIZE=5 COLOR='darkred'><B>Example 4</B></FONT>: <FONT SIZE=5 ¬ COLOR='darkblue'><B>Moving Around Dynamically</B></FONT><BR> <HR><FONT SIZE=6 COLOR='darkslateblue'><B>Message Center</B></FONT><BR> </CENTER> <CENTER> <FORM> <TABLE BORDER ALIGN=CENTER><TR><TD> <INPUT TYPE=radio NAME='getMsgR' VALUE='John' ¬ onClick='getMessage(this)'>John <INPUT TYPE=radio NAME='getMsgR' VALUE='George' ¬ onClick='getMessage(this)'>George <INPUT TYPE=radio NAME='getMsgR' VALUE='Barbara' ¬ onClick='getMessage(this)'>Barbara <INPUT TYPE=radio NAME='getMsgR' VALUE='Ken' ¬ onClick='getMessage(this)'>Ken <INPUT TYPE=radio NAME='getMsgR' VALUE='Julie' ¬ onClick='getMessage(this)'>Julie <INPUT TYPE=hidden NAME='translate' VALUE='' > </TD></TR></TABLE> </FORM> </CENTER> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
The script works by first obtaining the current location. It then strips off the filename and replaces it with the value of the radio button clicked. It also makes sure to tack on the suffix, .htm. This presumes that the message HTML files are in the same directory as the current page. However, it would be easy enough to build in a subdirectory name just for the messages or even have a separate subdirectory for each person. The location object is then set to the newly constructed URL. Setting the location object retrieves the file at that location. In our example, this file represents the set of messages for the particular user whose button was pressed.
You can force a page to be reloaded by setting the location object to the URL corresponding to that page.
When you submit a form, all the values of the various form elements are retrieved, parsed, and concatenated with the location object; they are placed after the path and preceded by question marks (?). The value of location.search is precisely that string, including the question mark (?).
This string is not just a simple list of element contents, however. Each element value is placed in the string in the form 'elementName=elementValue' and followed by an ampersand (&). Any non-alphanumeric characters are coded or escaped. The ASCII value of any such character is changed into a two-digit hex number preceded by a percent sign (%). If text field or textarea elements have multiple words, these words are separated by a plus sign (+). Consequently, when you get the location.search string, you have to decode it to get the various form elements that it contains.
The section on "Global and Local Variables" in Chapter 9 discusses character encoding in more detail.
You can place your own form element values, or anything else, in the location's search property. As long as you precede it with a question mark (?), location.search will retrieve it. However, not all non-alphanumeric characters can be placed in the string or retrieved intact. If you are going to concoct a home-grown search string, you may either need to encode the parameters yourself or not allow non-alphanumeric characters. Listing 8.7 is a simple page that shows you how to manipulate location.search.
Listing 8.7 Using the Search Property of the Location Object <HTML> <HEAD> <!- Created 08 Feb 1996 a6:10 PM 06:10 PM --> <TITLE>Forcing a Reload with Location</TITLE> <SCRIPT> function reloadMe() { astr = document.nameForm.myName.value astr= self.location.pathname + '?' + astr self.location = astr } function clearUp() { self.location = self.location.pathname } if (self.location.search != null && self.location.search !='') { document.write('<CENTER><FONT SIZE=4 COLOR="darkslategray"><B> ¬ Form Entry Data: </B></FONT></CENTER>') document.write('<CENTER><FONT SIZE=4 COLOR="red"><B>' + ¬ self.location.search + '</B></FONT></CENTER>') } </SCRIPT> </HEAD> <H3><HR></H3> <CENTER><FONT SIZE=6 COLOR="blue"><B>Forcing a Reload with ¬ Location</B></FONT></CENTER> <H3><BR><HR><BR></H3> <CENTER> <FORM NAME=nameForm> <INPUT TYPE=text NAME=myName VALUE='abracadabra&#^$()'> <INPUT TYPE=button NAME=reloadBtn VALUE='Reload Page' ¬ onClick='reloadMe()'> <INPUT TYPE=button NAME=submitBtn VALUE= 'Submit Form' ¬ onClick='this.form.submit()'> <INPUT TYPE=button NAME=clearBtn VALUE= 'Clear' onClick='clearUp()'> <INPUT TYPE=hidden NAME=hideFld > </FORM> </CENTER> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
A script in the <HEAD> part of an HTML document can pick up the command-line parameters with location.search and write something to the document being loaded based on what it finds. This example just reads the parameter string and writes it for you at the head of the page. Note that this write is guarded by a test to see if location.search is null or empty. If location.search is not a valid string and you attempt to parse it into variables that are used later, you will encounter error after error. Always test for a null string or an empty string.
The code in listing 8.7 has two useful functions. ClearUp() simply strips the search string from the location by setting the location object to location.path. The reloadMe() function takes the value from the text box and adds it to location.path. It then sets the location to that result.
The history object is a list that contains the locations of all the URLs that you have visited. You can move backwards and forwards through the history list with history.back and history.forward. You can also move around in the list in a relative fashion with history.go(). This function takes a positive or negative integer argument and moves you that many URLs forward or backward in the history list. The only property of a history list you can access is its length, which is the number of items in the list. You can neither set nor retrieve history list items.
To show how to manipulate the history list, we will build another pop-up window that boasts only a Close button and four directional buttons. The buttons enable you to manipulate the history list of the parent window. You can move backwards and forwards by one step or five. This code is shown in listing 8.8.
Listing 8.8 Using the History Object in a Pop-up Window <HTML> <HEAD> <!- Created 08 Feb 1996 a9:21 PM 09:21 PM --> <TITLE>Running through the History List</TITLE> <SCRIPT> var aNoteWin var myDummyVar = 'Apples, peaches, pumpkin pie...' function openNote(topic) { aPopUp= window.open('','Note','toobar=no,location=no, ¬ directories=no,status=no,scrollbars=yes,resizable=yes, ¬ copyhistory=no,width=110,height=150') ndoc= aPopUp.document ndoc.close() ndoc.open() astr ='<HTML><HEAD><BR><TITLE>' + topic + '</TITLE>' astr +='<SCRIPT>' astr +='function closeNote(aName){' astr +='self.close()' astr +='}\n' astr +='function saveNote(aName){' astr +='}\n' astr +='function goNext(){' astr +='creator.history.forward()\n' astr +='}\n' astr +='function goBack(){' astr +='creator.history.back()\n' astr +='}\n' astr +='function goStart(){' astr += 'creator.history.go(-5)\n' astr +='}\n' astr +='function goEnd(){' astr +='creator.history.go(5)\n' astr +='}\n' astr +='<\/SCRIPT>' astr +='</HEAD>' ndoc.write(astr) astr ='<BODY>' astr +='<FORM NAME="popForm">' astr +='<TABLE ALIGN=LEFT BORDER>' astr +='</TR><TR ALIGN=CENTER><TD>' astr +='\<INPUT TYPE=button NAME=closeBtn VALUE="Close" ¬ ONCLICK="closeNote()" \>' astr +='</TD>' astr +='</TR>' astr +='<TR><TD>' astr +='<INPUT TYPE="button" NAME="startBtn" VALUE=<< ¬ onclick="goStart()">' astr +='<INPUT TYPE="button" NAME="backBtn" VALUE=< ¬ onclick="goBack()">' astr +='<INPUT TYPE="button" NAME="nextBtn" VALUE=> ¬ onclick="goNext()">' astr +='<INPUT TYPE="button" NAME="endBtn" VALUE=>> ¬ onclick="goEnd()">' astr +='</TD></TR>' astr +='<TR><TD>' astr +='<INPUT TYPE="hidden" NAME="IAm" VALUE="0">' astr +='</TD></TR>' astr +='</TABLE>' astr +='</FORM>' astr +='<BR CLEAR=ALL><H3><BR></H3>' astr +='</BODY></HTML>' ndoc.write(astr) ndoc.close() self.aNoteWin = aPopUp self.aNoteWin.creator = self aNoteWin.document.popForm.startBtn.focus() } function closeNote(which) { self.aNoteWin.close() } </SCRIPT> </HEAD> <BODY > <CENTER> <FONT SIZE=5 COLOR='darkred'><B>Example 6</B></FONT>: ¬ <FONT SIZE=5 COLOR='darkblue'><B>Running through the History List ¬ </B></FONT> </CENTER> <H3><BR><HR><BR></H3> <BODY> <H3><BR><HR><BR></H3> <CENTER> <FORM NAME='noteForm'> <INPUT TYPE='button' NAME='makeBtn' VALUE='Make Popup' ¬ onclick='openNote("JoAnn Murphy at 7:00; bring salad.")'> <INPUT TYPE='button' NAME='closeBtn' VALUE='Close Popup' ¬ onclick='closeNote()'> </FORM> </CENTER> <H3><BR><HR><BR></H3> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
This pop-up is a variation on our old friend, aNoteWin. It can access its parent's variables through an artificial property of aNoteWin, the creator property. At the end of the openNote() function, which creates and draws the window, aNoteWin.creator is set to self. This automatically creates a new property of the aNoteWin. This enables you to have ready access to the parent window's variables, functions, and objects.
Although it would be useful to retrieve history list items, this functionality has been removed from JavaScript. Unfortunately, each history list entry contains the entire location, including the search string. If this information could be retrieved, the possibility exists that credit card or other personal information might be gleaned by malicious individuals.
You may have wondered why there is no windows array. This also, does not exist in JavaScript for security reasons. If it did, a script from one window might reach into another unrelated window and scavenge information from its form elements or its location object. Again, what might be perceived as a limitation in JavaScript has been imposed to protect you.
The document object encapsulated all JavaScript objects that correspond to the HTML elements. It is the parent of forms, links, and anchors. These objects occur as arrays and are accessed as document.Forms[xx], document.Links[xx], and document.anchors[xx], where xx is an array index. The document object also has several other useful properties. It has a property, for example, for all of the standard object colors, such as the background color, text color, and link colors. You cannot change the property of a static closed document, however, so these properties are useful only when building a document.
Four properties that are useful in keeping your documents up to date are the location, title, lastModified, and referrer properties. These are used to dynamically write a header or a footer for your documents. Listing 8.9 shows a typical example of how you could use the document object in this way. Note that the properties of the document object are read-only. The attempt to set document.title in this listing will fail.
Listing 8.9 Writing the Document Header <HTML> <HEAD> <!- Created 08 Feb 1996 a11:32 PM 11:32 PM --> <TITLE>Writing a Document Header</TITLE> <SCRIPT> document.bgcolor = 'linen' document.text = 'darkslateblue' document.link = 'coral' document.vlink='peach' document.alink='red' document.title='Dynamic Headers' document.write('<TABLE ALIGN=RIGHT WIDTH=300 BORDER=1>') document.write('<TR><TD>') document.write('<FONT SIZE=7 COLOR= "navy">') document.write('<CENTER>' +document.title + '</CENTER>') document.write('</TD></TR></TABLE>') document.write('<CENTER><B>') document.write('<HR>') document.write('This document was last modified on<BR> ¬ <FONT COLOR="red">' + document.lastmodified + '</FONT><BR>') document.write('Save this URL: <BR><FONT COLOR="red">' ¬ + document.location + '</FONT><BR>') document.write('You arrived here from <BR><FONT COLOR="red">' ¬ + document.referrer + '</FONT><BR>') document.write('<BR><HR><BR>') document.write('</B></CENTER>') document.write('') </SCRIPT> </HEAD> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
You can get input from your users via HTML form elements (sometimes known as widgets). You can have many forms on a page. If they are named (by an HTML NAME directive) you can refer to them by name. You can also refer to a form by its index into the zero based forms array. Each form can have any one of the standard HTML form elements. These include single-line text, radio, checkbox, hidden, password, reset, and submit. There is also a select widget, which can be either a drop-down list or a plain list, and a textarea widget, which can be used to collect large amounts of text spanning multiple lines.
The section on "Using JavaScript Event Handlers" in Chapter 3 talks about the correspondence between HTML doem elements, the events which they generate, and their JavaScript counterparts.
A script can only access elements that have already been created. They cannot be accessed in a document <HEAD> because the forms and their elements do not yet exist.
Links are the bread and butter of any hypertext system, especially HTML. In JavaScript, the links array can be canvassed in order to provide a list of links in a document. Links have only one property, the target. The target is not the URL pointed to by the link; rather, it is the window into which that URL will be loaded. Any link is also a location object, so that you can dissect the link in the same way you dissect a location object.
Links can have an onClick handler just as buttons do. However, when the onClick handler finishes, the URL specified by the link will be loaded. If you do not want the link to go anywhere, just specify the current URL as its destination. If you want to use a link to execute a function, use HREF= 'javascript: myfunc()'. Myfunc() can call a function or contain JavaScript code. For example, HREF='javascript: self.close()', immediately closes the current window.
A javascript:xxx() call replaces a URL. The browser will try to interpret any return from a function call as if it were a URL. If the browser does not understand the return value, it reloads the current page. When that occurs, any window globals that you set during the xxx() function call will be lost.
Both text and images can be links. You can include both in the same link if you want so that clicking either the text or the image will activate the link's events. Because images can be links, you can use them as buttons to call functions if you use javascript:xxx() as the HREF instead of a URL. Unfortunately, because you cannot replace images dynamically, you cannot modify the appearance of the image to simulate a button down effect.
Links can also trap the onMouseOver event. However, it traps this event at the boundaries of the link. What that means is that if you run your mouse pointer over a link, the event will be fired twice: once when you enter the bounding box of the link and once when you leave it.
If you use the onMouseOver event to write to the status bar, you find that if you move your mouse too quickly you miss the status write. This is because it is rapidly replaced by the browser's own response to the event. When you exit, the status written will stay there until you encounter another link. If you want to use the content of your link in a function called from an onMouseOver handler, you can pass the function the keyword this. Links are treated like any other JavaScript Object. Figure 8.3 shows a onMouseOver event being triggered just as the mouse moves over the link.
Fig. 8.3 MouseOver is only fired when the mouse pointer enters or leaves the linked object.
Figure 8.3 was generated by the code in listing 8.10, which includes examples of trapping onClick and onMouseOver events from links. It also includes a script that uses the document.links array to write a list of all of the links on the page. Examples of using a javascript:xxx replacement for a URL in a link can also be found in listing 8.2, which uses linked images as buttons.
Listing 8.10 Event Processing for the Link Object <HTML> <HEAD> <!- Created 09 Feb 1996 a2:45 AM 02:45 AM --> <TITLE>What's Your Link</TITLE> <SCRIPT> function checkOut() { a = (confirm("This file is 10 megs in size. It will take 2 hours ¬ to download it. Are your sure you want to do that at ¬ this time?")) if (a == true) { alert ('loading file...') } else { alert('NOT loading file!') self.location = self.location } } function enhance(what) { astr = what.href self.status = 'Click here to go to a page of backgrounds.' } </SCRIPT> </HEAD> <BODY> <TABLE ALIGN=RIGHT WIDTH=250 BORDER=1> <TR><TD> <FONT SIZE=7 COLOR= "darkcorel"> <CENTER>What's Your Link</CENTER> </TD></TR></TABLE> <FONT SIZE=5 >Example 9</FONT><BR> This page demonstrates onClick and mouseOver events for links <HR> <H3><BR><HR><BR></H3> <TABLE ALIGN=LEFT BORDER WIDTH=250> <TR><TD> <A HREF='C8-8.HTM' onMouseOver='enhance(this)'> <IMG WIDTH=100 HEIGHT=100 VSPACE=2 HSPACE= 2 ALIGN=Left ¬ SRC="Images/grkaleid.jpg"> <CENTER><FONT SIZE=5>Enhanced Status</FONT></CENTER></A> </TD></TR></TABLE> This Linked image has an onMouseOver event in its Link tag. This event appears to be fired twice, once when the mouse passes into the boundary of the image and once when it passes out. Move the mouse SLOWLY to see the effect of the event handler.<BR CLEAR ALL> <H3><BR></H3> <TABLE ALIGN=LEFT BORDER WIDTH=250> <TR><TD> <A HREF='C8-9.HTM' onClick='checkOut()'> <IMG WIDTH=32 HEIGHT= 50 VSPACE=2 HSPACE= 2 BORDER=2 ALIGN=Left ¬ SRC="Images/answer_u.gif"> <CENTER><FONT SIZE=5>File Information</FONT></CENTER></A> </TD></TR></TABLE> This onClick routine asks you if you want to load a very large file. ¬ <FONT SIZE=4 COLOR='red'> </FONT> <BR CLEAR ALL> <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> <SCRIPT> k = document.links.length document.write('This page has ' + k + ' links. They are: <BR>') for (i = 0 ; i < k ; i++) { document.write(i + ' ' + document.links[i] + '<BR>') } </SCRIPT> </HTML>
Anchors consist of text or images in your document that are marked, usually named, and can be referenced by a link within the same document (known as a local link). The document object has an anchors array, but at this time its use is quite limited. You can find out how many anchors are on the page using the length property. The property arrays anchors[i].value or anchors[i].name can be accessed without error, but will also be empty.
Dynamic documents created using JavaScript provide all the functionality of static documents written in HTML. If you can write it in HTML, you can write it on-the-fly in a document script. In fact, you can write your whole document in a script. You have already seen an example of this in listing 8.8, which converts document properties into a formatted area that can be placed at the beginning of any document you write. You can also have a script after the <BODY> tag that writes a document footer in a similar fashion.
Unfortunately, you cannot change anything on your current page once the document is finished. If you want to write to the current document, you have to open it and write to it via scripts placed at the beginning and end of the document. You can also choose to rewrite the entire document.
Using the document.write method is like printing on a dot matrix printer: it is top down only. This makes it particularly hard to do graphing or other innovative work that requires accurate positioning of objects on the page because you cannot know in advance where they will end up.
You must also be careful when enclosing an HTML statement within a document.write clause. This innocent statement will give you at least one error:
Document.write('<FONT SIZE=5 COLOR='red'>Mozilla is GREAT!</FONT>')
Many HTML parameters need to be quoted, and it is much easier to use single quotes than double quotes. Unfortunately, the write statement above will terminate with the leading quote of 'red'. The closing parenthesis of the write statement will not be found, and an error will occur. The problem is easily fixed in this case: just use double quotes around the word "red".
But what do you do if there is a need for a third level of nested quotes? Take this HTML statement for example:
<INPUT TYPE='radio' NAME='mycolor' VALUE='red' onClick='Alert("You chose red!")'>
This statement already has nested quotes. If you want to enclose this within a document.write() clause, you have two choices:
document.write(<INPUT TYPE="radio" NAME="mycolor" VALUE="red" onClick="Alert(\"You chose red!\")">
astr = "You chose red!" document.write(<INPUT TYPE="radio" NAME="mycolor" VALUE="red" onClick="Alert(astr)">
If you have more than three levels of quotes, then you must use the second option.
The "Variables and Values" section of Chapter 2 gives the basic rules for string quoting.
To provide a canvas for yourself to write on, use the document.open() command. It is a good idea to precede this with a document.close() command as a safety precaution, in case there is already a document open. You can open or reopen a document in the current window or any window for which you have a reference. Opening a document in that window clears anything that is already there. Once the document is open, you can write to it.
If you issue a document.open() command from within a script in the current page and it is not preceded by a window reference, the current page will be opened. Whatever is on the page is gone! This can be quite a surprise. Don't worry. You can recover the page with a reload, but your users might not know that. Check all document.open() references carefully.
A document is open until you specifically close it or until the browser runs out of things to write on it. When you first open a window, the document associated with that window is also opened. You can then write to it with a header script. Then the browser writes all of the body, if there is one, and anything it finds in the footer script, if there is one. When it reaches the end of the HTML text, it automatically closes the document. Note that if you open a new window with myNewWin = self.open('', 'NewWin'), you do not have to issue a document.open(). Just start writing on the blank page.
We have already noted some items to be careful of in using document write statements. If you try to write to a document that is not open, nothing will happen. No error will occur-the command will simply fail. You can write anything to a nascent document, including scripts. If you are creating a window from scratch, then you have to write everything. Listings 8.1 and 8.2 at the beginning of this chapter illustrate this approach.
TROUBLESHOOTING
I opened a fresh document using document.open(), wrote to it for quite a long time using document.write(), and nothing happened. Where did I go wrong? Document.write() places all of its output into an ASCII stream. Think of it as one big string that exists somewhere in memory. The browser does not get to interpret the stream until you specifically say, "That's all, folks!" with a document.close(). Once you close the document, everything that you have written (hopefully) is rendered in the browser window. This also means than any script errors will not be noticed until the document is actually closed.
If you examine listing 8.9, you see that this document is written totally within the header. Let's revisit this document and add a little to it. Suppose that you have a number of images that have the same prefix and differ only in a final numerical suffix. Let us also suppose that these numbers are sequential. With a very little JavaScript, you can dynamically generate the image citations and write them to the page.
Listing 8.11 takes this approach. The for loop is particularly worthy of close examination. It keeps adding citation information to a continuously growing string. When it is finished, it uses one document.write() statement to put the string on the document stream. There are several reasons to use this type of an iterative construct:
Listing 8.11 Generating an Entire Document in JavaScript <HTML> <HEAD> <!- Created 08 Feb 1996 a11:32 PM 11:32 PM --> <TITLE>Writing a Document with JavaScript</TITLE> <SCRIPT> document.bgcolor = 'linen' document.text = 'darkslateblue' document.link = 'coral' document.vlink='peach' document.alink='red' document.write('<TABLE ALIGN=RIGHT WIDTH=350 BORDER=1>') document.write('<TR><TD>') document.write('<FONT SIZE=7 COLOR= "indianred">') document.write('<CENTER>' +document.title + '</CENTER>') document.write('</TD></TR></TABLE>') document.write('<BR>') document.write('<LEFT>') document.write('This page is an example of a document written ¬ completely within a script. The reference for each image is ¬ generated dynamically') document.write('</LEFT>') document.write('<BR CLEAR ALL>') document.write('<HR>') bstr = 'BLACE' kstr = '' for (i = 1 ; i <= 10 ; i++) { var xstr = bstr + i + '.jpg' kstr += '<IMG SRC=\"NewImages\/' + xstr + '" ' kstr += 'HEIGHT=100 WIDTH=100 VSPACE=5 HSPACE=5 BORDER=2 ALIGN=LEFT>' kstr += '<H3><BR><H3>' kstr += '<CENTER><FONT SIZE=4 COLOR="coral">' + xstr ¬ + '</FONT></CENTER>' kstr += '<HR><BR CLEAR ALL>' } document.write(kstr) document.write('<BR><HR><BR>') document.write('This document was last modified on<BR> ¬ <FONT COLOR="red"><B>' + document.lastModified + '</FONT><BR>') document.write('<BR><HR><BR>') document.write('</B></CENTER>') document.write('') </SCRIPT> </HEAD> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
There are many reason why you might want to rewrite your page dynamically. You may want to try out various background images and colors, for example. There are two steps to this process: obtaining (or generating) the current information that you will modify, and also saving that information somewhere. Obtaining the information is easy. Storing and retrieving it is not because JavaScript does not enable you to read or write files (another security restriction).
One approach is to use a form and submit that form with no action listed. This places the form's parameters in the search property of the location object. This requires quite a bit of parsing, though. We have already seen in listing 8.7 that you can write your own location.search string. This approach is often simpler than using submit-with its awkward results-provided that you have no escaped characters and are able to process the parameters in order. Listing 8.12 shows an example of this. It can be easily extended to include a number of different items. In fact, you can build a simple page with it.
Listing 8.12 Using JavaScript to Dynamically Rewrite a Document <HTML> <HEAD> <!- Created 08 Feb 1996 a6:10 PM 06:10 PM --> <TITLE>Dynamic Modification of Documents</TITLE> <SCRIPT> function reloadMe() { self.location = self.location astr= self.location.pathname + '?' astr += document.forms[0].aname.value + '*' astr += document.forms[0].mytext.value + '*' astr += document.forms[0].mylink.value + '*' astr += document.forms[0].myvlink.value + '*' astr += document.forms[0].myimage.value + '*@' self.location = astr } function clearUp() { self.location = self.location.pathname } function doTC(what) { what.form.mytext.value = what.value } function doLC(what) { what.form.mylink.value = what.value } function doVC(what) { what.form.myvlink.value = what.value } function doImage(what) { document.forms[0].myimage.value = 'DBLACE' + what + '.jpg' } function doname(what) { what.form.aname.value = what.value } function createArray(n) { this.length = n return this } function arrayParms(astr) { var k = astr.length astr = astr.substring(1,k) var n = 0 var a = 1 var i = 1 var counter=0 while(a > 0) { a = astr.indexOf('*',n) var bstr = astr.substring(n,a) if (bstr != '@' && counter <10 ) { parms[i] = bstr n=a+1 i++ } else a = 0 counter++ } } var parms = new createArray(5) var astr = location.search arrayParms(astr) astr = '<BODY BACKGROUND = "Images/' + parms[5] + '" ' astr += 'TEXT="'+ parms[2] + '" ' astr += 'LINK="'+ parms[3] + '" ' astr += 'VLINK="'+ parms[4] + '" ' astr += 'ALINK="red" ' astr += '>\n' document.write(astr) document.write('<TABLE ALIGN=RIGHT WIDTH=350 BORDER=1>') document.write('<TR><TD>') document.write('<FONT SIZE=7 COLOR= "indianred">') document.write('<CENTER>' +document.title + '</CENTER>') document.write('</TD></TR></TABLE>') document.write('<LEFT><B>') document.write('This page is an example of dynamically revised by ¬ a header script which acts on information stored in the command ¬ line. That information is based on user\' choices.') document.write('</B></LEFT>') document.write('<BR CLEAR ALL>') document.write('<HR>') astr ='<CENTER><FONT SIZE=7 COLOR="' + parms[3] + '"><B> ' astr += parms[1] + '</B></FONT></CENTER>' document.write(astr) document.write('<HR><BR>') </SCRIPT> </HEAD> <CENTER> <FORM NAME=nameForm> Enter your first name here:<BR> <INPUT TYPE=text NAME=myname SIZE= 20 ¬ onChange='doname(this)'><H3><BR></H3> <CENTER> <TABLE ALIGN=LEFT WIDTH=100 BORDER CELLPADDING=5> <TR ALIGN=LEFT><TD> <CENTER><B>Text</B></CENTER> <INPUT TYPE="RADIO" NAME="tc" VALUE='white' ONCLICK='doTC(this)'>white <INPUT TYPE="RADIO" NAME="tc" VALUE='yellow' ONCLICK='doTC(this)'>yellow <INPUT TYPE="RADIO" NAME="tc" VALUE='navy' ONCLICK='doTC(this)'>navy <INPUT TYPE="RADIO" NAME="tc" VALUE='blue' ONCLICK='doTC(this)'>blue <INPUT TYPE="RADIO" NAME="tc" VALUE='orange' ONCLICK='doTC(this)'>orange <INPUT TYPE="RADIO" NAME="tc" VALUE='red' ONCLICK='doTC(this)'>red <INPUT TYPE="RADIO" NAME="tc" VALUE='black' ONCLICK='doTC(this)'>black </TD></TR></TABLE> <TABLE ALIGN=LEFT WIDTH=100 BORDER CELLPADDING=5> <TR ALIGN=LEFT><TD> <CENTER><B>Link</B></CENTER> <INPUT TYPE="RADIO" NAME="lc" VALUE='white' ONCLICK='doLC(this)'>white <INPUT TYPE="RADIO" NAME="lc" VALUE='yellow' ONCLICK='doLC(this)'>yellow <INPUT TYPE="RADIO" NAME="lc" VALUE='navy' ONCLICK='doLC(this)'>navy <INPUT TYPE="RADIO" NAME="lc" VALUE='blue' ONCLICK='doLC(this)'>blue <INPUT TYPE="RADIO" NAME="lc" VALUE='orange' ONCLICK='doLC(this)'>orange <INPUT TYPE="RADIO" NAME="lc" VALUE='red' ONCLICK='doLC(this)'>red <INPUT TYPE="RADIO" NAME="lc" VALUE='black' ONCLICK='doLC(this)'>black </TD></TR></TABLE> <TABLE ALIGN=LEFT WIDTH=100 BORDER CELLPADDING=5> <TR ALIGN=LEFT><TD> <CENTER><B>VLink</B></CENTER> <INPUT TYPE="RADIO" NAME="vc" VALUE='white' ONCLICK='doVC(this)'>white <INPUT TYPE="RADIO" NAME="vc" VALUE='yellow' ONCLICK='doVC(this)'>yellow <INPUT TYPE="RADIO" NAME="vc" VALUE='navy' ONCLICK='doVC(this)'>navy <INPUT TYPE="RADIO" NAME="vc" VALUE='blue' ONCLICK='doVC(this)'>blue <INPUT TYPE="RADIO" NAME="vc" VALUE='orange' ONCLICK='doVC(this)'>orange <INPUT TYPE="RADIO" NAME="vc" VALUE='red' ONCLICK='doVC(this)'>red <INPUT TYPE="RADIO" NAME="vc" VALUE='black' ONCLICK='doVC(this)'>black </TD></TR></TABLE> </CENTER> <BR CLEAR ALL> <HR> <CENTER><FONT SIZE=4>Click on the image that you want for a ¬ background.</FONT></CENTER> <H3><BR></H3> <A HREF='javascript:doImage(1)'> <IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="Images/DBLACE1.jpg"></A> <A HREF='javascript:doImage(2)'> <IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="Images/DBLACE2.jpg"></A> <A HREF='javascript:doImage(3)'> <IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="Images/DBLACE3.jpg"></A> <A HREF='javascript:doImage(4)'> <IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="Images/DBLACE4.jpg"></A> <A HREF='javascript:doImage(5)'> <IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="Images/DBLACE5.jpg"></A> <BR CLEAR ALL> <HR> </CENTER> <TABLE ALIGN= RIGHT WIDTH=300><TR ALIGN=RIGHT><TD> Name: <INPUT TYPE=text NAME=aname ><BR> My Image: <INPUT TYPE=text NAME=myimage ><BR> My Text: <INPUT TYPE=text NAME=mytext ><BR> My Link: <INPUT TYPE=text NAME=mylink ><BR> My VLink: <INPUT TYPE=text NAME=myvlink ><BR> </TD></TR></TABLE> <INPUT TYPE=button NAME=reloadBtn VALUE='Rewrite Page' ¬ onClick='reloadMe()'> <INPUT TYPE=button NAME=clearBtn VALUE= 'Clear' onClick='clearUp()'> <INPUT TYPE=hidden NAME=hideFld > </FORM> <HR> Click on Netscape's reload button before you click on the Rewrite ¬ Page button. <H3><BR><HR><BR></H3> <H3><BR><HR SIZE=5 WIDTH=80%><BR></H3> </BODY> </HTML>
This page illustrates the following points that we have touched upon before:
Figure 8.4 shows the result of loading this page (only the top part of the page is shown). The page starts out in the default Netscape colors. It gives the user the opportunity to select text and link colors, and a background tile. The user is in the process of selecting a tile.
Fig. 8.4 A dynamically rewritten page stores information for use in the next rewrite operation.
This script does several things that are worth noting, as follows:
Figure 8.5 shows all the choices being placed in the summary form as the user clicks and enters text. Figure 8.6 shows the browser window after it has been rewritten dynamically to use the colors and tiles chosen by the user. Note that the summary form's contents have been added to the command line.
Fig. 8.5 Dynamic documents may modify their own appearance under user control.
Fig. 8.6 Dynamic documents can rewrite their own background.
You can write to any page that appears in your window hierarchy. You cannot write to a page that is not a part of that hierarchy. Consequently, a parent can write to a child window and a child can write to its parent. If you want a parent window to write to a newly created child window, then you need to keep a handle to that window. The window.open() method returns such a handle; you should store this value as a global variable. It can then be used subsequently to access the child. If you do not use a global variable, then you will not be able to access the child window from any function other than the one that created it.
Let's examine the very first complete example in this chapter (listing 8.2) again now that you have more knowledge and experience. The parent window has two buttons, one to open the window and one to close it. These buttons call the parent windows' functions, openNote() and closeNote(), respectively. The parent stores the handle to the openNote window in the global variable, aNoteWin. The responsibilities of the open routine are as follows:
The open routine also exemplifies a common and useful time saving practice, known as aliasing. The full hierarchical representation of aNoteWin's document (self.aNoteWin.document) is collected in the short and easy to write variable, known as ndoc.
Finally, it is worth pointing out the utility of having the child window's Close button in the parent window, especially if the child window is small. The open() method will not create a second window of the same name, although it can do some updating if you make a second open() call with different parameters. If you click the Make Note button and nothing happens, it is possible that you did not get rid of the last window you made.
Murphy's Law dictates that the forgotten child will be at the very bottom of the eight other large windows on your screen. Being able to close the window from the parent is a great time saver and an excellent debugging tool.
In this section, we will write a simple text graph using an approach similar to that described in the section, "A Page Generated Entirely by JavaScript." We will provide entry fields on a form in which the user can enter some numbers. We will then use those numbers to dynamically generate the text graph using Xs. Because we need to keep the size of the graph such that it will fit on the display, we will check all of the input in the form. Figure 8.7 shows the initial appearance of the form.
Fig. 8.7 The text graph page enables the user to enter data that will be graphed.
Data is entered into the form on the right. Up to 10 numbers can be added. As the data is entered, the program automatically does summary statistics. This is really useful if you want to see whether data outliers can be gracefully thrown away. (Data outliers are elements which are very far away from all other elements, such as 1000 in the sequence 1,3,1000,19,-4.) Once the data is entered, the user has the option of drawing the graph.
There are several points to examine in this example. The first thing to notice is that data is parsed and saved in exactly the same way as the previous example. Second, the code that draws the graph is conditional on location.search being non-empty. If no parameters have been added, then no graph is displayed; instructions are given instead.
As the user enters data, it is checked to see whether it falls within an acceptable range. As this is done, cumulative statistics are also kept. These are presented in a table adjacent to the data itself. Finally, if the location is reset, then all the fields in the form are cleared. This approach is much more polite than using Netscape's Reload button. Note that a footer script is used to reload the data fields. Figure 8.8 shows the result after user input has been entered and a graph drawn.
Fig. 8.8 Numerical data may be converted to a text graph using dynamic documents.
|