Javascript [Electronic resources] : The Definitive Guide (4th Edition) نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Javascript [Electronic resources] : The Definitive Guide (4th Edition) - نسخه متنی

David Flanagan

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


13.11 Multiple Windows and Frames


Most of the client-side JavaScript
examples we've seen so far have involved only a single window
or frame. In the real world, JavaScript applications often involve
multiple windows or frames. Recall that frames within a window are
represented by Window objects; JavaScript makes little distinction
between windows and frames. In the most interesting applications,
there is JavaScript code that runs independently in each of several
windows. The next section explains how the JavaScript code in each
window can interact and cooperate with each of the other windows and
with the scripts running in each of those windows.


13.11.1 Relationships Between Frames



We've already seen that the
open( ) method of the Window object returns a new
Window object representing the newly created window. We've also
seen that this new window has an opener property
that refers back to the original window. In this way, the two windows
can refer to each other, and each can read properties and invoke
methods of the other. The same thing is possible with frames. Any
frame in a window can refer to any other frame through the use of the
frames, parent, and
top properties of the Window object.

Every window has a frames property.
This property refers to an array of Window objects, each of which
represents a frame contained within the window. (If a window does not
have any frames, the frames[] array is empty and
frames.length is zero.) Thus, a window (or frame)
can refer to its first subframe as frames[0], its
second subframe as frames[1], and so on.
Similarly, JavaScript code running in a window can refer to the third
subframe of its second frame like this:

frames[1].frames[2]

Every window also has a
parent property, which refers to the Window object
in which it is contained. Thus, the first frame within a window might
refer to its sibling frame (the second frame within the window) like
this:

parent.frames[1] 

If a window is a top-level window and not a frame,
parent simply refers to the window itself:

parent == self;  // For any top-level window

If a frame is contained within another frame that is contained within
a top-level window, that frame can refer to the top-level window as
parent.parent. The top property is a
general-case shortcut, however: no matter how deeply a frame is
nested, its top property refers to the top-level
containing window. If a Window object represents a top-level window,
top simply refers to that window itself. For
frames that are direct children of a top-level window, the
top property is the same as the
parent property.

Frames are typically created with
<frameset>
and
<frame> tags. In HTML 4, however, as
implemented in IE 4 and later and Netscape 6 and later, the
<iframe> tag can also be used to create an
"inline
frame" within a document. As far as JavaScript is concerned,
frames created with <iframe> are the same as
frames created with <frameset> and
<frame>. Everything discussed here applies
to both kinds of frames.

Figure 13-4 illustrates these relationships between
frames and shows how code running in any one frame can refer to any
other frame through the use of the frames,
parent, and top properties. The
figure shows a browser window that contains two frames, one on top of
the other. The second frame (the larger one on the bottom) itself
contains three subframes, side by side.


Figure 13-4. Relationships between frames


With this understanding of the relationships between frames, you may
want to revisit Example 13-6, paying particular
attention this time to the way the code (which is written to run in a
second frame) refers to the history and
location properties of the first frame.


13.11.2 Window and Frame Names



The second, optional argument to the
open( ) method discussed earlier is a name for the
newly created window. When you create a frame with the

HTML <frame>
tag, you can specify a name with the name
attribute. An important reason to specify names for windows and
frames is that those names can be used as the value of the

target attribute
of the
<a>,
<map>



, and
<form> tags. This value tells the browser
where you want to display the results of activating a link, clicking
on an image map, or submitting a form.

For example, if you have two windows, one named
table_of_contents and the other
mainwin, you might have HTML like the following in
the table_of_contents window:

<a href=" target="mainwin">
Chapter 1, Introduction
</a>

The browser loads the specified URL when the user clicks on this
hyperlink, but instead of displaying the URL in the same window as
the link, it displays it in the window named
mainwin. If there is no window with the name
mainwin, clicking the link creates a new window
with that name and loads the specified URL into it.

The target and name attributes
are part of HTML and operate without the intervention of JavaScript,
but there are also JavaScript-related reasons to give names to your
frames. We've seen that every Window object has a
frames[] array that contains references to each of
its frames. This array contains all the frames in a window (or
frame), whether or not they have names. If a frame is given a name,
however, a reference to that frame is also stored in a new property
of the parent Window object. The name of that new property is the
same as the name of the frame. Therefore, you might create a frame
with HTML like this:

<frame name="table_of_contents" src="2"> 

Now you can refer to that frame from another,
sibling frame with:

parent.table_of_contents

This makes your code easier to read and understand than using (and
relying on) a hardcoded array index, as you'd have to do with
an unnamed frame:

parent.frames[1]

The name property of
any Window
object contains the
name of that window. In JavaScript 1.0, this property is read-only.
In JavaScript 1.1 and later, however, you can set this property,
thereby changing the name of a window or a frame. One common reason
to do this is to set the name of the initial browser window. When a
browser starts up, the initial window has no name, so it cannot be
used with the target attribute. If you set the
name property of the window, however, you can then
use that name in target attributes.


13.11.3 JavaScript in Interacting Windows


Chapter 12: the Window object serves as
the global object for client-side JavaScript code, and the window
serves as the execution context for all JavaScript
code it contains. This holds true for frames as well: every frame is
an independent JavaScript execution context. Because every Window
object is its own global object, each window defines its own
namespace and its own set of global variables. When viewed from the
perspective of multiple frames or windows, global variables do not
seem all that global, after all!

Although each window and frame defines an independent JavaScript
execution context, this does not mean that JavaScript code running in
one window is isolated from code running in other windows. Code
running in one frame has a different Window object at the top of its
scope chain than code running in another frame. However, the code
from both frames is executed by the same JavaScript interpreter, in
the same JavaScript environment. As we've seen, one frame can
refer to any other frame using the frames,
parent, and top properties. So,
although JavaScript code in different frames is executed with
different scope chains, the code in one frame can
still refer to and use the

