Copyright ©1996, Que Corporation. All rights reserved. No part of this book may be used or reproduced in any form or by any means, or stored in a database or @retrieval system without prior written permission of the publisher except in the case of brief quotations embodied in critical articles and reviews. Making copies of any part of this book for any purpose other than your own personal use is a violation of @United States copyright laws. For information, address @Que Corporation, 201 West 103rd Street, Indianapolis, IN 46290 or at support@mcp.com.

Notice: This material is excerpted from Special Edition Using JavaScript, ISBN: 0-7897-0758-6. This material is provided "as is" without any warranty of any kind. Please see this DISCLAIMER.

Chapter 8

Dynamic HTML and Browser Objects

by Mark Reynolds

This chapter describes the creation of dynamic documents and windows as well as the interaction between windows and their components. Before you begin this chapter, you might want to reread the section on "Browser and HTML Objects" in chapter 4. This chapter presumes that you now have a working knowledge of Javascript syntax; the material covered is somewhat more complex than in earlier chapters.

The first theme of the chapter will be the creation of @popup windows. The entire content of those windows will be defined by a creation function, rather than a URL. We will examine various examples, including popups with text, popups with buttons, and editable popups.

We will next examine the history, status and location objects. We will see how we can create a hurl the user to a specific URL on the history list, how to examine the various part 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, we will create a page entirely from JavaScript. We will also learn how to rewrite pages on the fly.

At the end of this chapter you will be able to:

Javascript Object Hierarchy

We have already learned a lot about objects in JavaScript. In fact, this 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 which JavaScript provides. In order to go @furtherand explore dynamic @HTML creation we must firsttake a closer look at the hierarchy of objects in JavaScript.

If you are familiar with any object oriented languages, you will expect an object Hierarchy to begin with a generic object from which all other objects are descendents 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 which 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 in order 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 which 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.

Browser 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, scrollbars, 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 allows 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 which the window contains) at any time. Table 8.1 lists these various elements, when they may be modified, and how they may be modified. It should be noted that the last two items in this table are not really 'window"elements. They control what is displaye, but are not explicitly displayed themselves.

Table 8.1 Modification rules for JavaScript controls
Object
When
How
Rewrite?
Button Barwindow creationYes/No NA
Menuwindow creationYes/NoNA
Location Displaywindow creationYes/No NA
Status Barwindow creationYes/No NA
Historywindow creationYes/NoNA
Documentduring rewriteComplete NA
Many form Any timeCompleteNo
element properties
Status bar contentAny timeComplete No
LocationAny timeCompleteYes
History ListAny timeCompleteYes
Pointer

Dynamic Window Creation

One of the more advanced projects later in this book is the creation of a 'sticky notes' application. In order to do that, we will need to have a small note window in which to present the note. Let's create a primordial note window now. In order to do that, you must already have a window open with an element which will allow you to call a Javascript function. The base window will be 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 script control, the next window which is created by the navigator will have the same dimensions as the last window created by JavaScript.

The element which we will use will be an image which will behave as a button, which will betriggered by a 'HREF=Javascript:@myfunc' included in the link tag. This works very well if you need call only one function and you need no return value. When you try to use this mechanism in a window which you have constructed on the fly, however, the image refuses to display. In fact, any image which uses relative addressing refuses to display in a dynamic window. The solution is to either use a complete @static reference for the image or to set the base @directory of your page with <BASE>path</BASE> in the header. This latter approach will help @JavaScript find the image. If you need an object which 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.

Three steps are necessary in to or use an image as a button to execute a @Javascript function. First we must write an appropriate HTML declaration for the desired image. Next, we must enclose this HTML declaration within reference tags. Finally, we must resolve the HREF to a JavaScript function declaration. 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/book/gobtn.gif" BORDER=0>

<A HREF='xxxxxx'><IMG WIDTH=23 HEIGHT= 22 VSPACE=2 HSPACE= 2 ALIGN=LEFT SRC="images/book/gobtn.gif" BORDER=0><A>

<A HREF='Javascript: openNote'><IMG WIDTH=23 HEIGHT= 22 VSPACE=2 HSPACE= 2 ALIGN=LEFT SRC="images/book/gobtn.gif" BORDER=0><A>

