Приглашаем посетить
Клюев (klyuev.lit-info.ru)

Programming the Body and Frameset Elements

Programming the Body and Frameset Elements

An HTML document can contain either of two types of contents: body contents or a frameset definition. The first Body or Frameset element appearing in the document defines the document's type. A similar object model is exposed for the document in both cases.

The body Property

The document object exposes a body property that represents the root of the document's contents. The name of this property is ambiguous because the body property can represent either a Frameset or a Body element, depending on the document type. As explained in Chapter 7, "Document Element Collections," every document has a Body or Frameset element, regardless of whether it is explicitly declared. If a document's frameset nests other Frameset elements, the body property represents the outermost Frameset element in the document.

The Body or Frameset element is also contained in the document's all collection. Thus, the body property can be accessed directly from the document as follows:

// Returns BODY or FRAMESET depending on the type of document.
document.body.tagName;

Or it can be accessed through the all collection:

// For documents with a Body element
document.all.tags("Body").item(0).tagName;       // Returns "BODY"
/* Displays "true"; demonstrates that the two elements are the
   same */
alert(document.all.tags("Body").item(0) == document.body);

// For documents with a Frameset element
document.all.tags("Frameset").item(0).tagName;   // Returns "FRAMESET"
/* Displays "true"; demonstrates that the two elements are the
   same */
alert(document.all.tags("Frameset").item(0) == document.body);

In the preceding code, the tags method returns a collection consisting of the Body or the Frameset elements. If the document has a Body element, the HTML DTD (document type definition) limits it to a single Body element, and the parser ignores any extra ones. If the document has a Frameset element, it can have multiple Frameset elements; the tags method returns all of them, beginning with the outermost one. In either case, the first element in the collection returned by the tags method is the element contained in the body property. The code uses item to access this element.

Availability of the body Property

The object model is constructed and exposed simultaneously during the parsing of the document. Before the parser encounters the body or frameset of the document, the body property is not available, and therefore the body property returns null. The following code illustrates the availability of the body property:

<HTML>
   <SCRIPT LANGUAGE="JavaScript">
      alert(document.body == null);    // true--precedes <BODY> tag
   </SCRIPT>
   <BODY>
      <SCRIPT LANGUAGE="JavaScript">
         alert(document.body == null); // false--follows <BODY> tag
      </SCRIPT>
   </BODY>
</HTML>

For documents with body contents, the <BODY> tag does not have to appear explicitly in the document to be accessible. Instead, the Body element is implicitly created once the document contains an element—or simply some text—that must be a part of the body. The elements that make up body contents are defined by the HTML DTD. Chapter 1, "Overview of HTML and CSS," explains how to read a DTD, and more information about how the document is parsed is provided in Chapter 7, "Document Element Collections."

Distinguishing Between Body and Frameset Contents

You can use the tagName property to determine whether a document contains a body or a frameset. The following code displays an alert box reporting its document type—in this case, a frameset:

<HTML>
   <HEAD>
      <TITLE>Frameset Exposed as the Body</TITLE>
   </HEAD>
   <FRAMESET ROWS="100%" ONLOAD="alert(document.body.tagName);">
      <FRAME SRC="foo.htm">
   </FRAMESET>
</HTML>

Checking the length of the frames collection on the window is not an accurate way to determine whether a document is a frameset. A document with a Body element may contain IFrame elements, which would be included in the frames collection.

Client Window and Document Size

The width and height of the client window are exposed as properties of the Body and Frame elements. The physical size of the document is the size of the client area— that is, the amount of space the document occupies on the screen. The logical size of the document is the size of the contents. For document contents that are larger than the window, scrollbars are usually displayed. Figure 9-1 illustrates the properties that represent the physical and logical size of the document, and the subsequent sections describe them. Other elements in the document can expose the same properties for determining their size. The special relationship these properties share with other elements in the document is discussed in Chapter 12, "Dynamic Positioning."

Physical Size

The physical width and height of the document (frameset or body type) are exposed through the offsetWidth and offsetHeight properties of the Frameset or Body element. The physical width and height measure the area of the currently visible window including the scrollbars. The clientWidth and clientHeight properties are exposed to determine the size of the client area—the physical size as defined by the offsetWidth and offsetHeight properties less the size of the scrollbars and surrounding borders. These properties are read-only and cannot be used to change the size of the window.

