Javascript: "Flipping" Framesets
(Multiple Simultaneous Frame Changes On One Mouse Click)

Perhaps someday, during your Web-spinning career, you will want to be able to make several frames in a frameset change at once, with one mouse click (such as on a link). We hope with this chapter to give you some ideas and tips on how to solve your version of this frameset puzzle.

The above depicts the case of an (apparently) 3-frame frameset, which is used to hold either a "timeline" set of frames (title, index, and contents) or a "glossary" set of frames (different title, index, and contents). The programmer wanted to make items in the "Timeline" frameset able to link to items in the "Glossary" frameset and vice-versa. Most of these desired links are in the 'contents frame' of each frameset. Several 'snapshots' below show the desired behavior. When you click an item in the Timeline which refers to an item in the Glossary, all the frames change (nearly) at once to show that you are now in the Glossary. The chosen Glossary item is displayed at the top of the 'contents' frame. The same is true in reverse for a Glossary item which is linked to some occurrence in the Timeline.

*** Copyright Disclaimer: The author acknowledges that Star Wars is copyright and reserved by LucasFilm Limited, and has ABSOLUTELY NO INTENTION of publishing a complete 'Timeline/Glossary' anywhere on the Web without LucasFilm's express permission. The author is building this page STRICTLY for personal, in-house, one-copy-on- my- PC- only use. ***

Now that you have seen the specimen and the lawyers have been fed, here is the secret:

