JavaScript-Simulated Modal Dialog Windows
by Jim Allen
A Modal Dialog Window is a popup window that always stays on top.
Two modal windows are built into every browser. Try them:
Because of the disadvantages of these two
built-in modal windows, web designers try to use the browser popup window
as a modal window, but there are problems with this approach, too.
Ordinary popup windows will disappear behind other windows
when you click outside their borders.
Open an ordinary popup window and try it.
These little popup windows fall behind other windows,
they get lost and might never get closed. In contrast, a modal window
always stays on top, in your face, until the programmer or the user closes it.
The onBlur Focuser: As a first attempt to bring a popup window
to the top and keep it there, using this code in the popup
is the right idea. [1]:
<body onblur = "window.focus( )">
Whenever the popup window loses focus (blurs), this script will bring it back
into focus. When a window gains focus, it moves to the top.
The problem with this solution is that modal windows often have forms in them,
and when the user clicks to fill out the form, focus moves to the form.
This causes the script to activate and return focus back to the window,
and then the user cannot continue filling out the form. Each time the user clicks
in the form field, the script awakens and takes the focus away from the textbox
and returns it to the window. (This behavior happens in IE, but not Netscape.)
Here, try the onBlur Focuser.
Another possible solution is to use showModalDialog. [2]
But this method is Internet Explorer specific - you will still need
a solution for Netscape. But worse, MSIE's code does not seem to work in the way
MS claims! [3] In fact, after several hours of fiddling,
I'm becoming inclined to agree with others [4]
that it doesn't work at all (at least on the Mac IE5).
Maybe I'll try this one again sometime.
The setTimeout Focuser: Several sources [5] suggest this work-around:
<body onblur = "setTimeout('self.focus( )',5000">
which gives the user up to five seconds to fill out the form, before refocusing on the window.
This technique contains the germ of a solution, but is not quite right. The 5 seconds (5000 milliseconds)
is arbitrary; success depends on the attention span and typing speed of the user. Also,
this window can submarine and be lost for up to 4.9 seconds, and then it resurfaces mysteriously.
Here, you can test the setTimeout Focuser yourself, too.
Is there an all-encompassing, airtight solution to this problem? The Javascript Apostle,
Danny Goodman, presents a complete solution [6]
at Netscape's developer's site that would warm the soul of any hardcore programmer!
But it sends chills of fear through the rest of us! Danny goes on and on through 3 pages
of dense, convoluted code that I could never reproduce on a whim. It's the kind of code
that you cut and paste into your document and pray to the gods of binary that it works.
Now I don't want to sound prejudiced against hardcore coders; I myself have produced
reams of code, too, when called upon. But most of the time on the web,
the programming goals are different. Websites are ephemeral; here today
and superceded, redesigned, remodelled or bankrupt tomorrow. Pace apostle,
it's just not worth
large amounts of coding time to carry out what should be a simple task.
But note, it's not "short and dirty, brute force methods" that we're after, either.
As I tell my colleagues, the code must not only be useful, but must be beautiful, too!
In fact, it is the beauty of the code that tells you that you've got it right.
Good scripting solutions have a special simplicity and symmetry. It's not just brevity,
but a spare elegance that makes it 'logical' and easy to reproduce from memory.
Truth is beauty, and beauty truth.
The Solution: As I suggested above, both the onBlur Focuser and the setTimeout Focuser contain
the germs of a solution to the problem. First, I reproduce the behavior of the
onBlur Focuser with a setTimeout initiated function:
function fcsOnMe(){
window.focus();
mytimer = setTimeout('fcsOnMe()', 500);
}
This function is initially set into motion in the body tag:
<body onLoad = "mytimer = setTimeout('fcsOnMe()', 500);">
Once the page loads, the function fcsOnMe() runs every half-second (500 milliseconds) and
gives the focus to the popup window. The function then sets itself to be called again
in 500 more milliseconds, over and over. At this point, the script functions like the onBlur Focuser,
and access to form elements is interfered with by the constant refocusing.
What is needed now is some way to allow the form elements to switch the
refocusing cycle off and on again, as the form fields gain and lose focus.
I realized that form elements have
onFocus and onBlur event handlers (on both browsers - always a plus!) which
could do the switching. Thus:
I wrap a switch around the focuser:
if (!skipcycle){
window.focus();
}
Then I add control over this switch to every form field:
<input type="text" onfocus="skipcycle=true" onblur="skipcycle=false">
And that's it! The popup window stays on top, and yet still allows complete
use of forms - a javascript-simulated modal dialog window. You can click here to
test my Javascript-Simulated Modal Dialog Window.
Here is the full script of the window you are testing:
<html>
<head>
<script language="javascript"><!--
var skipcycle = false
function fcsOnMe(){
if (!skipcycle){
window.focus();
}
mytimer = setTimeout('fcsOnMe()', 500);
}
//-->
</script>
</head>
<body onload = "mytimer = setTimeout('fcsOnMe()', 500);">
<FORM name="test">
<input type="text" name="a" size="20" onfocus="skipcycle=true" onblur="skipcycle=false"><br>
<input type="text" name="b" size="20" onfocus="skipcycle=true" onblur="skipcycle=false"><br>
<input type="text" name="c" size="20" onfocus="skipcycle=true" onblur="skipcycle=false"><br>
<input type="submit">
</form>
</body>
</html>
Admittedly, this solution does not lock out click access to the parent window,
a possible source of trouble pointed out in Danny Goodman's article. [7]
Yes, it might be possible for a very fast mouseclicker to click around
in the parent window during the milliseconds
that the modal window is submerged, and break the context between parent and child
windows. If this really worries you, you could shorten the 500 milliseconds of the
refocusing cycle. However, users exhibiting this behavior are not trying
to succeed on my webpages, they are trying to break things. I don't really mind
if they fail to send me form data. For many purposes, this is a pseudo-problem.
Another way you can tell that something is right is when you can easily
make the script into a game. I was testing the modal windows on both major browsers,
and began to wonder:
what if there were two modal windows,
each fighting to be on top... and thus was created the self-playing video game
Battling Modal Windows!
Enjoy!
Jim Allen
tjallen@pipeline.com
Quick Printable Instructions
for installing Allen's Modal Dialog Windows
Footnotes:
- Both Doc JavaScript and
Danny Goodman
mention this before giving other answers.
- See Microsoft's reference page
for the official syntax.
- At least two sources suggest the syntax should be = and not : See both
Doc JavaScript and Microsoft's own
reader's comments.
- See the comments of users on Microsoft's own site!
- Doc JavaScript among others.
- Danny Goodman's Simulating Modal Dialog Windows.
- ibid
Some Resources:
- Almost Complete Control of Popup Windows by Martin Webb of irt.org. This is great stuff!
- Dialog Boxes at webreference.com
- The Importance of Good Dialog by Dave Massy
(DHTML-Dude guest column at msdn's Web Workshop)
- Danny Goodman's famous Simulating Modal Dialog Windows.
- Microsoft's Reference pages for modal dialog windows.
March 27, 2001 original draft
April 3, 2001 small clarification
|
|