In Figure 9-1, no horizontal scrollbar is displayed, so the offsetHeight and clientHeight properties would be the same if the border was set to 0. However, a vertical scrollbar is displayed, so the offsetWidth and clientWidth properties represent distinct values.

Programming the Body and Frameset Elements

Figure 9-1. Properties for determining the window and document size.

Logical Size

The Body element exposes four properties for determining the logical size of the document and the position of the user's view into the document: scrollWidth, scrollHeight, scrollTop, and scrollLeft. The logical size of the document represents the total height and width of the document, not the size of the browser window that provides a view into the document. These properties are not available or necessary on frameset documents because the logical size of the frameset is equivalent to its physical size.

The scrollWidth and scrollHeight properties represent the logical size of the document in pixels. These properties are read-only and are calculated by the browser based on the document contents. You can change the scrollWidth and scrollHeight properties by dynamically adding or removing elements or by resizing the window. Resizing the window usually affects both properties because the contents rewrap to the new width.

The scrollTop and scrollLeft properties represent the scroll offsets of the logical document. They represent the point in the document that is displayed in the upper-left corner of the window. When the horizontal and vertical scrollbars are scrolled all the way to the left and top edges of the document, scrollLeft and scrollTop both equal 0. These properties are read/write and can be modified to immediately scroll the document to a particular pixel position. If you need to set scrollLeft and scrollTop at the same time, the scroll method on the window is a more convenient mechanism because it takes both new coordinates, horizontal and vertical, as arguments.

As a group, these properties provide information for determining the visible portion of the screen. The currently viewable area of the document can be easily calculated using the size properties, as shown here:

upperLeftX = document.body.scrollLeft;
upperLeftY = document.body.scrollTop;
lowerRightX = upperLeftX + document.body.clientWidth;
lowerRightY = upperLeftY + document.body.clientHeight;

The scrolling-related properties are also exposed on any other scrolling element. For example, you can give a Div element scrollbars using the CSS (Cascading Style Sheets) overflow3 property, and the TextArea element displays scrollbars by default. When these elements have scrollbars, they expose the scrolling-related properties for determining the scrolled regions of their contents. The TextArea element is discussed in detail in Chapter 10, "Forms and Intrinsic Controls," and the CSS overflow property is discussed in Chapter 12, "Dynamic Positioning."

Window Events

The Body and Frameset elements expose attributes corresponding to all window-level events. For example, the following code in a document with a Body element specifies an ONLOAD event handler for the window:

<BODY ONLOAD="doThis();">

The code for a frameset document is similar:

<FRAMESET ONLOAD="doThis();" ROWS="*">

Even when you use the <BODY> or <FRAMESET> tag to specify the handler for a window event, the event is scoped to the window object, not to the body object. This distinction is important when you use the this pointer in the event handler. In a body-level event handler, this points to the body object; in a window event handler, this points to the window object, even if you specify the handler in the <BODY> tag. The following code illustrates how this pointers work for a window event (onload) and a body event (onclick):

<BODY ONLOAD="alert(this == document.body);  // false"
   ONCLICK="alert(this == document.body);    // true">
</BODY>

Furthermore, for window events, the srcElement property of the event object contains null.

While a document can have multiple framesets, it can have only one handler for each window event. If several Frameset elements in the document define handlers for an event, only the last handler's code is executed. In the following example, only the second onload event handler executes, displaying the alert b. The event does not fire until the entire document is loaded.

<HTML>
   <HEAD>
      <TITLE>Frameset onload Event</TITLE>
   </HEAD>
   <FRAMESET ONLOAD="alert(`a');" ROWS="100, *">
      <FRAMESET ONLOAD="alert(`b');" COLS="*.*">
         <FRAME SRC="a.htm">
         <FRAME SRC="b.htm">
      </FRAMESET>
      <FRAME SRC="c.htm">
   </FRAMESET>
</HTML>

Because you can define only one handler per window event, you cannot specify a handler on a Frame or nested Frameset element that works only for that particular element. To protect against this behavior possibly changing in the future, window event handlers should be specified only on the first Frameset element.