The function used in this example is the openNote() function, the source for which is given below. Before we plunge into this code, it is worthwhile to notice that the border has explicitly been set to 0. This is the only way you can keep Navigator for 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. Note that it has been placed in a table to make it look neater. 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 will just update the first one.

Listing 8.2 The Complete Source for 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 tobear in mind.
  1. You only need the first two parameters (the URL, which can be empty, and the window name) to open a window. If you do not include the third paramater, the window attributes list, then the window will have all of its window attributes set to yes (present).
  2. If you specify anyof the windows attributes, then you must include the whole list of attributes. Otherwise the results will be unpredictable.
  3. Enclose the attributes list in quotation marks, separate the items with commas, and do not leave spaces.

Fig.8.1

Your first dynamically created window in Javascript.

This small script illustrates several points. First, you can set a window global by defining it outside of any function and preceeded it with var. Here we set the window global aNoteWin with

var aNoteWin

This variable is global so that we could use it to refer to aNoteWin in other functions. Although we did not do so here, we 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 which you create can be a 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; we will discuss this in a later chapter. All the @display elements are neatly wrapped in a table.

Listing 8.3 (C8-1.htm) 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

}

Window Status

Netscape keeps you appraised of which link or button your cursor 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 it 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 (c8-2.htm) 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 workaround 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/book/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/book/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/book/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="images/book/okbtn.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 @Table Overlays, which will be discussed later, and an onLoad() handler which provides a workaround for @Netscape's unpredictable order of drawing images.

The status window is created with a 'Javascript: openStatus(defMsg,msg)' link attached to an image. This function openStatus(defMsg, msg) performs several 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 in order to bring the window to the front. This is done by a call to the setFocus() method.

Finally, we close the window with an Image link Javascript call to close(). Close simply closes aStatWin and makes sure that its value is reset to null.

The function fixup() is worth looking at in more detail.

The order in which Netscape draws images depends upon where the images are coming from, whether they are in the cache, and whether their height and width are given explicit. It may also depend on the size of the images. Extremely attractive presentations can be made by overlaying text and @graphics over other @graphics via a feature of @Netscape tables. However, Netscape will invariably draw your bottom image last when the page first loads. Scrolling the screen will cause 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 does to insure that all of the IMAGE buttons are visible. While this is far from an ideal solution, it is effective.

Always check that a newly createdwindow exists before you try to use address its properties or methods. Do this by checking to see if the window is null. If it is null use alert to inform the user.

Fig 8.2

A status bar window created dynamically by the parent window.

The Location Object

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 will also contain any post parameters of a 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, andfile (for files on the local dist). 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 which the browser will display. Search includes any post parameters which 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.

Finding out Where You Are

This next example is a page which has no body. It is written entirely by the header script. As the page writes, it dissects the location object and lists all of its properties in a table. In order to see a non-empty location.search, you will have to submit the little form included after the table. To see a non-empty location.search, click on 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 (C8-3.htm) 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>

Sending the User Elsewhere

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 (C8-4.htm) Modifying the Current URL

<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 work by first obtaining the current location. It then strips off the file name and replaces it with the value of the @radiobutton 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 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.

Using the Search Property

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 '?' The value of Location.search is precisely that string, including the '?'. 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 '&'. Any non-alphanumeric characters are coded or escaped. The @ASCII value of the character is changed into a two digit @hex number preceded by %. If text field or @textarea elements have multiple words, these words are separated by '+'. Consequently, when you get the Location.search string, you have to decode it to get the various form elements which it contains

You can place your own form element values, or anything else, in the location's search property. As long as you precede it with '?', location.search will retrieve it. However, not all non-alphanumeric characters may 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 which 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 which are used later, you will encounter error after error.Always test for a null string of empty string.

The code in @Listing 8.7 has two useful functions. Clear() 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

The @history object is a list which contains the locations of all the URL's which 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,the number of items in the list. You can neither set nor retrieve history list items.

