WebReview.com: cross-training for web teams

SEARCH
INSIDE
 Current Issue
 Columns
 Offline
 Newsletters
 Archives

TRACKS
 Web Authors
 Designers
 Developers
 Strategists

GUIDES
 Style Sheets
 Web Browsers
 Web Tools
 Ranking System

ABOUT
 WebReview.com
 Write for Us
 Advertising
 Staff
 Contact

NETWORK
 WebTechniques.com
 WEB2000 Show Site
 WebCoder.com

Jan. 28, 2000 Issue > Web Authors

Exclusive Hover Buttons With DOM 2 Events

By Mitch Gould

Rank: 2

DOM 2 Browsers

If you want to play with the code in this article, make sure you have the right browser for the job.

• If you have IE 5.01 for Windows, that'll work ...

• Or, you can download a beta copy of IE 5.5 for Windows ...

• Or, you can go get the M12 build of Mozilla for Mac, Windows, or Linux and check out the FetchBuilds links.

Microsoft Internet Explorer 5.5 has now gone into beta, and mozilla.org has released a solid milestone build (M12 of the Netscape Navigator version 5 prototype). This means that many important features of the W3C's Document Object Model Level 2 specification (DOM 2) are now available on both of the dominant browsers. To use the code presented here, you must have one of these version-5 browsers.

DOM 2 provides many new exciting features for scripters. You say you'd like a standard interface for user-interface events? How about dynamic control over style? You'll find examples of both of these advanced features in this article. Unfortunately, due to differences in compliance with this new W3C standard, we'll need to address some remaining browser incompatibilities.

For instance, unlike Navigator 5, Microsoft's Event.srcElement property doesn't track the W3C standard for Event.target, but instead supports only legacy Microsoft-DHTML code. This inconsistency provides a concrete example of that nebulous "semantics" jargon that is so fashionable today. One could say that in this instance Microsoft did not conform to the standard "semantics" forged by the W3C DOM.

Alas, we'll need to fall back on a browser-sniffing fork in our scripts, just as we did before the W3C DOM. The good news is that both browsers manage many other event-handling matters in the same way.

Exclusive hover buttons

So, what's on the menu today? Well, because so many scripters seem to share an attraction to hover effects for buttons, let's script that project. Not only do hover effects provide a visual showcase for DOM 2 events, they also demonstrate DOM 2's dynamic control over CSS style by changing numerous aspects of an element's appearance at once.

A basis for HTML toolbars

These special effects signify more than flashy window-dressing. Speaking of menus, as a matter of fact, mutually exclusive buttons are functionally equivalent to a drop-down menu (leaving aside any cascading menu features). In contrast to HTML 3.2's mutually exclusive radio buttons, however, HTML 4.01 buttons provide versatile support for many kinds of HTML content—complex text styling, images, and even tables.

Moreover, this example demonstrates how DOM 1's understanding of the container relationships between nested elements can be easily exploited for coherent style changes. Specifically, we'll see how to coordinate user-interface responses between HTML 4.01 button and label objects. This example suggests how "virtual UI control objects" can be created by aggregating existing HTML objects.

Try the example

Before we begin, try the "Exclusive Hover Buttons with DOM 2 Events" example. It consists of four buttons enclosed within labels. The buttons respond to mouseovers and clicks with two levels of highlighting. A button click writes the button ID in the status bar; but in Navigator 5.x, this event could trigger anything from creating a new IFRAME to sorting e-mail messages, by calling upon Netscape's internal toolkit, XPCOM. In Internet Explorer 5.5, these buttons can be hooked to a new feature known as HTML behaviors, which, like Navigator, can provide some potentially risky services, such as copying and pasting with the system clipboard via the Windows COM interface.

The HTML source, shown in Figure 1, is simple, consisting of the HTML 4.01 code for buttons and labels, their styles, and a concise script.


