Chapter 17

Using Frames and Cookies


CONTENTS

o=One of the tremendous advantages of hypertext is its ability to link together many pieces of information in a nonlinear fashion. Rather than having to read a book one page at a time, you can leap from one link to the next as you explore different topics and their interconnections. However, sometimes this easy access to information can have unfortunate and cumbersome side effects.

One such side effect occurs when you find yourself moving back and forth between a small set of pages, over and over again. This happens because of a problem with presentation: The information you want is scattered over more than one page. If you are reading a tutorial, for example, you may find that you are revisiting the Table of Contents page with dreary repetitiveness. You can avoid this by having multiple browser windows open at the same time, but this often takes up too much of your display.

This chapter focuses on the emerging HTML frames technology, which addresses this issue of presentation. Both Microsoft's Internet Explorer version 3.0 and the Netscape Navigator browser enable you to split a single browser window into multiple, independent subwindows, each containing its own URL. These subwindows are known as frames. We will explore frames technology and its close relationship to JScript in some detail.

To do this, we must first address the related topic of data storage. Sophisticated applications often require both data presentation and data storage/management capabilities. Unfortunately, information or parameter storage is particularly difficult. Both Microsoft and Netscape provide a persistent means of storage via Cookies. We explore this method in the first section of this chapter, and then subsequently illustrate how such data can then be used to format a page on-the-fly.

Parameter Specification and Data Storage

Because Microsoft is extremely security-conscious, storing or loading data is difficult-even between document reloads. Chapter 8, "Dynamic HTML and IE Objects," briefly described one method of storing simple data between document reloads via a string saved in location.search. This special location.search property is often referred to as the command line. A script can retrieve this string and redraw itself based on information in the string. This approach is limited in the current release of Internet Explorer, however, so we will discuss the more permanent storage option offered by Cookies.

The "JScript Object Hierarchy" section of Chapter 8 "Dynamic HTML and IE Objects," discusses the location object and its various properties, including the search property.

Storing 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 all of your data, encode it, and store it in the command line.

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

The only possibility that offers any permanence is Cookies. Cookies are lines in a file that the browser enables you to write to disk. This file will be stored in the Cookies folder on a Windows machine, or in a file called COOKIES on a Macintosh. Cookies are limited in size and number. Nevertheless, Cookies are extremely useful. They are frequently used in the same way as a Windows .INI file, a Macintosh Preferences file, or a UNIX .RC file. The next subsection examines the Cookie approach.

Storing Persistent Data in Cookies

The only method you can use to store variables between invocations of Internet Explorer v3 is the Cookie approach. This is also the only approach that works with windows in different hierarchies. It should also be noted that the specification for the Cookie storage format is still a draft, so the approach described in this section should be used with caution.

Cookies were originally designed to enable a server to save 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. They are also useful in case the server crashes and later wants to pick up where it left off. Cookies are now available for general use in JScript.

Cookies have the following five parameters:

NAME=VALUE
expires=DATE
path=PATH
domain=DOMAIN_NAME
secure

Only the first one, which is a familiar NAME=VALUE pair, is required. All of the others are optional. However, if you do not save an expiration date, the Cookie automatically expires when you close Internet Explorer -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 overwrites the existing one.

Although servers can write named Cookies one at a time, JScript cannot. You can set an individual named Cookie with the statement, document.Cookie='Cookiename=xxxx', but when you retrieve document.Cookie, you get a string consisting of all of the Cookies. Currently, the only way to retrieve an individual Cookie is to search through the entire set of Cookies obtained from document.Cookie. Consequently, it helps to add a prefix or suffix to the names of your Cookies with little-used characters. This makes them easy to find with indexOf().

Let's examine each of the Cookie parameters in turn. As 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 parameter is used to describe the expiration date for the Cookie. As defined by the draft standard Cookie specification, 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 never to expire, give it a date several years in the future.

The path=PATH parameter is used to limit the search path of a server that can see your Cookies. This is analogous to specifying a document BASE in an HTML document. If you use a slash (/), then everything in the domain can use your Cookies.

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

Listing 17.1 shows the Cookie versions of the routines for saving and restoring persistent information. This code will be found on the CD-ROM in the file C17-1.htm. The information goes to, and comes from, the document Cookie. These routines have been liberally modified from the original versions, which were written by Bill Dortch and placed in the public domain.


