Приглашаем посетить
Есенин (esenin-lit.ru)

Manipulating Framesets

Manipulating Framesets

Framesets were first supported in Netscape Navigator 2.0 and Microsoft Internet Explorer 3.0. Framesets are a special type of HTML document used to divide a browser window into multiple regions called frames. Framesets are most commonly used to display a menu or other navigation mechanism in one frame and a document in another or to provide a nonscrollable header at the top of the page.

Figure 5-2 shows a frameset that displays four panes: a table of contents pane with information panes above and below it, and a document pane. The table of contents pane contains a list of anchors representing documents. When an anchor is clicked, the corresponding document is displayed in the right frame.

Manipulating Framesets

Figure 5-2. Frameset with three frames on the left, including a table of contents, and a frame on the right containing a document.

This section first introduces the HTML elements for creating frameset documents and then describes the object model for manipulating them. Each frame is a distinct window object that can be accessed and referenced by other frames.

Authoring Framesets

The first step in creating a frameset is to determine the layout requirements. A frameset can divide a screen into any number of rectangular regions; each region contains its own HTML document.

The <FRAMESET> tag replaces the <BODY> tag in the HTML document and is used to split the screen. Within the Frameset element are <FRAME> tags that point each region to the individual document. Framesets can be nested to easily divide the screen into horizontal and vertical columns.


NOTE: Internet Explorer 3.0 mixed the concepts of a frameset and a document with body contents even though these were intended to be independent concepts. In Internet Explorer 3.0, when a page consists of both a frameset and a body, the body is rendered as a frame behind the frameset. This behavior is no longer supported in Internet Explorer 4.0 and was never supported by Netscape Navigator and therefore should not be used.

The syntax for a frameset is shown here:

<FRAMESET COLS="..." ROWS="...">

       <FRAME SRC="..." NAME="...">

</FRAMESET>

The COLS and ROWS attributes take comma-delimited lists of measurements that are used to divide the screen. For example, the following frameset divides the screen into four equal regions:

<FRAMESET COLS="50%, 50%" ROWS="50%, 50%">
</FRAMESET>

When these measurements are not specified, the frameset contains one row and one column that take up the entire window.

To fill the regions with contents, the <FRAME> tag is used. The number of frames specified should be equal to the number of rows multiplied by the number of columns. In this example, the frameset should have four frames:

<FRAMESET COLS="50%, 50%" ROWS="50%, 50%">
   <FRAME SRC="f1.htm">
   <FRAME SRC="f2.htm">
   <FRAME SRC="f3.htm">
   <FRAME SRC="f4.htm">
</FRAMESET>

Frames in a frameset are populated across and then down. The preceding HTML code divides the browser into four regions containing HTML files, as shown in Figure 5-3.

Manipulating Framesets

Figure 5-3. Frameset with four frames.

There is no requirement that the number of frames match the specified number of rows and columns. If you provide too many Frame elements, the extra ones will be downloaded, but they will not be visible. If you provide too few Frame elements, some panes will appear without documents.

The following code demonstrates a technique that allows an extra frame to be supplied but not displayed. This frame can contain contents that are manipulated by custom code.

<FRAMESET COLS="50%, 50%">
   <FRAME SRC="f1.htm">
   <FRAME SRC="f2.htm">
   <FRAME SRC="hidden.htm">
</FRAMESET>

The frame containing hidden.htm is not displayed on the screen because the first two frames take up 100 percent of the screen real estate. Scripts or other contents that are being used for scripting purposes only might exist in hidden.htm.

Framesets can also be nested using two techniques: a single cell can be further subdivided into extra rows and columns by specifying another frameset, or a document loaded into a frame can itself contain a frameset that further divides the screen. To use the first technique in the example in Figure 5-3 to split the lower right region into two columns, create the following HTML code:

<FRAMESET COLS="50%, 50%" ROWS="50%, 50%">
   <FRAME SRC="f1.htm" NAME=f1>
   <FRAME SRC="f2.htm" NAME=f2>
   <FRAME SRC="f3.htm" NAME=f3>
   <FRAMESET COLS="50%, 50%">
      <FRAME SRC="f4.htm" NAME=f4>
      <FRAME SRC="f5.htm" NAME=f5>
   </FRAMESET>
</FRAMESET>

In this example, any one of the documents (f1.htm through f5.htm) can contain another frameset that further divides the window. When a document inside a frame contains another frameset, you can change the number and arrangement of your frames just by changing that document. This technique will be examined in more detail in the section "Targeting Frames" later in this chapter. With nested framesets, you can't change the arrangement of the frames as easily.