The onresize Event

The onresize event is fired whenever the size of the physical window changes, not the size of the contents within the body or frameset document. Therefore, this event is actually a window event when defined on the Body element. The onresize event is also exposed on elements within the document that have a defined size. In those cases, the event fires only when the physical size of the element changes.

When a document is first loaded into a new window, the onresize event does not fire. Therefore, if code is being used to lay out the document based on the initial window size, the code should be called from the onload event.

Programming Body Contents

Documents that contain a Body element have a few additional features not available to frameset documents, including access to the HTML and textual contents contained within the body and an onscroll event that fires when the window is scrolled.

You can write scripts to manipulate the text in the Body element or any element in the body. The techniques are discussed in Chapter 13, "Dynamic Contents."

The onscroll Event

The window object exposes an onscroll event that fires whenever the window is scrolled either explicitly by the user or through code. This event occurs only in documents with Body elements and not in frameset documents because they do not display scrollbars.

Programming Frameset Contents

Because the frameset document is another type of HTML document, it supports the document object model. The frameset document exposes an all collection that provides direct access to all the elements in the document. Through the all collection, the individual attributes of each Frameset and Frame element can be accessed and in many cases dynamically modified.

While the number of frames in the frameset is static and cannot be modified without creating a new document, a number of the attributes of the Frameset element can be changed. For example, the ROWS and COLS attributes are read/write attributes, which allows you to change the layout of the frameset dynamically. This flexibility can be used to add custom behavior to a traditional frameset.

The following code creates a custom layout that allows the user to select from a set of pages. This example turns off the resizing capability of each frame and instead automatically expands the frame the user clicks on. This layout model requires a small amount of code behind the frameset and each document.

<HTML>
   <HEAD>
      <TITLE>Sliding Frames</TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         var defSize = 25;

         function display(f) {
            var newRows = "";
            // Get all the Frame elements.
            var elFrame = document.all.tags("FRAME");
            for (var intFrames = 0; intFrames < frames.length;
                  intFrames++) {
               var curF = frames[intFrames].document;
               if (curF.body == f.document.body) {
                  // Give selected frame all the space.
                  newRows += "*, ";
                  /* Make the header much bigger. */
                  curF.all.header.style.fontSize = "200%";
                  /* Turn on scrollbars for the active frame
                     by accessing the Frame element
                     in the frameset document. */
                  elFrame[intFrames].scrolling = "yes";
               }
               else {
                  // Set to default size.
                  newRows += defSize.toString() + ", ";
                  // Reset header font size.
                  curF.all.header.style.fontSize = "";
                  // Turn off scrolling.
                  elFrame[intFrames].scrolling = "no";
               }
            }
            document.body.rows = newRows;
         }
      </SCRIPT>
   </HEAD>
   <FRAMESET ROWS="*, 25, 25">
      <FRAME SRC="home.htm" NORESIZE>
      <FRAME SRC="news.htm" NORESIZE SCROLLING="No">
      <FRAME SRC="info.htm" NORESIZE SCROLLING="No">
   </FRAMESET>
</HTML>

Figure 9-2 demonstrates this code in action. When the user clicks on the News or Information heading, the other frames automatically shrink and the selected frame expands to take up the remaining view.

Programming the Body and Frameset Elements

Figure 9-2. An example of automatically sliding frames.

In each document in the frameset, the onfocus event handler must call the display routine. The parent property on the document must be referenced to call the function:

<!-- The onfocus event must be defined for each document in the
     frameset. -->
<BODY ONFOCUS="parent.display(this);">

Also in each document in the frameset, the ID of the first paragraph must have the value header. The text in this paragraph will be enlarged when the document has the focus.

This example demonstrates modifying the attributes of individual frames. The Frame element in the all collection of the document is different from the contents of the window's frames collection. The frames collection on the window returns the window instance created based on the document's source. The Frame element in the all collection represents the frame as defined by the HTML source and is used to create the window. Modifying the Frame element can modify the window and its contents—for example, scrollbars can be manually turned on and off. Scrollbars have been turned off in our example so that they do not clutter the collapsed heading view of the document.

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