ColdFusion in Context: Breaking Frames Without Javascript

Suppose you want to send users home whose sessions have timed out or who have strayed into areas of the application in which they don't belong. Users who have talking browsers often have turned off javascript; so, you need a method that doesn't rely on javascript. If parts of your application use frames but your home page doesn't, here's an approach that will work.

Alternatives That Don't Work

The literature leads you to believe that you can send a header containing "window-target: _top" and have it honored by Netscape browsers. However, this doesn't work reliably and would only be browser-specific anyway. Base target="_top" doesn't work either for this purpose. It affects only subsequent controls (links and forms) on this page.

Other tools you might expect to solve the problem don't. ColdFusion's cflocation tag doesn't have a target attribute. The cfinclude tag adds code to the current page which is already locked inside a frame. Aiming cflocation at the parent of a different frameset puts the new frame inside the current frame. Meta refresh doesn't have a target attribute.

Links and forms do have target attributes and can pop frames, but you can't automatically submit them without javascript.

Most of the hands-off navigation of frames is therefore made possible by javascript. Javascript is used to pop the frame at the client. Javascript can be used to automatically change the location as it does this. Javascript can also be used to automatically submit a form that specifies a target.

Alternatives That Do

Without javascript, you're left with links and forms, both of which require explicit action from the user. However, that isn't so bad. You generally want the user to know what's going on when you drop the user out of an application. When javascript is available, you usually use a javascript alert followed by a javascript redirect. If you're going to do that anyway, then a statement followed by a link or a form submit button is a reasonable method of achieving this result.

See a Form Work

I vote for the form. To see it work, set the stage as follows. Imagine that a frame discovers that the user does not have the right role for a given task. Put this code in left.cfm.

<cfparam name="url.Role" default="">
<cfif url.Role is not "Friend">
  <form target="_top" action="home.cfm" method="post">
    You have strayed and must go home.
  <input type="submit" value="OK">
  </form>
  <cfabort>
</cfif>
My Menu

Here's the right frame; put it in right.cfm.

My Display

Here's the frameset; put it in main.cfm, and give it a way to pass a value to left.cfm. As with all framesets, be sure to put the frameset after the head and before the body of the page.

<head>
</head>
<cfparam name="url.Role" default="">
<frameset cols="20%,*">
<frame src="left.cfm?Role=<cfoutput>#url.Role#</cfoutput>" name="Menu">
<frame src="right.cfm" name="Display">
</frameset>
<body>

Here's home; put it in home.cfm.

<a href="main.cfm">Go to Main and get bounced back</a>
<a href="main.cfm?Role=Friend">Go to Main and Stay</a>

Browse home.cfm and try both links. The first will give you a form telling you what's wrong and what will happen. The second shows you the application without interruption. =Marty=