digitalroom.net javascript & cgi javascript & cgi

Frame Protection

(JavaScript 1.0/JScript 1.0 compatible)

One major annoyance I have with web sites that use frames is that if you open a link explicitly, it will load the page outside of its original frameset. Search engines complicate this matter even further, as they link pages within such sites directly.

  1. Introduction
  2. Solutions?
  3. Detection?
  4. Redirection (server-side)
  5. Redirection (client-side)
  6. Source code
  7. Issues new


Introduction

The issues and solutions discussed throughout this article use my site as an example, which has a left (menu) frame and a right (main) frame. I'll also be referring to JavaScript from time to time, so these references might prove to be useful:


Solutions?

Any solution to this problem must be capable of two things:

  1. Detecting whether or not page has been loaded within its frameset.
  2. Redirecting or reloading the page so that it loads itself within its intended frameset.

It seems the only way to detect if frames are present on a web page is through JavaScript (on the client end), and it turns out this is not too difficult. However, things get a bit tricky when it comes to reloading the same page in a frame.

Assuming that our entire web site uses frames, we will have to place the frame-checking code in every single page - so we have to make sure that we keep this to a minimum. Adding 30 lines of JavaScript to every page on a web site isn't very elegant, nor does it do wonders for your users' download times.


Detection

There are two ways to detect (the presence or absence of) frames through JavaScript:

  1. Use the top.frames.length property, which returns the number of frames present in the current (top level) window.

  2. Use the predefined window properties : Self refers to the current window or frame, while Top refers to the topmost window or frameset. If "self == top", then we know that no frames are present.

(Both of these properties are supported under JavaScript 1.0 and JScript 1.0)

Once we use one of the two methods above to detect whether our page is valid, we need to redirect the current page to one that uses frames.

Unless you want to have a separate HTML file with a defined frameset for every document on your web site, the need to define and load a frameset dynamically becomes very apparent.


Redirection (server-side)

The easiest and most compatible solution is to call a CGI program that will redirect you to the framed page. Since CGI resides and runs on the web server, we won't run into any JavaScript compatibility issues.

As an example, let's suppose that this very page (/javascript/index.htmlframe.html) was loaded directly. The code below detects the absence of frames, and calls a CGI function with this page as a parameter:

<SCRIPT LANGUAGE="JavaScript">
  if (top.frames.length == 0) {
    top.location = "http://www.digitalroom.net/cgi-bin/framefix.cgi?new=javascript/frame.html";
    };
</SCRIPT>

If you don't have access to custom CGI/PHP etc. on your Web server or don't want your URLs to get mangled, then a client-side solution may be in order.

The upshot to this is that bookmarking an URL using this method bookmarks the actual page. Our next solution will always bookmark the homepage. It's a matter of preference really.


Redirection (client-side)

We use the same frame detection code as the CGI method, but in this case, we redirect the browser to an alternate page which will dynamically load our frameset. The method I'm using employs a browser cookie to save the current page's URL, and the new page will use this cookie as it defines the frameset. We only wind up adding 7-8 lines of code to each page within the web site for detection, and the bulk of the code (which retrieves and deletes the cookie) is kept within the redirection page.

(The document.referrer property, which specifies the URL of the calling document is not properly supported under JScript 1.0, always returning the URL of the current page)


Show me the code!

Add this code (customizing it to your needs if necessary) to every file on your web site, right after the <BODY> tag on each page.

<SCRIPT LANGUAGE="JavaScript">
<!--
  if (top.frames.length == 0) {
    document.cookie = "newURL=" + escape(document.URL) + "; path=/;"
    ver = parseInt(navigator.appVersion, 10);
    if ( ((navigator.appName == "Netscape") && (ver >= 3)) ||
         ((navigator.appName == "Microsoft Internet Explorer") && (ver >= 4)) )
      location.replace("/index2.html");
    else
      location = "/index2.html";
    };
//-->
</SCRIPT>

Explanation:


index2.html essentially defines the same frameset as the main start page (index.html) for my web site, except that it loads the right (main) frame dynamically as defined by our cookie:

<HTML>
<HEAD>
<TITLE>Redirection Example</TITLE>

<SCRIPT language="JavaScript">
<!--

var newURL = getCookie('newURL');
if (newURL == null) newURL = "main.html";

document.write('<FRAMESET ROWS="*,35" FRAMEBORDER=0 FRAMESPACING=0 BORDER=0>');
  document.write('<FRAMESET COLS="130,*" BORDER=0 FRAMEBORDER=0 FRAMESPACING=0>');
    document.write('<FRAME SRC="menu.html" NAME="menu" SCROLLING="auto" NORESIZE MARGINHEIGHT=0 MARGINWIDTH=0>');
    document.write('<FRAME SRC="',newURL,'" NAME="main" SCROLLING="auto">');
  document.write('</FRAMESET>');
  document.write('<FRAMESET COLS="130,*" FRAMEBORDER=0 FRAMESPACING=0 BORDER=0>');
    document.write('<FRAME SRC="navtitle.html" NAME="navtitle" SCROLLING="no" MARGINHEIGHT=0 MARGINWIDTH=0>');
    document.write('<FRAME SRC="nav.html" NAME="nav" SCROLLING="no" MARGINHEIGHT=0 MARGINWIDTH=0>');
  document.write('</FRAMESET>');
document.write('</FRAMESET>');

deleteCookie('newURL', '/', null);

//-->
</SCRIPT>

</HEAD>
</HTML>

Explanation:

Something that is noticeably missing in this code are the getCookie() and deleteCookie() JavaScript functions. It is important to note that these are (unfortunately) not predefined functions within JavaScript and I have borrowed them from the Crispy JavaScript Cookies function archive. If you view the source of my index2.html page, you can copy/paste these functions into your own version of the file to suit your needs.

On a final note, there may be some cases in which you might want to hard-code the URL which you define in your cookie. For example, if I link the menu.html file of my web site directly, I wouldn't want it to reload the frameset with menu.html as the left frame, and menu.html as the right frame (since this would be stored in the newURL cookie). In cases like these, make sure to specify the right file you want to redirect to. For example:

    document.cookie = "newURL=" + escape("main.html") + "; path=/;"

Issues

This solution should work without any problems from Netscape 2.0 and Internet Explorer 3.0. The only time you will run into problems are if browser cookies are disabled, in which case the page will just redirect to the default page (as specified by index2.html).

NOTE! - Wim Vogel has pointed out to me that this solution prevents a user from printing any reloaded pages using Netscape 4.x. A description and workaround to this problem is available on Ivan Peters' site.

Last updated on February 06, 2000