To create only rows or only columns, you need to supply only the ROWS or only the COLS attribute. More sophisticated control over the layout beyond percentage values for ROWS and COLS is also supported. The values supplied for each row or column can be a pixel measurement or an asterisk (*). The * is used to distribute the remaining space. To create a frameset in which the first column is 50 percent of the width of the screen, the second column is one-third of the remaining space, and the third column is the rest of the space, use the following code:

<FRAMESET COLS="50%, *, 2*">
   <FRAME SRC="f1.htm" NAME=f1>
   <FRAME SRC="f2.htm" NAME=f2>
   <FRAME SRC="f3.htm" NAME=f3>
</FRAMESET>

Fixing the Size and Scrollbars

By default, frames can be resized and have full support for scrolling. Two attributes can be added to a frame that fix the size and disable the scrollbars for the document: NORESIZE and SCROLLING. Specifying NORESIZE fixes the current size of the frame; SCROLLING has three valid values, as listed in the table on the following page.


Value Description
auto Displays scrollbars only if necessary
yes Always displays scrollbars
no Never displays scrollbars, even if the contents are clipped

The following code demonstrates a few of the different combinations available with the SCROLLING and NORESIZE attributes:

<FRAMESET COLS="50%, 50%" ROWS="50%, 50%">
   <FRAME SRC="f1.htm" NORESIZE>
   <FRAME SRC="f2.htm" SCROLLING="yes">
   <FRAME SRC="f3.htm" SCROLLING="no" NORESIZE>
   <FRAME SRC="f4.htm" SCROLLING="auto">
</FRAMESET>

Borderless Frames

Internet Explorer 3.0 and Netscape Navigator 3.0 introduced the ability to create borderless frames. Borderless frames seamlessly display multiple pages without any visual elements dividing the screen. This technique allows visually appealing documents to be easily constructed.

The BORDER attribute specifies the thickness of a border. Borderless frames are created by setting the BORDER attribute of the <FRAMESET> tag to 0 to make the borders invisible.

Three additional properties are available on the frameset that provide greater control over the borders. The FRAMEBORDER attribute specifies whether the border, if present, will be drawn as a three-dimensional frame. The FRAMESPACING attribute, like the BORDER attribute, sets the border thickness. The resulting border thickness will be the value of the FRAMESPACING attribute plus the thicknesses of the three-dimensional edges, if any. The BORDERCOLOR attribute defines the color of the frame border.

Supporting Down-Level Browsers

Browsers that do not support framesets will display an empty document when they attempt to load the page. To provide contents to an older client, HTML 4.0 defines the <NOFRAMES> tag. The NoFrames element can contain any valid body contents that will be ignored by frames-enabled browsers and displayed on any older clients. This technique works because the older clients do not understand the <FRAMESET>, <FRAME>, and <NOFRAMES> tags; they simply ignore these tags and display the contents of the NoFrames element. Browsers that support framesets know to ignore the contents when they parse the NoFrames element. An example frameset document is shown here:

<HTML>
   <HEAD>
      <TITLE>Frameset Example</TITLE>
   </HEAD>
   <FRAMESET COLS="50%, 50%" ROWS="50%, 50%">
      <FRAME SRC="f1.htm">
      <FRAME SRC="f2.htm">
      <FRAME SRC="f3.htm">
      <FRAME SRC="f4.htm">
   </FRAMESET>
   <NOFRAMES>
      To view this Web site, please use a frames-enabled browser or 
      click <A HREF="noframes.htm">here</A> for a no-frames version.
   </NOFRAMES>
</HTML>

It is a good idea to always provide no-frames comments in frameset documents. They can be as simple as the statement in the preceding code or as complex as an entire alternative Web page. The contents supplied in a NoFrames element can include anchors and any other valid HTML code. A minimal statement should be provided so that the user understands why the Web site is not working. Otherwise, a user with an older browser who sees no contents may choose to not come back to the Web site.

Another use of the NoFrames element is in the bodies of documents. For example, a frameset might provide a navigation bar next to a main document, but clients that do not support framesets will not display the bar when they display the main document. You can provide a simpler navigation bar in a NoFrames element in the main document, as shown in this example:

<HTML>
   <HEAD>
      <TITLE>Navigation Example</TITLE>
   </HEAD>
   <BODY>
      <NOFRAMES>
         <!-- These contents are displayed only in browsers without
              frameset support. Embed an alternative navigation bar
              below. -->
         <P>
            <A HREF="home.htm">Home Page</A>
            <A HREF="search.htm">Search Page</A>
         </P>
      </NOFRAMES>

      Document's contents go here.
      <NOFRAMES>
         <!-- Add a message at the end of the document. -->
         <P>
            This page is best viewed with a frames-enabled browser.
      </NOFRAMES>
   </BODY>