In order to show how to manipule of the history list, we will build another popup window which boasts only a close button and four directional buttons. The buttons allow 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 (C8-6.htm) Using the History Object in a Popup 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=&lt;&lt; onclick="goStart()">'

     astr +='<INPUT TYPE="button" NAME="backBtn" VALUE=&lt; onclick="goBack()">'

     astr +='<INPUT TYPE="button" NAME="nextBtn" VALUE=&gt; onclick="goNext()">'

     astr +='<INPUT TYPE="button" NAME="endBtn" VALUE=&gt;&gt; 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 @popup is a variation on our old friend, aNoteWin. It can access its parents 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 aNoteWinThis allows use to have ready access to the parent @window's variables, functions, and objects.

SecurityAspects of JavaScript 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. If it did, a script from one window might reach into another unrelated window and scavenge information form 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

The document object encapsulated all @JavaScript objects which 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]. 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 are useful only when building a document. Four properties which 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 way in which 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>

Forms

You can get input from your users via 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 @dropdown list or a plain list, and a @textarea widget which can be used to collect large amounts of text spanning multiple lines.

Listing 8.10 is a page with several forms on it. This page demonstrates the interaction of form elements. It also has a script which @iterates through all of the forms in the document and prints out their element names and values.

A script can only access elements which have been created. They may not be accessd in a document <HEAD> since the forms and their elements will have yet exist.

Links

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 in which you can 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()', will immediately close the current window.

A Javascript:xxx call replaces a URL. The browser will try to interpret any return from the function call in that fashion. If the browser does not understand the return value, it will reload the current page. When that occurs, any window globals which you set as 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 on 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, since you cannot replace images dynamically, you cannot modify the appearance of thie 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 cursor 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 will find that if you move your mouse to quickly you will 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 write 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 '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.

Fig8.3

MouseOver is only fired when the cursor enters or leaves the linked object.

Listing 8.11includes examples of trapping onClick and onMouseOver events from links. It also includes a script which 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 be found inListing 8.2, which uses linked images as buttons.

Listing 8.11 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'>Note to MME:  abort does not
work. Checking  it out.  Remember to fix.</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

Anchors consist of text or images in your document which 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 may be accessed without error, but will also be empty.

Dynamic Documents

Dynamic documents created using JavaScript provide all the functionality of @static documents written in @HTML. If you can write it in HTML your can write it on the fly in a document script. In fact, you can write your whole document in a script. We have already seen an example of this in Listing 8.8, which converts document properties into a formatted area which can be placed at the beginning of any document which you write. You can also have a script after the <BODY> tag which will write a document footer in a similar fashion.

Restrictions on Document.Write

Unfortunately, you cannot change anything on your current page once the document is finished. If you want to write to the current document, you will 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 which requires accurate positioning of objects on the page, since 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:

HTML :  <FONT SIZE=5 COLOR='red'>Mozilla is GREAT!</FONT>

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 wish 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.

Using Nascent Documents

In order 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. 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 which 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 will also be opened. You can then write to it with a header script. Then the browser will write 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 which 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 will have to write everything. The first two examples 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 which 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 which you have written (hopefully) will be rendered in the browser window. This also means than any script errors will not be noticed until the document is actually closed.


A @Page Generated Entirely by JavaScript

If you examine Listing 8.9 of this chapter, you will see that this document is written totally within the header. Let's revisit this document and add a little to it. Suppose that we have a number of images which have the prefix, and differ only in a final numerical suffix. Let us also suppose that the numbers are sequential. With a very little Javascript we can dynamically generate the image citations and write them to the page.

Listing 8.12 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.12 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>

Dynamicaly Rewriting Your Page

There are many reason why you might wish to rewrite you page dynamically. You may want to try out various background images and colors, for example. In order to do to obtain the current information which you will be modifying, and also save that information somewhere. Obtaining the information is easy. Storing and retrieving it is not because Javascript does not let you read or write files (another security restriction).

One approach is to use a form and submit that form with no action listed. This will place the form's parameters in the search property of the location object. This requires quite a bit of parsing, though. We have already shown in Listing 8.7 that you can write your own location.search string. This approach will often be simpler than using submit, with it awkward results, provided that you have no escaped characters and are able to will process the parameters in order. Listing 8.13 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.13 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 = "NewImages/' + 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="NewImages/DBLACE1.jpg"></A> 

