7.6 Assuring a Page Loads in its Frameset
NN 2, IE 3
7.6.1 Problem
You want a page
bookmarked from a frame within a frameset to load within its
frameset.
7.6.2 Solution
For a frameset that always consists of the same framed documents,
include a script patterned on the one below in each
frame's document. This solution includes a test for
a peculiarity of the Netscape Navigator 4 browser described in the
Discussion section:
var isNav4 = (navigator.appName = = "Netscape" &&
parseInt(navigator.appVersion) = = 4);
if (top.location.href = = self.location.href) {
if (isNav4) {
if (window.innerWidth != 0) {
top.location.href="frameset12.html";
}
} else {
top.location.href="frameset12.html";
}
}
If a user has bookmarked a page with the previous script in it, the
page will begin to load, but will then load the frameset that
normally houses the page.
7.6.3 Discussion
The Navigator 4 issue affects
the Windows version in particular. In that browser, when a user
prints a frame, the page is automatically loaded into a temporary
window of zero width. Scripts run when the page loads into that
invisible window, so it's important to bypass the
frameset-loading routine when the page is being printed or else
you'll land in an infinite loop. If Navigator 4 is
not among your target audience, you can simplify the script to just
one branch:
if (top.location.href = = self.location.href) {
top.location.href="frameset12.html";
}
This script compares the URLs of the windows referred to as
top and self. If they are the
same, it means that the document is loading as the only one in the
browser window. You'll have to tailor the URL
assignment for each document containing this script so that the
desired frameset loads.
For a more fluid frameset, where one or more frames changes in
response to user action, you need more intelligence built into the
scripts and documents. At the core, each page's
document needs a script not only to load the frameset, but to convey
the URL of the page that needs loading into one of the frames. For
example, if a frameset contains a fixed navigation frame through a
product catalog, and the content frame's document
changes with each menu choice, you want a bookmark to one of the
product frames to load the frameset with that product showing.
To make this intelligent frame loading proceed correctly requires
scripts in each bookmarkable page and one in the frameset. Each page
sends information about itself by way of a search string appended to
the frameset page's URL; the
frameset's script receives that information and
loads the content frame accordingly.
Let's start with a content document. The script gets
all of its information from the page itself, so you can write this
script once as an external library and link it into each content
page. Here is the library script, which runs as the page loads:
var isNav4 = (navigator.appName = = "Netscape" &&
parseInt(navigator.appVersion) = = 4);
if (parent = = window) {
// Don't do anything if NN4 is printing frame
if (!isNav4 || (isNav4 && window.innerWidth != 0)) {
if (location.replace) {
// Use replace( ), if available, to keep current page out of history
location.replace("masterFrameset.html?content=" + escape(location.href));
} else {
location.href="masterFrameset.html?content=" + escape(location.href);
}
}
}
The current page's URL is attached to the URL of the
frameset in the form of a name/value pair, just like a typical form
submission search string. All browsers except some early ones apply
the location.replace(
) method so that the current page
won't be added to the browser's
history. If the page were to be part of the history, a user clicking
the Back button could get into an infinite backward loop because the
button would never be able to go any earlier than this page.
Code for the frameset consists of two functions, one of which is
triggered by the onload event handler of the
<frameset> tag. The key supporting function
converts the search string from the URL into an object whose property
name is the name part of the name/value pair passed in the search
string. The function also accommodates multiple name/value pairs
embedded in the search string in case you wish to pass additional
information to the frameset:
function getSearchData( ) {
var results = new Object( );
if (location.search.substr) {
var input = unescape(location.search.substr(1));
if (input) {
var srchArray = input.split("&");
var tempArray = new Array( );
for (var i = 0; i < srchArray.length; i++) {
tempArray = srchArray[i].split("=");
results[tempArray[0]] = tempArray[1];
}
}
}
return results;
}
The onload event handler of the frameset invokes
the following loadFrame(
) function, which reads the search
string data and applies the URL to the content frame:
function loadFrame( ) {
if (location.search) {
var srchArray = getSearchData( );
if (srchArray["content"]) {
self.content.location.href = srchArray["content"];
}
}
}
This example uses the same frame name (content) as
the property name in the name/value pair of the search string.
Theoretically, you could generalize the loadFrame(
) function to assign the URL to the frame whose name
arrives in the name/value pair. That design choice, however, places
the burden of knowing the destination frame at the individual frame
level. By leaving the specification to the frameset script, the
destination frame's name is kept within the context
of the affected frameset.
Assuming that the framesetting document contains a default URL for
the content frameset (i.e., for when the visitor first arrives to the
frameset), that default page stays in place if no search string
containing a content property name arrives with
the frameset URL. If a search string accompanies the URL, the default
page appears momentarily, until the passed URL is loaded into the
frame.
7.6.4 See Also
Recipe 7.5 for a script that keeps your site from being encapsulated
in someone else's frameset; Recipe 10.6 for more
examples of passing data between pages via URLs.
|