</HTML>

This technique works correctly in Internet Explorer versions 3.0 and later. It does not work in Netscape Navigator because Navigator currently displays the contents of the NoFrames element when they exist in the body of the document.

Inline Frames

Internet Explorer versions 3.0 and later support the ability to create inline frames. An inline frame is contained within the body of a document instead of within a frameset and allows a single document to contain other, independent documents within the flow of the page. The inline frame is functionally similar to a frame in a frameset. It supports targeting and allows users to navigate within the frame, independent of the parent document.

Using an inline frame is similar to embedding an object using the <OBJECT> tag. The following two HTML statements both embed a document:

<IFRAME SRC="banner.htm" WIDTH=500 HEIGHT=500></IFRAME>
<OBJECT TYPE="text/html" DATA="banner.htm" WIDTH=500 HEIGHT=500>
   </OBJECT>

The primary difference between the two statements is that the IFrame element can later be targeted similar to a frame in a frameset. In general, the IFrame element should be used to define the navigable user interface within a page, and the Object element should be used to include contents. The two elements both embed banner.htm in the document, but only the IFrame element allows navigation within its own window.

The IFrame element is a container whose contents are ignored by browsers that support IFrame. Therefore, just as you can use the NoFrames element for non-frames-enabled browsers, you can specify alternative contents inside the IFrame element for browsers that do not support IFrame:

<IFRAME SRC="banner.htm" WIDTH=500 HEIGHT=500>
   <P>Your browser does not support IFrame.</P>
</IFRAME> 

Adding Script Elements

Scripts in a frameset document must be defined in the Head element of the document prior to the first Frameset element, as shown below. Browsers may ignore scripts that appear within or after a Frameset element.

<HTML>
   <HEAD>
      <TITLE>With Framesets, Script Location Is Important</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         /* This script will execute because it occurs before the 
            Frameset element. */     
      </SCRIPT>
   </HEAD>
   <FRAMESET ROWS="*">
      <FRAME SRC="foo.htm">
      <SCRIPT LANGUAGE="JavaScript">
         // Scripts following the <FRAMESET> tag are ignored.
      </SCRIPT>
   </FRAMESET>
</HTML>

Targeting Frames

Naming a frame is similar to naming a window; the name is used to specify a target for a link. When an anchor targets a frame or window, it replaces the current contents of the frame or window with the new document. Only individual frames, including the frame containing the frameset itself, can be targeted. The replacement document can have any MIME type supported by the browser, including a frameset that further divides the screen. This provides a technique that gives the appearance that multiple frames are being updated simultaneously.

The simple frameset shown here divides the screen into two frames:

<HTML>
   <HEAD>
      <TITLE>Main Document</TITLE>
      <BASE TARGET="fContent"> 
   </HEAD>
   <FRAMESET COLS="300, *">
      <FRAME SRC="menu.htm" NAME="fMenu">
      <FRAME SRC="contents.htm" NAME="fContent">
   </FRAMESET>
</HTML>

The file contents.htm, shown next, appears in the right column and can itself be another frameset. When the user navigates, the right frame can be updated with a new document or an entirely new frameset definition.

<HTML>
   <HEAD>
      <TITLE>Contents</TITLE> 
   </HEAD>
   <FRAMESET ROWS="20%, *">
      <FRAME SRC="welcome.htm">
      <FRAME SRC="home.htm">
   </FRAMESET>
</HTML>

Searching for a Targeted Frame

When you target a frameset, a specific algorithm is used to determine the resulting window for the document. This algorithm is important because multiple frames might share the same name. The location of a document with a specified target is determined by searching the set of named windows and frames.

If any of the predefined target keywords are specified, the document is displayed in that frame. For example, _TOP replaces the window with the new document, _PARENT replaces the parent frame, and _SELF replaces the current document. For any other target name, all frames, inline frames, and windows are searched in the following order:

  1. The current frame
  2. All subframes of the current frame, then all subframes of those subframes, and so on
  3. The immediate parent of the current frame and then its subframes, the subframes of those subframes, and so on
  4. The next immediate parent and all its subframes, and so on up the chain to the top-level window and its subframes
  5. The named windows opened by the current window in an arbitrary order

If no match is found, a new window is opened as the target for the URL.

Scripting Framesets

Framesets are accessed and scripted through a frames collection that contains each frame defined by a frameset. The frames collection on a window contains all the child frames of the document. Each frame is a window object that exposes the same object model as a stand-alone window.