<A HREF='Javascript:doImage(2)'>

<IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="NewImages/DBLACE2.jpg"></A> 

<A HREF='Javascript:doImage(3)'>

<IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="NewImages/DBLACE3.jpg"></A> 

<A HREF='Javascript:doImage(4)'>

<IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="NewImages/DBLACE4.jpg"></A> 

<A HREF='Javascript:doImage(5)'>

<IMG WIDTH=100 HEIGHT= 100 VSPACE=5 HSPACE= 5 BORDER=2 ALIGN=Left SRC="NewImages/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 several points which we have touched upon before. It uses a script in the document HEAD to write to the document as it is being created. It dynamically changes the location.search string to store parameter information. Finally, it uses that information during the next rewrite operation to pick up where it had previously left off. Figure 8.4 shows the result of loading this page. The page starts out in the default Netscape colors. It gives the user the opportunity to select text and link colors, a background tile, and a caption. The user is in the process of selecting his chosen tile.

Fig8.4

A Dynamically Rewritten Page Stores information for use in the next rewrite operation.

This script does several things which are worth noting. First, it creates a global array named parms. It does not bother to initialize the array because the program knows which parts of the array it is going to use later. Second, it has a simple routine named reloadMe() to gather up all of the form elements and write them to the location object. Third, it has a simple parsing routine named arrayParms() to dissect location.search and place the pieces in an array. Fourth, its header script acts on the information provided by the user to dynamically reconstruct the page. 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.

Fig8.5

Using the Rewrite Page to Enter Text.

Fig8.6

The @Rewrite Page after the User has made some Choices.

You can write to any page which appears in your window hierarchy. You cannot write to a page which 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 you need to keep a handle to that window. window.open() returns such a handle; you should store this value as a global variable. It may 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 which created it.

The openNote() @Script Revisited

Let's examine the very first in this chapter again now that we 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 storesthe handle to the openNote window in the global variable aNoteWin. The responsibilities of the open routine are to:

The open routine also exemplifies a common and useful time saving practice, known as aliasing. The full hierarchichal respresentation of aNoteWin's document (self.aNoteWin.document) is collected in the short and easy to write variable @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 on 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 timesaver and an excellent debugging tool.

Writing a Text Graph

In this @sectionwe will write a simple text graph using an @appraoch similar to that of "@A Document Generated Entirely in JavaScript". We will provide entry fieldson a form where the user can enter some numbers. We will then use those numbers to dynamically generate the text graph using X's. Because we need to keep the size of the graph so that it will fit within a, we will check all of the input in the form. This code will be found on the CD-ROM with @Special Edition Using JavaScript, in file TextGraph.htm. Figure 8.7 shows the initial appearance of the form.

Fig8.7

The @Text Graph generate allows the user to enter data which will be graphed.

Data are entered into the form on the right. Up to 10 numbers can added. As the data are entered, the program automatically does summary statistics. This is really useful if you want to see whether data outlier can be gracefully thrown away. Once the data are entered, the user heas 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 which draws the graph is conditional on location.search being nonempty. 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 if 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 will be 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.

Fig8.8

When data enter is complete the text graph is drawn.

Parameter Specification and Data Storage

Because Netscape is extremely security conscious, they have made it extremely difficult to store or load data, even between document reloads. We have presented one method of storing simple data between document reloads via a string saved in location.search. Scripts can get and use this information to redraw documents, as we have seen. Are there any other options?

Where to store parameters and other data

If you have a lot of data, you might appreciate having it accumulated and stored for you. You can use a submit widget or form.submit() to have the browser collect up all of your data, encode it, and store it in the command line. As we pointed out before, the output is very hard to read, and looks like scrambled text.

Another possibility is to store data in dynamic arrays in a window or, better, in the @frameset document. Unfortunately, this, too, is labile. If you have database like data, it must all be hand coded into the document which will host it, although you could use an @HTML builder or other @programming tool to automatically create the @HTML document.