<html>
<head>
<title>Exclusive Hover Buttons</title>
<script type="text/javascript">
 // Version-5 Browsers only.
 // Splice each broken line before using!

 // Browser patch for missing W3C DOM
 // Event.target call in IE5; returns the
 // object that is the source of the event.
 function getTarget(e) {
  // IE5
  if (e.srcElement) {
   return e.srcElement
  }
  // NC5
  if (e.target) {
   return e.target
  }
 }
 
 // The bulk of this module is taken up with
 // handling the mutually-exclusive visual effects
 // of clicking a button. The action handler
 // is only window.status write. Modify that for
 // your actual needs. 
 function clickWhich(e) {
  // Lo-lite all buttons.
  for (var i = 0; i < 
  document.getElementsByName('set1').length;
  i++) {
   // Button
   document.getElementsByName('set1').[break]
   [con't]item(i).className = "normal"
   // Label
   document.getElementsByName('set1').[break]
   [con't]item(i).parentNode.className = "normal" 
  }
  // Select the clicked button.
  // Button
  getTarget(e).className = "active" 
  // Label
  getTarget(e).parentNode.className = "active"
  // Here's where the real action goes.
  window.status = "You clicked: " + getTarget(e).id
 }

 // This module handles the mutually-exclusive
 // visual effects of a mouseover.
 function overWhich(e) {
  // Lo-lite all buttons, unless one is active.
  for (var i = 0; i <
  document.getElementsByName('set1').length; i++) {
   // If the button is not active...
   if (
   document.getElementsByName('set1').[break]
   [con't]item(i).className != "active" ) {
    // Button
    document.getElementsByName('set1').[break]
    [con't]item(i).className = "normal"
    // Label
    document.getElementsByName('set1').[break]
    [con't]item(i).parentNode.className =
"normal"
   }
   // Hi-lite the hover button.
   if ( getTarget(e).className != "active" ) {
    // Button
    getTarget(e).className = "hover"
    // Label
    getTarget(e).parentNode.className = "hover"

   }
  }
 }
</script>
<style>
 label.hover {
  background-color: blue;
  width: 100px;
 }
 
 button.hover {
  background-color: aqua;
  color: blue;
 }
 
 label.active {
  background-color: aqua;
  width: 100px;
 }
 
 button.active {
  background-color: blue;
  color: white;
 }
 
 label.normal {
  background-color: black;
  width: 100px;
 }
 
 button.normal {
  background-color: gray;
  color: aqua;
 }
</style>
</head><body
 onmouseover="javascript: overWhich(event);"
 onclick="javascript: clickWhich(event);">
<img src="w3cdom.gif">
This page is for Navigator version 5
 or Explorer version 5<em>only</em>.
<form name="form0">
<label id="l0" name="lab1"
class="normal">
<button name="set1" class="normal"
id="b0">0</button>
Zeroth</label>
<br>
<label id="l1" name="lab1"
class="normal">
<button name="set1" class="normal"
id="b1">1</button>
Oneth</label>
<br>
<label id="l2" name="lab1"
class="normal">
<button name="set1" class="normal"
id="b2">2</button>
Secondth</label>
<br>
<label id="l3" name="lab1"
class="normal">
<button name="set1" class="normal"
id="b3">3</button>
Thirdth</label>
<br>
</form>
</body>
</html>

Figure 1. Sample code.

This HTML is unremarkable in all aspects but one: the absence of any event handlers in the buttons themselves. Instead, the BODY contains the only explicit event handlers:

<body onmouseover="javascript: overWhich(event);" 
onclick="javascript: clickWhich(event);">

This makes the code far briefer and cleaner but introduces a mystery: how do the buttons know they've been clicked? Well, we're getting there.

Oh, wait a minute: the buttons and labels are grouped using the same attribute, name, that has traditionally been used to group several HTML inputs into a set of radio buttons.

<label id="l0" name="lab1" class="normal">
<button name="set1" class="normal" 
id="b0">0</button>
Zeroth</label>

Fortunately, both browsers support the name attribute on HTML 4.01 buttons and labels.

Dynamic styles

The special effects are handled with CSS classes for the normal, hover, and active states of both buttons and labels. Note the element.className syntax in the CSS selectors.

As an aside, I will not bother to defend the simple color choices. They work well for the example because the differences in selection state are so obvious. But in user-interface design, it is best to find that tricky balance between naturalistic (subtle) colors and those that show sufficient contrast. For that kind of control, you'll need to use CSS's rgb(red, green, blue) functionality.

Elements can be assigned a new look dynamically with the new DOM 2 className property, as in the following pseudo-code:

 somelement.className = someclass

Because of excellent style support in DOM 2, making sweeping changes to appearance is actually easier than getting a handle to the desired element in the first place, as we'll see below.

DOM API sniffing

As mentioned previously, your code needs to sniff out the name of the Event.target property, so we've encapsulated this feature into a reusable module, getTarget(). It takes the form of a time-honored DHTML fork:

 // Browser patch for missing W3C DOM Event.target call 
 // in IE5; returns the object that is the source of the event.
 function getTarget(e) {
  // IE5
  if (e.srcElement) {
   return e.srcElement
  }
  // NC5
  if (e.target) {
   return e.target
  }
 }

I haven't fussed over how to be nice to people who persist in loading this example with an unsupported browser. If this dilemma causes you to stay up nights, you can either direct the user to an alternate page composed of HTML 3.2 radio buttons, or, if you're like some of my more wicked friends, you can redirect them to the Home for Obsolete Browsers.

Global event capturing

DOM 2 event-handling means you don't necessarily have to load up each tag with event handlers. If your document needs to coordinate activity between several buttons, it can kidnap the event and tell its child elements how it thinks they should respond. To control the activated state of mutually exclusive buttons, this feature is quite desirable. So the body grabs any hover that occurs anywhere and queries DOM 2 to determine the target, using our custom utility, getTarget(). It then clears hover styles on all elements except the current hover target.

The active style on button clicks is handled much the same way. Note that hover is a transient effect, but you must design your visual reminder of an active state as "sticky" because applications go into a steady command state. One nice thing about DOM 2 is that it allows us to repurpose className as a check for a button's active state.

if ( document.getElementsByName('set1').item(i).className
  != "active" ) 
{
  // If the button is not active...
}

DOM 1 element addressing

The code just mentioned uses a DOM call, document.getElementsByName(), that returns an array of matches and is ideal for mutually-exclusive controls such as this one. By comparison, the document.getElementById() function is a workhorse approach that you will use whenever possible to address elements. But DOM also provides a way for the button to communicate with its parentNode—the label that contains it:

document.getElementsByName('set1').item(i).parentNode.className
    = "normal"

This example shows how to synchronize the state of the label with that of the button. In a broader sense, it shows how to use the DOM to aggregate standard HTML objects into custom objects—"virtual UI controls."

Conclusion

The example presented here can quickly be developed from an educational toy into the beginnings of a powerful front-end for interactive applications. By studying this code, you can kickstart your career into the next generation of Web development—one in which the W3C DOM will play a central role.






Current Issue . Columns . Newsletters . Archives . Web Authors . Designers . Developers . Strategists
Style Sheets . Web Browsers . Web Tools . About Us . Write for Us . Advertising . Staff . Contact
WebReview.com © 1995-2001 CMP Media Inc. | Privacy Policy