The frames collection is constructed based on the document hierarchy, not the visual hierarchy. Therefore, the visual hierarchy cannot be explicitly determined using the collection itself. For example, this HTML document divides the screen into two rows: the top row is a single frame, and the bottom row is divided into two columns.

<HTML>
   <HEAD>
      <TITLE>Nested Framesets in a Single Document</TITLE>
   </HEAD>
   <FRAMESET ROWS="50%, 50%">
      <FRAME SRC="top.htm" NAME="topRow">
      <FRAMESET COLS="50%, 50%">
         <FRAME SRC="bleft.htm" NAME="bottomLeft">
         <FRAME SRC="bright.htm" NAME="bottomRight">
      </FRAMESET>
   </FRAMESET>
</HTML>

The frames collection exposed for the window containing the preceding document orders the frames as follows:

topRow
bottomLeft
bottomRight

Even though the framesets are nested, the frames collection flattens them into source order.

If one of the documents referenced by a frameset contains another frameset, a document hierarchy results; each document defines its own children and each child window may further define more children. For example, suppose top.htm is a frameset document:

<HTML>
   <HEAD>
      <TITLE>Nested Document That Is a Frameset</TITLE>
   </HEAD>
   <FRAMESET COLS="40%, *">
      <FRAME SRC=tleft.htm NAME="nestLeft">
      <FRAME SRC=tright.htm NAME="nestRight">
   </FRAMESET>
</HTML>

The collections are now hierarchical because the document in the frame topRow contains a subsequent frameset that in turn contains two more documents:

topRow
     nestLeft
     nestRight
bottomLeft
bottomRight

The collection of the topmost document is still the same. However, drilling into the top frame returns a nested collection:

top.frames.length   // 3 frames: topRow, bottomLeft, bottomRight
top.frames["topRow"].frames.length // 2 frames: nestLeft and nestRight
top.frames["topRow"].frames["nestLeft"].length // 0: no children of
                                               // nestLeft

Frames as window Objects

Each frame in the frames collection is actually a window object. The set of properties exposed on each frame is the same as the set exposed by the top-level window. The window properties discussed in the rest of this section are therefore properties of frames.

Dynamic HTML exposes three related properties for referencing a window: self, parent, and top. The self property always returns the current window. The parent property returns the parent window in a frameset hierarchy. The top property returns a reference to the topmost window in the browser.

When the window is the topmost window, the parent property returns the current window. Therefore, when you write a loop that walks up the frameset hierarchy, the break case is when the current window equals the parent window, not when the parent window is null. The following code walks up the frameset hierarchy until the topmost window is reached:

var fParent = self;
while (fParent != fParent.parent) {
   fParent = fParent.parent;
}

Similar code determines whether the current window is the topmost window in the object hierarchy:

if (self == top) {
   // Top window; do something.
}
else {
   // Document is in a frameset; do something else.
}

The Implicit frames Collection

While the frames collection is exposed on the window object, it is not actually a distinct property. Instead, the frames object and the window object represent a single object. The existence of a frames property simplifies and helps disambiguate code.

The lack of distinction between objects is important. In JavaScript, whenever a property is added to the window object, it is also available through the frames collection and vice versa. Therefore, referencing the frames property is not required. For example, the following pairs of statements are equivalent:

// Specify number of frames.
window.length;
window.frames.length;

// Access the topRow frame.
window.topRow;
window.frames.topRow;

// Access the first frame in the collection.
window[0];
window.frames[0];

Although there is no real distinction between objects, it is good coding practice to use the frames collection when you explicitly refer to frame-related members and the window property when you are using properties on the current window. This practice helps self-document your code.

Defining Frame Contents

The contents of a frame are usually defined by a separate HTML document. The SRC attribute of a frame can contain literal HTML code. The advantage of putting HTML in a <FRAME> tag is that header frames can be defined inline, as shown here, without requiring an external URL. This technique is valuable in that it reduces the number of round-trips required to and from the server.

<HTML>
   <HEAD>
      <TITLE>JavaScript-Generated Frame</TITLE>
   </HEAD>
   <FRAMESET ROWS="80, *">
      <FRAME SRC="JavaScript:'<H1>Welcome to My Home Page</H1>`" 
             NAME="header">
      <FRAME SRC="content.htm">
   </FRAMESET>
</HTML>

Supplying the initial contents for a frame has no effect on its ability to act as a target. This technique can be further generalized to most attributes that use an URL. For example, Chapter 9, "Scripting Individual Elements," demonstrates how to use JavaScript for the HREF attribute of an anchor. Alternatively, the VBScript: prefix can define the contents using VBScript.

Traversing the Frameset Hierarchy