The only possibility which offers any permanence is @Netscape Cookies. Cookies are lines in a file which Netscape will allow you to write to disk. You can see your cookies in the file, 'cookies.txt' in your Netscape directory/folder. Cookies are limited in size and number. Nevertheless, cookies are extremely useful. There are frequently used in the same was as you a Windows ini file, a Mac Preferences file, or a Unix .@rc file The next two subsections will examine both the command line approach and the cookie approach.

Command Line Giberish Parameters

Using the submit() routine to store form field values in the command line leads to a location which looks like this:

?myname=Mona+M.+Everett%2C+Ph.D.&tc=navy&lc=blue&vc=orange&aname=Mona+M.+Everett%2C+Ph.D.&myimage=DBLACE4.jpg&mytext=navy&mylink=blue&myvlink=orange&myurl=http%3A%2F%2Fwww2.best.com%2F%7Edsiegel%2Ftips%2Ftips_home.html%22&cmmt=Welcome+to+my+little+home+page+builder.++There%27s+no+tellin%27+just+how+much+this+page+can+be+expanded.++What+do+you+think%3F%0D%0A&subbtn=Submit

If you examine this output, you may be able to discern some patterns. First of all, it begins with the characteristic '?' character which delinerates the location.search string. Second, most of the information seems to occur in pairs, with the field name as the @lefthand member and the field value as the @righthand member. The pairs are separared by the character '&'.

There are absolutely no spaces in this output. Every space has been replaced by the '+' character. As we mentioned much earlier in this chapter various escape sequences containing the '%' character occur in this string. These sequences are used to encode nonalphanumeric characters in the input. In particular, any punctuation has been replaced by such a sequence.

Javascript does not give you a lot of tools with which to dissect this sequence. Let's see how we can use the ones we have.First, there are a pair of built in functions to handle the escape sequences. These are escape(), which will take a non-alphanumeric and hand you back the coded sequence, and unescape(), which reverses the process. Second, we can use the substring method of the String object to 'walk' through a string. A statement of the form

     myString.substring(start,stop)

extracts all the characters starting from position start and ending at the last character just before the position stop. This allows us examine each character in the string one at a time, if we wish. Based on the character encountered, we can replace it or take some action.

The file C8-13.htm on the CD-ROM with Special Edition Using JavaScript has two functions which use this approach. The first one, which decodes the command line search string, provides the core of the page rewrite code. The second changes all of the '<' and '>' to '&lt;' and '&gt;', respectively, so that you can write out HTML to the page. This function is not actively called in the page but is used for @writeline debugging. The latter function is also really useful if you want to write HTML dynamically to your page to show your user how to do something.

Let's examine the function which decodes the command line search string, arraySubParms(). It is shown in Listing 8.14. In order to use it, you must first have created and initiated the parms array using a function such as this:

function createArray(n)

{

     this.length = n

     for (i=1 ; i <=n; i++)

     this[i] = ''

     return this

}

The @parms arrays must not only be created, it must also be initialized before you use it. The function createArray() does this for you. The array must be declared as a global variable with the statement '@var parms = new createArray[10]'

Listing 8.14 (c8-13.htm [extract]) Extracting command line information

function arraySubParms(astr)

{

     k = astr.length

     astr = astr.substring(1,k)

     lstr = ''

     rstr = ''

     bstr = ''

     crstr = ''

     counter = 1

     for (i = 0 ; i <= k ; i++)

     {

          ccStr =''

          ccStr = astr.substring(i,i+1)

     

          if (ccStr == '+') ccStr = ' '

          if (ccStr == '%')

               {

                    var xx = astr.substring(i,i+3)

                 ccStr = unescape(xx)     

                    i += 2     

               }

          // car  

          if (ccStr == '=')

               {

                    parms[counter] = bstr

                    bstr = ''

                    continue

               }

          //right hand member of pair

          if (ccStr == '&')

               {

                    parms[parms[counter]] = bstr

                    counter++

                    bstr = ''

                    ccStr=''

                    continue

               }

          bstr += ccStr

     }

}

