Handling Window Events
Window events occur when the user does something affecting an entire browser window. The most common window event is simply loading the window by opening a particular Web page. You can also have events that trigger event handlers when windows are closed, moved, or even sent to the background.
When working with event handlers, you'll often find it useful to connect an event handler to an object using dot syntax, like so:
window.onfocus
window.onload
document.onmousedown
Note that when you use the event handler as part of an object like this, the event handler is written all in lowercase. Also, keep your event handlers in external scripts, rather than placing them inside the HTML tagthis approach is more standards- compliant, it separates out the JavaScript code from the HTML code, and it's easier to edit (or replace) all your JavaScript code in an external file.
The onload event
We have used the onload event frequently throughout this book. It is triggered when the user enters your page and all its elements have completed loading. The epidemic of advertising pop-up windows is an example, though not an especially pleasant one, of the onload event handler in action.
Although we've shown onload repeatedly, up until now we've skipped one important bit of information: what to do when you have multiple things you need to have happen when the page loads. Scripts 9.1 and 9.2 demonstrate how to do this.
Script 9.1. The HTML for the multiple onload example.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Welcome!</title>
<script type="text/javascript"
language="Javascript" src="script01.js">
</script>
</head>
<body id="pageBody">
<h1>Welcome to our Web site!</h1>
</body>
</html>
|
Script 9.2. Setting multiple onload attributes using our new addOnload() function.
addOnload(initOne);
addOnload(initTwo);
addOnload(initThree);
function addOnload(newFunction) {
var oldOnload = window.onload;
if (typeof oldOnload == "function") {
window.onload = function() {
if (oldOnload) {
oldOnload();
}
newFunction();
}
}
else {
window.onload = newFunction;
}
}
function initOne() {
document.getElementById("pageBody").style. backgroundColor = "#0000FF";
}
function initTwo() {
document.getElementById("pageBody").style. color = "#FF0000";
}
function initThree() {
var allTags = document.getElementsByTagName ("*");
for (var i=0; i<allTags.length; i++) {
if (allTags[i].nodeName == "H1") {
allTags[i].style.border = "5px green solid";
allTags[i].style.padding = "25px";
allTags[i].style.backgroundColor = "#FFFFFF";
}
}
}
|
| | 1. |
addOnload(initOne);
addOnload(initTwo);
addOnload(initThree);
In this script, we'll want three entirely separate things to happen when the page first loads. Setting window.onload three times wouldn't work, because the second time would overwrite the first, and then the third would overwrite the second. Instead, we're calling a new function (defined below), addOnload(), which handles the onload handler for us. For each call, we're passing one parameter: the name of the function we want to run when an onload event is triggered. You can see the result in Figure 9.1.
| 2. |
function addOnload(newFunction) {
This line starts off a new function, much like any other function. What's being passed in is the name of a function.
This can be a bit confusing, so here's an example. Instead of calling
window.onload = myNewFunction;
we'll instead call
addOnload(myNewFunction);
which works out the same at the end.
| 3. |
var oldOnload = window.onload;
This line declares a new variable oldOnloadif we've already set window.onload, we'll store its value here. If we haven't, it doesn't hurt anything.
| | | 4. |
if (typeof oldOnload == "function") {
In this line, we check to see what kind of variable oldOnload is. If we've previously set window.onload, it'll be a function call (otherwise, it'll be nothing at all). If it's a function, do the following.
Tips
If you want to have an onload handler do more than one thing, the easiest way is to create one function that does everything, and then have the onload handler call that function. But make sure that each function returnsif, for example, your function contains a setTimeout() call to itself, it'll never return and therefore never go on to the rest of the called functions. If you're working with an existing body of code, it's easy to accidentally reset window.onloadany given HTML page can call multiple external JavaScript files, any of which can set the event handler. If one place sets window.onload directly, but every time after that you call addOnload(), you're fine. But if you set window.onload after you've set it previously (whether directly or via addOnload()), you'll have walked on top of your handler and lost its original value. This script is (very) loosely based on one by Simon Willison (simonwillison.net) and is used with his permission.
| 5. |
window.onload = function() {
if (oldOnload) {
oldOnload();
}
newFunction();
}
These lines of code reset the value of window.onload to do two things: whatever it was doing before, and our new function. The window.onload event handler is set to be an anonymous function (one that doesn't have a name). Then, if oldOnload has a value (which it should, but this works around a bug in Internet Explorer 7), we tell window.onload to do what it was already doing. But before the function ends, we add that it needs to also do our newFunction() as well.
| 6. |
else {
window.onload = newFunction;
}
If oldOnload wasn't a function, that is, it was undefined, we tell it do our new function when the page completes loading. In this fashion, we can call addOnload() multiple times: the first time it assigns its function to window.onload; the second and later times it creates that anonymous function, telling JavaScript to do everything it's been told to do previously and the new thing as well.
|
The onunload event
The onunload handler is triggered when the user leaves your Web page. The most common use for this is advertising windows that pop up when you leave some commercial sites, especially pornographic sites. If you find yourself on one of the latter, you'll often find that it's almost impossible to leaveevery time you close a window or attempt to navigate away from the site, window after window appears, re-opening the same or other pages, all of the same genre.
Consequently, people have come to hate the onunload handler with a passion, so use it sparingly.
The onresize event
Netscape 4.x has a well-known bug where dynamic content isn't redrawn when a Web page is resized. Scripts 9.3 and 9.4 force the page to reload its contents to avoid this problem. Thankfully, Netscape versions 6 and later no longer suffer from this bug.
Script 9.3. This HTML includes the JavaScript hidden inside a multi-line comment, since it's meant for use in older browsers.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>onResize Netscape fix</title>
<script language="Javascript" type="text/javascript" src="script02.js">
</script>
</head>
<body bgcolor="#FFFFFF">
<h1>
<script language="Javascript" type="text/javascript">
<!-- Hide code from older browsers
document.write("This is dynamic content")
// Stop hiding code -->
</script>
</h1>
</body>
</html>
|
Script 9.4. You can fix Netscape 4.x's dynamic content redraw bug with this script.
window.onresize = resizeFix;
if (document.layers) {
var origWidth = window.innerWidth;
var origHeight = window.innerHeight;
}
function resizeFix() {
if (document.layers) {
if (window.innerWidth != origWidth || window.innerHeight != origHeight) {
window.location.reload();
}
}
}
|
1. |
window.onresize = resizeFix;
The event handler is attached to the window object and calls the resizeFix function.
| 2. |
We only want to do the following if the user has Netscape 4.x, and this is the simplest way of checking that. The document.layers object only ever existed in this browser.
| 3. |
var origWidth = window.innerWidth;
var origHeight = window.innerHeight;
If we're in Netscape 4.x, we want to save the current height and width of the browser window for later use.
| | | 4. |
Here's where we actually handle the browser being resized.
| 5. |
Again, check to make sure that this only happens if they are using Netscape 4.x.
| 6. |
if (window.innerWidth != origWidth || window.innerHeight != origHeight) {
If they came in here and either the height or the width of the window has changed, the user resized the window, and we want to force the page to reload. If the browser window size hasn't changed, the onresize handler was triggered by Netscape drawing the scrollbars, and it can be ignored.
| 7. |
window.location.reload();
Reload the page if the user actually did resize the window ( Figure 9.2).
|
The onmove event
The onmove event handler is triggered when the window is moved.
The onabort event
The onabort event handler is triggered when the user cancels an image loading on the Web page. It's not used very often, and not all browsers seem to fully support it.
The onerror event
The onerror event may be triggered when a JavaScript error occurs on the page.
Tip
The onfocus event
The onfocus and onblur handlers are mirror images of each other. While they may sound like what happens when you've been working on JavaScript too late at night, in reality, the onfocus handler triggers when a page becomes the front-most active window. Scripts 9.5 and 9.6 catch the onfocus handler and force the page to always go to the back (Figure 9.3).
Script 9.5. This HTML is for the page that's in back.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Always in Back</title>
<script type="text/javascript" language="Javascript" src="script03.js">
</script>
</head>
<body bgcolor="#FFFFFF">
<h1>Unimportant content that should never be in front</h1>
</body>
</html>
|
Script 9.6. Using the onfocus handler, you can control window stacking.
window.onfocus = moveBack;
function moveBack() {
self.blur();
}
|
1. |
window.onfocus = moveBack;
Here's another example of the window and event handler object calling a function, in this case moveBack.
| 2. |
function moveBack() {
self.blur();
}
If the browser window becomes the active window, this function is triggered and forces the window to be blurred (i.e., inactive).
|
The onblur event
If you have a window that you always want to remain in front of all your other windows (a control panel, for instance, that loads in the content of the main page), Scripts 9.7 and 9.8 are what you need. Any time the user tries to put this page in the background (triggering the onblur handler), it forces its way back up to the front again.
Script 9.7. This HTML is for the page that stays in front.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Always in Front</title>
<script type="text/javascript" language="Javascript" src="script04.js">
</script>
</head>
<body bgcolor="#FFFFFF">
<h1>Important content that should always be in front</h1>
</body>
</html>
|
Script 9.8. This script uses onblur to keep a window in the front (active) position.
window.onblur = moveUp;
function moveUp() {
self.focus();
}
|
1. |
Here's another example of the window and event handler object calling a function, in this case moveUp.
| 2. |
function moveUp() {
self.focus();
}
If the browser window becomes the inactive window, this function is triggered and forces the window to become active.
|
Tips
Be very careful not to accidentally open up two windows that both contain this bit of code. Chances are, your browser will not handle the result gracefully! Instead of using this script on the control panel, you could use Script 9.6 on the main window to always make it go to the back, making the control panel always the front-most window. You may be more familiar with one of the more nefarious uses of the onblur event: advertisers who open ad windows behind your current Web page, which you don't discover until you close the window and find a stack of them piled up. Unfortunately, people blame the last Web site they opened, when in fact the ads were likely created by a page browsed much earlier.
|