The frameset is actually FOUR frames. Go back and look, if you didn't already notice: there is a tiny frame, one pixel high, running along the bottom of the frameset. This frame, "batonbox", holds an HTML file whose sole purpose is to contain JavaScript functions. Why do this? Here are the principles at work:

  1. A Javascript command in one frame can call a JavaScript function in another frame. (To be precise, the function defined in the 'file.htm' which is sitting in that frame.) So, the JavaScript phrase, "top.batonbox.GoToGloss()" means, "go to the top level of this frameset, find the frame under it which is called 'batonbox', and then execute the JavaScript function called GoToGloss which is defined in the HTML file sitting in that frame."
    'Batonbox' was named in the HTML for the frameset:

    <FRAMESET ROWS = "80,*,1" FRAMEBORDER=yes BORDER=1>
    <FRAME SRC="timetitl.htm" NAME="title" MARGINWIDTH=3 MARGINHEIGHT=3 SCROLLING=no>
    <FRAMESET COLS="*,250" FRAMEBORDER=yes BORDER=1>
    <FRAME SRC="parlor.htm" NAME="main" MARGINWIDTH=10 MARGINHEIGHT=10>
    <FRAME SRC="timeindx.htm" NAME="index" MARGINWIDTH=7 MARGINHEIGHT=10>
    </FRAMESET>
    <FRAME SRC="variable.htm" NAME="batonbox" MARGINWIDTH=1 MARGINHEIGHT=1>
    </FRAMESET>

    (In our example, the frames are called "title", "index", "main", and "batonbox".

    You do NOT need to nest the names of these nested frames in the JavaScript call. Although "main" and "index" are in a frameset which is nested inside another frameset (which contains "title" and "batonbox"), phrases such as "top.title.main.etc" are not only unnecessary but also incorrect. Once a frame has been named, JavaScript recognizes it wherever it is in the frame structure.

  2. But a JavaScript function must be defined inside an HTML file in order to exist. If you change which HTML file is in the frame, the JS function that was in that frame cannot finish running because, of course, it is gone. So, in order to finish doing a routine in which it changes the HTML files in frames, the JavaScript function which changes the other frames must stay in a frame whose HTML file never changes.

  3. An HTML file whose sole purpose is to contain JavaScript functions doesn't care how large (or small) the frame that contains it is.
    {In fact, people used to create frames that were only 1 pixel square (i.e. invisible) and used them to contain all sorts of sneaky Big Brother-ish routines, until the Net standards people dropped the hammer. Now, browsers won't recognize a frame 1 pixel square, but they will still deal with a 1-pixel-by-screen-width one.}

  4. Finally, there is a sneaky 'target' bug particular to this example frameset, which is described in greater detail below.

So, in order to simultaneously change the contents of 3 frames at one click, the programmer created the fourth skinny frame, whose sole function is to contain the JavaScript functions which perform the frame-changes. A call, whose function can reside in any other frame, invokes the JavaScript function in this 'batonbox' frame, which then serenely tosses the contents of the other frames out and replaces them with new HTML files, according to its script. But all is not blissful in Batonbox Paradise.

The 'Target' Bug:

When "flipping" a frameset, the HTML file for one of the frames must be explicitly called out as an href, and "target"-ed as necessary.

I found that when building a link in the 'main' frame that will cause the frameset files to "flip", I could not pass the name of the new HTML file for the 'main' frame, directly into the JavaScript functions in 'batonbox'. (At least not in Netscape.) Attempts to do so resulted in a 'directory listing' in that frame, instead of seeing the desired webpage. The user would click on a link in the 'main' frame of the Glossary which referred to an entry in the Timeline, but while the 'title' and 'index' frames for the Timeline loaded up correctly, the 'main' frame would just show a listing of the current file directory. Not what we wanted.

The solution for this problem was ridiculously simple-- use the "target" command to place the desired file directly in the 'main' frame. This is the more normal means of causing one HTML file to replace another in the same frame.

Finer points of "target acquisition": NO "base target=x" !!

It's possible to set up a "base target" (a sort of "default setting") in the <head> of your frameset, but this will cause you problems in our case. Say one of your frames is named "x". If you set 'base target=x' in the <head>, then frame x will fail to load up the desired file, 'yatta.htm', on a command such as 'top.x.location.href=yatta.htm'.

On the other hand, if you do not have a base target set, but do not specify a target in that local link, the frame in which that link is located will have the loadup problem.

To avoid all this, do not specify a 'base target' in <head> at all. Instead, inside all of your links, specify one of the html files and its path explicitly, and specify its target individually if it is other than the frame in which the link is located. For example, you'd just say 'target="x"'. Then, in order to change the HTML files in the other frames, include an OnClick JavaScript routine inside the same link, that will load them up with their new files.

Putting It All Together

Here is a typical "frame flippy" crosslink, and how it works:

<a href="t/glosst.htm#T16skyhopper" target="main" onclick="top.batonbox.GoToGloss()"> skyhopper</a>

  • <a href...>skyhopper</a> -- It is a hyperlink.

  • a href="t/glosst.htm#T16skyhopper" -- We specify that the file "glosst.htm" at its bookmark "T16skyhopper", located in the subdirectory "t" will be displayed. (A subsequent link which wants to return to this location will include the snippet
    "a href=../thisfile.htm" where '../' brings you back up a directory level.)

  • target="main" -- the "target bug" fix. You aim the desired file at a specific frame. BUT this statement must occur FIRST in the hyperlink before we...

  • onclick="top.batonbox.GoToGloss()" -- This JavaScript command catches the mouse click when the user clicks the link. It means, "go to the top of this frameset and find the frame named 'batonbox'. In the file located in that frame, execute the JavaScript fuction called GoToGloss(). The GoToGloss() function then reloads the new HTML files into the other two frames. It looks something like this:

function GoToGloss(){
top.title.location.href="glostitl.htm";
top.index.location.href="glosindx.htm"}

("~.location.href" performs the same function in JavaScript as does "href=" in HTML.)

All In One Line

This extremely hyper hyperlink cannot be broken up by carriage returns in your code. JavaScript is sensitive to spaces and carriage returns, and the link won't work properly.

"Back" Problems

In a 3-frame set like this, clicking the 'back' button on your browser will restore only one frame at a time. You'll have to click 3 times (in our example) to get back to the previous display (e.g. 'back' from the Glossary to the Timeline). You can see on the page snapshots above that there is a "Back One Window" button in the HTML files of the "title" frames. It calls another JavaScript routine, which has recorded the previous set of 3 HTML files for the frameset, and restores those files to the frames when commanded. Thus when that button is clicked once, all 3 frames "flip" back together.


Index           Home  Back       About  Contact us!

Copyright (c) 2000 B. Parcells