When arraySubParms(astr) receives a string it immediately chops off the first character, which is the '?' that starts the location.search string. It then finds the length of the string and begins a loop which will cycle through every character in the string with the statement 'cc = @astr.substring(i,i+1)'. The variable cc is then checked to see if it equal to the character '+'. If it is then that character is replaced with a space. If cc is a percent sign the function uses the substring function again to grab three characters, starting from its current position. It then uses the built-in function, unescape, to turn these three characters back into an ASCII character. Since three characters instead of one are used up, the pointer into the string, I, must be advanced by 3 with the statement 'I+=3'. In either of these two cases (+ or &) the next two conditional tests will fail and cc, which may have been modified , is added to @bstr.

The browser places all of the form element names and their values into the command line as name=value pairs. Each pair is terminated by '&'. The next two conditional tests extract the left and right members of the pair and place them into the left and right members of the associative array @parms. If the function finds that = character, it knows that bstr, which has steadily been accumulating characters, now holds the name of the element. Another variable, counter, is used to keep track of the current index into the parms array. The left member is set with the @statement'parms[counter] = bstr'. The variable @bstr is set to the empty string at this point, so that it can start accumulating characters anew. The value of counter is not advanced. A 'Continue' statement is used to bypass the rest of the loop so that the = character which was just seen is not added into the new value of @bstr.

@Javascript associative arrays are one dimensional arrays of pairs. The left and right members of a pair are set differently. Set the left member using a numberical index into the array; e.g., myArray[n] =lvar. Set the right member with an index equal to the value which you placed into the left member; e.g., myArray[myArray[n]] = rvar. You can also use myArray[lvar] = rvar if lvar has not changed between setting the left and right sides of the pair.

If the next test, for the '&' character, yields true, the function knows that it has now accumulated the right hand member of the array in bstr. It sets the right hand member with the statement 'parms[parms[counter]] = bstr.' Remember that you set the right hand member with the index as the name of the left hand member, not the index itself. The processing of the name=value pair is now complete. Again, @bstr is set to the empty string in anticipation of the next loop @interation. In this particular case, however, counter is now incremented with the 'counter++' statement.

When the function finally reaches the end of the location.search string, you will then have all of the variables in a the global parms array. You can now use them anywhere within the current window or in any window which you create.

The second noteworthy function from the c8-18.htm file is the toprint() function, which changes all occurrences of the '<' and '>' characters in any string into their corresponding control codes. This seemingly trivial operation is, in fact, very important. This is because the < and > characters are interpreted by @HTML. If you wish to write HTML to your document you must somehow prevent them from being interpreted as HTML delimiters. Converting them to control codes will do the trick. This function is very useful for debugging, or to show @HTML example code on your pages.

Listing 8.15 shows the code for this function.

Listing 8.15 (c8-13.htm [extract]) A Function to Print HTML safely

function toprint(it)

{

     var bstr=''

     var cc=''

     for(i=0; i< it.length; i++ )

     {

          cc = it.substring(i,i+1)

          if (cc == '<') cc = '&lt;'

          if (cc == '>') cc = '&gt;'

          bstr += cc

     }

     return bstr     

}

We will conclude this discuss of command line parameters by examining the remaining code from file C8-13.htm. It will use the global array you have just prepared to rewrite your page according you specifications. Listing 8.16 shows the page rewrite code itself.

Listing 8.16 File c8-13.@html [extract] Rewrite a @Web page used command line data

var astr = location.search

if (astr != null && astr != ''){ // start conditional

var parms = new createArray(12)

arraySubParms(astr)

astr = '<BODY BGCOLOR="linen" '

astr += 'TEXT="'+ parms['mytext'] + '" '

astr += 'LINK="'+ parms['mylink'] + '" '

astr += 'VLINK="'+ parms['myvlink'] + '" '

astr += 'ALINK="red" '

astr += 'BACKGROUND = "NewImages/' + parms['myimage'] + '" '

astr += '><BR>'

document.write(astr)

//document.write(toprint(astr))

} // end conditional

else document.write('<BODY>')

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>')

var astr = location.search

if (astr != null && astr != ''){ // start conditional

astr ='<CENTER><FONT SIZE=7 COLOR="' + parms['link'] + '"><B> '

astr += parms['aname'] + '</B></FONT></CENTER>'

document.write(astr)

} // end conditional