variables and functions defined by
code in another frame.

For example, suppose code in frame A defines a variable
i:

var i = 3; 

That variable is nothing more than a property of the global
object -- a property of the Window object. Code in frame A could
refer to the variable explicitly as such a property with either of
these two expressions:

window.i
self.i

Now suppose that frame A has a sibling frame B that wants to set the
value of the variable i defined by the code in
frame A. If frame B just sets a variable i, it
merely succeeds in creating a new property of its own Window object.
So instead, it must explicitly refer to the property
i in its sibling frame with code like this:

parent.frames[0].i = 4;

Recall that the


function
keyword that defines functions declares a variable just like the
var keyword does. If JavaScript code in frame A
declares a function f, that function is defined
only within frame A. Code in frame A can invoke f
like this:

f(  ); 

Code in frame B, however, must refer to f as a
property of the Window object of frame A:

parent.frames[0].f(  ); 

If the code in frame B needs to use this function frequently, it
might assign the function to a variable of frame B so that it can
more conveniently refer to the function:

var f = parent.frames[0].f; 

Now code in frame B can invoke the function as f(
), just as code in frame A does.

When you share functions between frames or windows like this, it is
very important to keep the rules of lexical scoping in mind. A function is
executed in the scope in which it was defined, not in the scope from
which it is invoked. Thus, to continue with the previous example, if
the function f refers to global variables, these
variables are looked up as properties of frame A, even when the
function is invoked from frame B.

If you don't pay careful attention to this, you can end up with
programs that behave in unexpected and confusing ways. For example,
suppose you define the following function in the
<head> section of a multiframe document,
with the idea that it will help with debugging:

function debug(msg) {
alert("Debugging message from frame: " + name + "\n" + msg);
}

The JavaScript code in each of your frames can refer to this function
as top.debug( ). Whenever this function is
invoked, however, it looks up the variable name in
the context of the top-level window in which the function is defined,
rather than the context of the frame from which it is invoked. Thus,
the debugging messages always carry the name of the top-level window,
rather than the name of the frame that sent the message, as was
intended.

Remember that constructors are also
functions, so when you define a class of objects with a constructor
function and an associated prototype object, that class is defined
only for a single window. Recall the Complex class we defined in
Chapter 8, and consider the following multiframed
HTML document:

<head>
<script src="/image/library/english/10113_Complex.js"></script>
</head>
<frameset rows="50%,50%">
<frame name="frame1" src=">
<frame name="frame2" src=">
</frameset>

JavaScript code in the files

and

cannot create a Complex object with
an expression like this:

var c = new Complex(1,2);  // Won't work from either frame 

Instead, code in these files must explicitly refer to the constructor
function:

var c = new top.Complex(3,4); 

Alternatively, code in either frame can define its own variable to
refer more conveniently to the constructor function:

var Complex = top.Complex;
var c = new Complex(1,2);

Unlike user-defined constructors, predefined
constructors are automatically
predefined in all windows. Note, however, that each window has an
independent copy of the constructor and an independent copy of the
constructor's prototype object. For example, each window has
its own copy of the String( ) constructor and the
String.prototype object. So, if you write a new
method for manipulating JavaScript strings and then make it a method
of the String class by assigning it to the
String.prototype object in the current window, all
strings in that window can use the new method. However, the new
method is not accessible to strings defined in other windows. Note
that it does not matter which window holds a reference to the string;
only the window in which the string was actually created matters.


13.11.4 Example: Colored Frames


Example 13-7, a


frame set that defines a grid of nine
frames, demonstrates some of the techniques we've discussed in
this chapter. The <head> section of the
frame set includes a <script> that defines a
JavaScript function named setcolor( ). The
onload event handler of the
<frameset> tag invokes setcolor(
) once for each of the nine frames.

setcolor( ) is passed a Window object as its
argument. It generates a random color and uses it with the
Document.write( ) method to create a new document
that is empty except for a background color. Finally,
setcolor( ) uses the setTimeout(
) method to schedule itself to be called again in one
second. This call to setTimeout( ) is the most
interesting part of the example. Notice especially how it uses the
parent and name properties of
Window objects.

Example 13-7. A frame color animation

<head>
<title>Colored Frames</title>
<script>
function setcolor(w) {
// Generate a random color
var r = Math.floor((Math.random( ) * 256)).toString(16);
var g = Math.floor((Math.random( ) * 256)).toString(16);
var b = Math.floor((Math.random( ) * 256)).toString(16);
var colorString = "#" + r + g + b;
// Set the frame background to the random color
w.document.write("<body bgcolor='" + colorString + "'></body>");
w.document.close( );
// Schedule another call to this method in one second.
// Since we call the setTimeout( ) method of the frame, the string
// will be executed in that context, so we must prefix properties
// of the top-level window with "parent.".
w.setTimeout('parent.setcolor(parent.' + w.name + ')', 1000);
// We could also have done the same thing more simply like this:
// setTimeout('setcolor(' + w.name + ')', 1000);
}
</script>
</head>
<frameset rows="33%,33%,34%" cols="33%,33%,34%"
onload="for(var i = 0; i < 9; i++) setcolor(frames[i]);">
<frame name="f1" src="''"><frame name="f2" src="''">
<frame name="f3" src="''"><frame name="f4" src="''">
<frame name="f5" src="''"><frame name="f6" src="''">
<frame name="f7" src="''"><frame name="f8" src="''">
<frame name="f9" src="''">
</frameset>


/ 844