Listing 17.1  c17-1.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].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
    
     cl = astr.length
     counter=0
     for (i = 0 ; i < nform.length ; i++)
         {
               nstr = nform.elements[i].name + '='
               ll = nstr.length
jx  = 0;
                 while (jx < cl) 
                   {
                     k = jx + ll; 
                     xstr = astr.substring(jx,k);
                     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
     jx = 0;
     for (i = 0 ; i < 6 ; i++)
          {
              jx=astr.indexOf(' ',jx)
              k = astr.indexOf('=',jx);
              xstr = astr.substring(jx+1,k);
               parms[i]=xstr;
               parms[parms[i]] = getCookieAt(k+1);
               jx = astr.indexOf(";", jx) + 1;
              if (jx <= 0 || i > 10) break ;    
          }

The function makeYearExpDate() enables you to set the expiration date for several 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 the Date object heavily. The static method, Date.getTime(), returns the date as seconds since The Epoch, while the method, Date.toGMTime(), returns the date converted to Greenwich Mean Time, which is what the Cookie expiration mechanism expects your Cookies to contain.

The function fixSep() escapes any semicolons that your variables might have. It is highly undesirable to store semicolons in the Cookie parameters, because the semicolon is the parameter separator. You could, in fact, escape all the nonalphanumeric characters in the entire string. However, this would make it difficult to read, especially if you simply want to look at the Cookie.

The function, GetCookieAt(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 function, FromCookie(), restores all of the summary form's 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 can retrieve the value of a single Cookie entry by indexing into the parms array.

Frames and JScript

Frames are one of the most important new features to be added to HTML. Frames allow multiple subwindows-or panes-in a single Web page. This gives you the opportunity to display several URLs at the same time on the same Web page. It also allows you to keep part of the screen constant while other parts are updated. This is ideal for many Web applications that span multiple pages but also have a constant portion (such as a table of contents). Before you learn about the implications of frames on JScript, a very brief tutorial on frames will be presented.

Specifying Frames in HTML

Frames in HTML are organized into sets which are known, appropriately enough, as framesets. In order to define a set of frames, one must first allocate screen real estate to this frameset, and then place each of the individual frames within it. We will examine the syntax for the HTML FRAMESET and FRAME directives in order to understand how frames and framesets are organized.

One of the most important, and most confusing, aspects of frames is the parent/child relationships of frames, framesets, and the windows that contain them. The first frameset placed in a window has that window as its parent. A frameset can also host another frameset, in which case the initial frameset is the parent. Note that a top-level frameset itself is typically not named, but a frameset's child frames can be named. Frames can be referred to by name or as an index of the frames array.

You can divide your window real estate with a statement of the form <frameset cols=40%,*>. This frameset statement divides the window horizontally into two frames. It tells the browser to give 40 percent of the window width to the left frame, frames[0], and anything remaining to the right frame, frames[1]. You can explicitly give percentages or pixel widths for all frames, but it is more useful to use an asterisk (*) for at least one parameter. Use this wildcard character (*) for the widest frame, or for the frame that is least likely to be resized. This helps ensure that the entire frameset is displayed on a single screen. You can also divide the window vertically with a statement like <frameset rows=20%,*,10%>. This statement gives 20 percent of the available window height to the top frame, frames[0], 10 percent to the bottom frame, frames[2], and anything left to the middle frame, frames[1].

Caution
You cannot divide a window both horizontally and vertically with one frameset. To do that, you must use nested framesets.

The subsequent <FRAME...> statements define the name, source (URL), and attributes of each frame in the frameset. For example,

<FRAME SRC='menu.htm' NAME='menuframe' MARGINWIDTH=2 MARGINHEIGHT=2 SCROLLING="YES">

defines a frame into which the MENU.HTM file will be loaded. This frame is named menuframe.

Unless you are designing a ledge (a frame that never changes) and you know it will always be displayed in the frame, make the frame scrollable. You can enter an explicit SCROLLING attribute, which should be the value YES or NO, but the frame will default to SCROLLING=YES. Scrolling is much kinder to your users. You might have a very high-resolution display, but a lot of computers, particularly laptops, do not. The MARGINWIDTH= xx and MARGINHEIGHT=xx attributes also allow you some latitude in how you present your document within a frame.

Note
Although Internet Explorer and Netscape both understand frames, many other browsers don't yet have that capability. Ideally, you should provide a version of your document that does not use frames for such browsers. At a minimum, you should warn the users about the presence of frames in your document using a <NOFRAMES>...</NOFRAMES> clause.

Make sure you have an initial URL to load into the frame, even if that URL is just a stub. Otherwise, you might find that the browser has loaded an index to the current directory. If you want to use a frame in the frameset to load other documents from a link, you must specify the target frame like this:

<A HREF='netcom.com/home' TARGET='menuframe'>Microsoft</A>

Frames are a sophisticated way to build Web pages; you can keep your menu in one frame and display your content in another. However, it is easy to go overboard and have too many frames. If you present too much information in several different small frames, the user will probably be scrolling quite often. Since the whole purpose of frames is to present information in a pleasing manner, it is important not to try the user's patience. Frames can be a powerful tool, but they should be used judiciously.

Building a Frameset

Framesets are easy to build, although their hierarchy can become complex if they are nested. Listing 17.2 shows a simple frameset document. For it to display correctly, there must be HTML documents with the names given by the SRC attribute in each FRAME definition. When this code is loaded into the browser, the page shown in Figure 17.1 appears. This code appears in the file C17-2.htm on the CD-ROM.


Listing 17.2  c17-2.htm-A Simple Frameset
<HTML>
<HEAD>
<TITLE><Simple Frame</TITLE>
<SCRIPT></SCRIPT>
</HEAD>
<FRAMESET cols=40%,*>
     <FRAME SRC="menu_2.htm" NAME="menuFrm" SCROLLING=YES
      MARGINWIDTH=3 MARGINHEIGHT=3>
     <FRAME SRC="display.htm" NAME="displayFrm" SCROLLING=YES
      MARGINWIDTH=3 MARGINHEIGHT=3>
     <NOFRAMES>
       You must have a frames-capable browser to
       <A HREF="noframes.htm">view this document</A> correctly.
     </NOFRAMES>
</FRAMESET>
</HTML>

Figure 17.1 : Framesets contain multiple frames and reference multiple URLs.

Note
When building a frameset, always remember the following rules:
  1. The <FRAMESET>…</FRAMESET> block replaces the <BODY></BODY> block. It is incorrect to have both.
  2. Always use a <NOFRAMES>…</NOFRAMES> clause for browsers that do not support frames.
  3. Make all your frames scrollable except in exceptional circumstances.
  4. Make sure the HTML documents referenced by the SRC attributes are "live" before the frameset is displayed.

One of the most difficult concepts about framesets and frames is how they are referenced. For the simple frameset previously shown, you can make a simple roadmap of the object references. When you want to reference the child frames from the frameset, you can use the following references:
  • MENU_2.HTM
=
frames[0]
or
menuFrm
  • DISPLAY.HTM
=
frames[1]
or
displayFrm
When one of the frames references its parent frameset, this object reference is used:
  • Either frame
=
parent
 
 

The contents of each frame are referenced as properties of the frame. For example, the frameset can access the document object of MENU_2.HTM as frames[0].document or menuFrm.document. The latter usage is usually preferable, since it is self-documenting.

Frames Within Frames

Frames can be nested in two ways. We will illustrate both types of nesting by putting another frameset inside the displayFrm frame object defined in Listing 17.2. To understand the first method, call the original frameset Frameset A. The frameset declaration shown in Listing 17.3 nests a second frameset, referred to as Frameset B, within Frameset A. It does this by replacing frames[1] (the displayFrm frame) with another frameset. This code can be found in the c17-3.htm file on the CD-ROM. The auxiliary files menu_3.htm, pics.htm, and text.htm are also required.


Listing 17.3  c17-3.htm-Example of Nested Frames in Which a Frame Is Replaced with Another Frameset
<HTML>
<HEAD>
<SCRIPT>
</SCRIPT>
</HEAD>
<frameset cols = 30%,*>
     <frame src = 'menu_3.htm' name='menuFrame' marginwidth=3
           marginheight=3>
          <frameset rows=66%,*>
               <frame src='pics.htm' name='picFrame' scrolling=yes
                marginwidth=3
                     marginheight=3>
               <frame src='text.htm' name= 'textFrame' scrolling=yes
                     marginwidth=3 marginheight=3>
          </frameset>
      <noframes>
          You must have a frames-capable browser to
                <a href=text.htm>view this document</a> correctly.
      </noframes>
</frameset>
</HTML>

Referencing in this type of nested frameset is no different from the type of object references described for a simple frameset. When a frameset references a child frame, the following object references are used:
  • MENU_3.HTM=
frames[0]
or
menuFrame
  • PICS.HTM=
frames[1]
or
picFrame
  • TEXT.HTM=
frames[2]
or
textFrame

When any of the component frames refers to the frameset that contains it, the following reference is used:
  • Any frame =
parent

The second method uses URLs to achieve nested framesets. We will set Frameset B's displfrm to an URL that contains a framed document. This URL will come from the file DISPLFRM.HTM and will create the frames picFrame and textFrame. In this case, the object references are somewhat more complex. When the parent refers to its child frames, it uses the following:
  • MENU_4.HTM=
frames[0] ormenuFrm
  • DISPLFRM.HTM=
frames[1] ordisplayFrm
  • PICS.HTM=
frames[1].frames[0] ordisplayFrm.picFrame
  • TEXT.HTM=
frames[1].frames[1] ordisplayFrm.textFrame

When the child frames refer to their frameset parent, these object references are used:
  • MENU_4.HTM=
parent
  • DISPLFRM.HTM=
parent
  • PICS.HTM=
parent.parent
  • TEXT.HTM=
parent.parent

Caution
Specifying an empty URL in a frame declaration can cause the index file in the server's current directory to be loaded into the frame. Anyone can then open any of the documents listed in that index file. This can be considerably detrimental if you do not want to give users unrestricted read access to that particular directory.

Examples of Interframe Communication

At this point, you know how to refer to parent framesets in frames, and also know the correct object references for child frames of a frameset. The next topic explores interframe communication. This example uses the CD-ROM files C17-2.HTM, MENU_2.HTM (shown in Listing 17.4), and DISPLAY.HTM. Make sure you place all these files in the same directory, and then load C17-2.HTM into your browser. The file MENU_2.HTM that's loaded into the left frame provides a simple and useful example of interframe communication.

The MENU_2.HTM file contains some links to well-known sites. A TARGET that points to the displayFrm frame is given for each link. If you click a link, the URL loads into the displayFrm frame instead of into the menuFrm frame. Note that you cannot refer to the "parent" object when you use a TARGET. To experiment with the page, click several links. After you have done this a few times, try to go backwards using IE's Back button. Notice that the whole frameset disappears; it is replaced by the document you were looking at before you loaded the C17-2.HTM frameset.

Tip
Internet Explorer's Forward and Back buttons work on the entire document-not on individual frames.

This limitation can certainly make life difficult, especially if you follow several links in the displayFrm and now want to get back to an intermediate one. Fortunately, there is a way to do this, but you must specifically provide for it. Notice the two small image buttons below the links. If you click the left arrow, the displayFrm frame reverts to the previously visited URL. Similarly, the right arrow takes you forward in the frame.


Listing 17.4  menu_2.htm-Using URLs to Create Nested Framesets
<HTML>
<HEAD>
<TITLE>MENU.HTM</TITLE>
<SCRIPT>
function goback()
{
      awin = self.parent.displayFrm
      awin.history.back()
}
function gonext()
{
      awin = self.parent.displayFrm
      awin.history.forward()
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR='darkslateblue' TEXT='linen' LINK='corel'
      VLINK='darkcorel' ALINK='yellow' >
<CENTER><FONT SIZE=7 COLOR="yellow"><B>MENU<B></FONT><CENTER>
<H3><HR></H3>
<A HREF="http://lycos-tmp1.psc.edu/lycos-form.html"
      TARGET ="displayFrm">Lycos</A><BR>
<A HREF="http://www.yahoo.com/new"
      TARGET ="displayFrm">Yahoo!</A><BR>
<A HREF="http://weber.u.washington.edu/~jgurney/java/"
      TARGET ="displayFrm">Java Botique</A><BR>
<A HREF="http://www.nashville.net/~carl/htmlguide/index.html"
      TARGET ="displayFrm">How do they do that with HTML?</A><BR>
<A HREF="http://www.internet-audit.com/"
      TARGET ="displayFrm">InternetAudit Bureau</A><BR>
<H3><BR></H3>
<CENTER>
<A HREF=javascript:goback()>
<IMG WIDTH=24 HEIGHT= 21 VSPACE=2 HSPACE= 2 BORDER=0
     SRC="Images/arw2_l.gif">
</A>
<A HREF="javascript:gonext()">
<IMG WIDTH=24 HEIGHT= 21 VSPACE=2 HSPACE= 2  BORDER=0
     SRC="Images/arw2_r.gif">
</A>
</CENTER>
<BR>
<H3><BR><HR><BR></H3>
<H3><BR><HR SIZE=5 WIDTH=80%><BR></H3>
</BODY>
</HTML>

Another interesting aspect of frames is revealed if you attempt to use the View Source option of Internet Explorer. Only the code for the frameset appears-the code for the frames contained in it does not. This is one approach to provide some simple protection for your source code. However, it keeps only novice users from seeing your code; experienced users can defeat this by loading the URLs referenced by the individual frames into a single browser window, and then using View Source on that window.

Caution
The current release of Internet Explorer does not reliably reload documents containing frames. This means that if you are editing a document and you press the Refresh button, the most recent version of that document might not be reloaded. Images within frames suffer the same problem.

Writing a New Document into a Frame

The examples in the files C17-2.HTM and C17-3.HTM do simple rewrites of documents into adjacent and foreign frames. We will now expand on that by taking the Note Object example from Chapter 8 "Dynamic HTML and IE Objects," and writing it to a frame, rather than to a new window. The file C17-4.HTM on the CD-ROM defines the frameset that loads the subsidiary documents SETNOTE.HTM and NOTE.HTM into its frames. The file SETNOTE.HTM contains a button that calls a writeNote() routine to write the new HTML into the frames[1] frame. The file NOTE.HTM is just a stub so that you don't have to write an empty URL. Listing 17.5 shows the code for the writeNote() function. Figure 17.2 shows what happens when the note is written into the frame.

Figure 17.2 : Documents can be dynamically written into frames.


Listing 17.5  setnote.htm-The Code for the writeNote() Function
function writenote(topic)
{
     topic = 'This is a little note about rewriting adjacent frames."
     topic += " You do it the same way as you would to rewrite"
     topic += " or originally write a window."
     aWin = self.parent.displayFrm
     ndoc= aWin.document
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()
}

Building a JScript Function Library in a Frameholder

You have already learned that a frameset document cannot contain any HTML other than frame definitions. It can, however, contain a script. In this script, you can keep window global variables and functions. We will define a minimal string manipulator in a frameset. With this tool, you can do the following:

The first two operations merely require calls to string functions. The latter can be accomplished by a routine that we have already written. You store these functions in the frameset of the file C17-5.HTM on the CD-ROM. This frameset requires the files FUNCS.HTM and EDITOR.HTM to be in the same directory.

The frame named menuFrm will contain buttons to call your frameset functions. These functions must be able to refer to objects in their own frame as well as the adjacent frame editFrm. In addition, you must be able to call these functions from the parent frame. The true value of a frameset function library is its reusability. It is easy to copy the HTML file that defines the library and create a new document by changing a small amount of code-the code that builds the frameset itself. In this way, you can reuse your code.

Another way to reuse code is to have all the functions in a small or hidden frame. When you want to use those functions, you simply load that frame. If you take this approach, you don't have to change the frameset code. In both cases, however, it is more difficult to address an adjacent frame than it is to address a parent or child.

The menuFrm frame loads the document defined in the CD-ROM file FUNCS.HTM. This file defines the buttons that access the frameset functions. Some of the object references are quite long, so this file makes liberal use of aliasing to shorten them. The file FUNCS.HTM is loaded into the frames[0] object, while a simple editor window is placed in frames[1]. This editor is implemented as a textarea. When this frameset is loaded, the browser will display something like what is shown in Figure 17.3.

Figure 17.3 : A frameset library can be used to implement a string processor.

The file FUNCS.HTM also has a test window and a button, so you can try out the functions it provides. These functions act on objects in its document. The code is such that the button always calls a routine called testit. The testit function has calls to the three routines in the function library. You can easily adapt this code for your own purposes by replacing the testit function.

The most complex part of using functions stored in the frameset is determining the appropriate name of the frameset window. This depends on the window from which the function call is made. The example previously shown offers a very simple solution: Just use self.parent.myfunc(). The self portion of this expression can be omitted, but you might want to keep it to discourage ambiguity.