document.write('<HR><BR>')

Let us examine the operation of this script in a little more detail. There are several points worth noting. First of all, the property location.search is examined to make sure that it is not null or the empty string. If location.search does not contain a valid string then most of the script processing is skipped. Two if..else statements are used for this purpose.

After the search string has been obtained and the @parms array filled in by the call to arraySubParms(), the script starts building the BODY statement.. Note that it builds it into a string and does not write it immediately with document.write. Note, too, the commented out call to printit(), which was used during debugging to see if the string was built correctly.

Accumulate your HTML output in a string rather than using individual document.write() calls. This will facilitate debugging.

Once the string has been assembled, the <BODY...> statement, which sets the background image and colors is written to the document. If there was no search string, a plain <BODY> statement is written.

The script then writes a nice header for the document. The script next uses a second conditional clause to write your name in large letters. It had to check for the existance of a search string in order to do so. If the search string is present, you get your name; if it is absent, go get brief directions on using the page. When the header script is complete the @HTML on the page will be interpreted by the browser.

Since all the form elements may be cleared with a submit, this program is polite and restores all of them from the global parms array. Instead of writing each one separately, it iterates through the form.elements array. Remember that the array was created with the element name as the left hand member of the array. This makes it easy to get the correct variable in the form element. This could have also been done using numerical indexing. The routine shown is particularly useful if you have a large number of elements to restore.

Notice that a couple of form elements were included which were not used to construct the page. We included them here to provide a lot of escaped characters and a longer string of text with which to test the script.

The Cookie Approach

The only method you can use to store variables between invocations of Netscape Navigator is the cookie approach. This is also the only approach which will work with windows in different hierarchies. Cookies were originally designed to allow a server to save state information on the client's disk. When the client contacted that same host at a later time the previously saved cookie would be sent back to the server. Cookies are therefore useful if a browser connection is interrupted and you want to pick up where you left off. It is also useful in case the server crashes and later wishes to pick up where it left off. Cookies are now available for general use in Javascript.

Cookies have five parameters:

Only the first one, which is a the familiar name value pair, is required. All of the others are optional. However, if you do not save an expiration date, the cookie will automatically expire when you close Netscape--not something you want to happen if you want to keep information from session to session. The various parameters are separated by semicolons. If you create a cookie with the same name and path as a cookie already in existence the new one you will overwrite the existing one.

Although servers can write named cookies one at a time, Javascript cannot. You can set an individual named cookie with the statement document.cookie='cookiename=xxxx', but when you retrieve document.cookie, you will get a string consisting of all of the cookies. Currently the only way to retrieve an individual cookie is too search through the entire set of cookies obtained from document.cookie. Consequently, it helps to prefix or suffix the names of your cookies with a little-used character(s). This makes them easy to find with IndexOf().

Let's examine each of the cookie parameters in turnAs stated, the @NAME=VALUE parameter is an associative pair. This means that it lends itself nicely to being stored in arrays and placed in form elements. This is the only required element of the cookie. The expires=DATE parameters is used to describe the expiration date for the cookie. As defined by Netscape, the date format must be 'Wdy, @DD-Mon-YY HH:MM:SS GMT' , with the separators exactly as given. If you do not want persistent data between browser invocations, leave out this expiration date. If you want your cookie to never expire, give it a date several years in the future.

The path=@PATH parameter is uses to limit the search path of a server which can see your cookies. This is analagous to specifying a document BASE in an HTML document. If you use '/' then everything in the domain can use your cookies.

The @domain=DOMAIN_NAME parameter is only useful if the server is setting the cookie or, if for some reason, you want to generate a cookie which is available to the server. If the server generated the cookie, then the default domain is the @domain name of the server which generated it. Finally, the parametersecure indiceates that the cookie should only be sent if there is a secure client-server relationship.

Listing 8.16 shows the cookie versions of the routines for saving and @restoringa persistent information. In this case the information comes to and goes from the document cookie, rather than the command line search string. These routines have been liberally modified from those presented by Bill Dortch and placed in the @public domain.