The following code visually demonstrates the document hierarchy for any frameset. This code walks the window hierarchy in a specified browser instance and outputs the document containership hierarchy.

<HTML>
   <HEAD>
      <TITLE>Frameset Hierarchy</TITLE>
   </HEAD>
   <FRAMESET ROWS="60, *">
      <FRAME SRC="frames.htm">
      <FRAME SRC="anyDocument.htm" NAME="hierarchy">
   </FRAMESET>
</HTML>

The preceding file is a top-level frameset. In the bottom frame, it displays the document to be analyzed (anyDocument.htm, but you can substitute any document you want). In the top frame, it displays the document frames.htm, listed next, which consists of a button and JavaScript code. When you click the button, the code creates a separate window showing the document hierarchy. This example is included on the companion CD.

<HTML>
   <HEAD>
      <TITLE>Frameset Hierarchy Generator</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function drillFrames(doc, w) {     
            doc.write("<TR><TD>Name: " + w.name + "<BR>");
            doc.write("Location: " + w.location.href);
            for (var i = 0; i < w.frames.length; i++) {
               doc.write("<TABLE BORDER WIDTH=100% CELLPADDING=3>");
               drillFrames(doc, w.frames[i]);
               doc.write("</TABLE>");
            }        
            doc.write("</TD></TR>");
         }

         function outputFrames() {
            var doc = window.open().document;
            doc.open();
            doc.write("<H1>Frameset Hierarchy</H1>");
            doc.write("<TABLE BORDER CELLPADDING=3>");
            // Start at the sibling frame in the hierarchy.
            drillFrames(doc, parent.hierarchy);
            doc.write("</TABLE>");
            doc.close();
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <FORM>
         <INPUT TYPE=BUTTON VALUE="Walk" ONCLICK="outputFrames();">
      </FORM>
   </BODY>
</HTML>

Determining the Layout of the Frameset

The frames collection exposes the document hierarchy in the browser; it does not expose the physical divisions of each frameset. This information is exposed through the document object. The document object has an all collection, which represents every element in the document. Using the all collection, you can determine the order of the framesets and frames. The document object and the all collection are discussed in Part II. Programming the Frameset element is discussed in Chapter 9, "Scripting Individual Elements."

Determining Whether All Frames Have Been Downloaded

Framesets also expose an onload event on the frameset window. The onload event occurs when all the frames within the frameset finish loading. Therefore, any initialization that requires communicating across the frames in the frameset should be written in this event handler.

In addition, the frameset document exposes a property that can be used to query the current state of each frame and window: readyState. While each frame is being loaded, this property's value is interactive, and when all the frames have been downloaded, its value is complete. The readyState property can be used as a flag to verify that all the frames have been downloaded. The readyState property and the related onreadystatechange event are discussed in detail in Chapter 6, "The HTML Document."

Simulating a Browser

The code in this section shows how to create a very simple browser using framesets. This HTML document sets up the frameset:

<HTML>
   <TITLE>Frameset Browser Demo</TITLE>
   <FRAMESET ROWS="60, *">
      <FRAME NAME="browser" SRC="browser.htm">
      <FRAME NAME="content" SRC="">
   </FRAMESET>
</HTML>

The following document represents the browser.htm file that is rendered in the top frame. The top frame contains Go and Refresh buttons and a text box in which the user types the URL. A Forward and a Back button are included for moving through the history list. These buttons simulate the same functionality found on most browsers' toolbars:

<HTML>
   <HEAD>
      <TITLE>Browser Bar</TITLE>
   </HEAD>
   <BODY>
      <FORM NAME="BrowseBar" ONSUBMIT="parent.content.location.href =
            this.txtGo.value; return false;">
         <INPUT TYPE=BUTTON VALUE="Back"
            ONCLICK="parent.content.history.back();">
         <INPUT TYPE=BUTTON VALUE="Forward"
            ONCLICK="parent.content.history.forward();">
         <INPUT TYPE=BUTTON VALUE="Refresh"
            ONCLICK="parent.content.location.reload();">
         <INPUT TYPE=SUBMIT VALUE="Go">
         <INPUT TYPE=TEXT NAME="txtGo">
      </FORM>
   </BODY>
</HTML>


NOTE: Browser security restrictions might prevent the Forward and Back buttons in this code from navigating if the documents involved are in different domains.

In this example, the controls are placed within a Form element to ensure compatibility with Netscape Navigator 2.0 and 3.0, which fail to render any controls that are not inside Form elements. Internet Explorer versions 3.0 and later do not have this limitation and can display and script controls even if they exist outside of forms.

[Содержание]