Listing 8.16 c8-14.@htm Saving and Restoring document cookie information

function fixSep(what)

// escapes any semicolons you might have in your data

{

     n=0

     while ( n >= 0 )

          {

               n = what.indexOf(';',n)

               if (n < 0) return what     

               else

                    {

                         what = what.substring(0,n) + escape(';') + what.substring(n+1,what.length)

                         n++

                    }          

          }

     return what

}

function toCookie()

{

     document.cookie = ''

     nform = document.data

     for (i=0 ; i<nform.length; i++)

          {

               expr =makeYearExpDate(1)

               astr = fixSep(nform.elements[i].value)

               //astr = nform.elements[i].value 

               astr= nform.elements[i].name + '=' + astr + ';expires=' + expr + ';path=/'

               document.cookie=astr

          }

}

function makeYearExpDate(yr)

{

     var expire = new Date ();

     expire.setTime (expire.getTime() + ((yr *365) *24 * 60 * 60 * 1000));

     expire = expire.toGMTString()

     return expire

}

function getCookieAt(n)

{

  e = document.cookie.indexOf (";", n);

     if (e == -1)

          e = document.cookie.length 

     rstr= unescape(document.cookie.substring(n,e)) 

     return rstr

}

function fromCookie()

//restores summary fields from cookie

{

     nform = document.data

     astr = document.cookie

     alert(astr)

     cl = astr.length

     counter=0

     for (i = 0 ; i < nform.length ; i++)

     //for (i = 0 ; i < 1 ; i++)

          {

               nstr = nform.elements[i].name + '='

               ll = nstr.length

               

               jx  = 0;

                 while (jx < cl) 

               {

                   k = jx + ll; 

                    xstr = astr.substring(jx,k);

                    //alert(nstr + '\n' + xstr + '\ni=' + i + '\nj=' + jx + '\nk=' + k + '\nll=' + ll + '\ncl=' + cl);

                   if (xstr == nstr)

                     {

                              nform.elements[i].value = getCookieAt(k);

                              break ;

                         }

                   jx = document.cookie.indexOf(" ", jx) + 1;

                   if (jx == 0) break ;

                 }

               

          }

}

function arrayFromCookie()

// fills global array from cookie

{

     astr = document.cookie

     cl = astr.length

     k=0

     //for (i = 0 ; i < nform.length ; i++)

     jx  = 0;

     for (i = 0 ; i < 6 ; i++)

          {

                    

              jx=astr.indexOf(' ',jx)

               k = astr.indexOf('=',jx);

               xstr = astr.substring(jx+1,k);

               //alert(xstr + '\ni=' + i + '\nj=' + jx + '\nk=' + k  + '\ncl=' + cl);

               parms[i]=xstr;

               parms[parms[i]] = getCookieAt(k+1);

              jx = astr.indexOf(";", jx) + 1;

              if (jx <= 0 || i > 10) break ;

               

          }

The function makeYearExpDate() allows you to set the expiration date for some number of years in the future. It was designed for really persistent cookies. If you want a shorter time, you can easily modify this routine. Note that this function uses on the Date object heavily. The static method Date.getTime() returns a neatly formatted date string, while the method and Date.toGMTime() returns the date converted to Greenwich Mean Time, which is what the cookie expiration mechanism expect your cookies to contain.

Thefunction fixSep() escapes any semicolons which you might have in your variables. It is highly undesirable to store semicolon in the cookie parameters, since semicolon is the parameter separator.. You could, in fact, escape all the non-alphanumeric characters in the entire string. However, this would make it difficult to read, especially if you simply want to look at the cookie.

The functionGetCookieAt(n) retrieves the cookie value starting at an offset of n characters into the cookie string. It replaces all escape sequences with their ASCII values. The functionFromCookie() restores all of the summary forms variables from the cookie. It is really an undo function.

The final function, arrayFromCookie() is called by the page rebuilding routines to build the global array, parms, from which the page is rewritten. Notice that we did not have to change the page rebuilding code from that of Listing 8.15. We only changed the routine to build the parms array.

QUE Home Page

For technical support for our books and software contact support@mcp.com

Copyright ©1996, Que Corporation