This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


Inside Knowledge
Download the code (2KB)
Aaron Skonnard

Internet Explorer 5.0 Behaviors
I
f you're like most Internet developers, you can't wait to start taking advantage of behaviors in your Web site. A behavior, for those of you who don't know, is a new technology for separating script from HTML—a component that defines some type of "behavior" on HTML page elements. For example, a sample behavior called hilite might change an element's text color to red when the mouse runs over the element and set the text color back to normal when the mouse leaves the element (see Figure 1). Instead of writing script routines in each HTML file that needs this type of highlighting, you can simply wrap the functionality into a behavior and reuse it everywhere.
Figure 1: The Hilite Behavior
Figure 1: The Hilite Behavior

              The Microsoft® Internet Explorer 5.0 beta 1 release finally made it possible to start using behaviors. If you played around with behaviors in this preliminary release, you know that behaviors were originally implemented as XML scriptlets. But much can change from one beta to the next. In beta 2, the preferred way to implement behaviors evolved into HTML Components (HTCs). (The final release of Internet Explorer 5.0 is scheduled for release shortly after you read this.) Implementing behaviors using HTCs is more simple and straightforward than you might expect.

HTC Basics

       As its name suggests, an HTC is a component meant for use in an HTML page. One of the key benefits of components is that they're language-neutral. Today HTCs can be implemented using any scripting language that supports the Microsoft ActiveX® scripting interfaces (such as VBScript or JScript®) or any other language that supports COM, including C++. Although HTCs are obviously much easier to implement using a scripting language, there is nothing stopping you from whipping out your C++ compiler to produce the same result. For those of you interested in this option, I've provided a section toward the end of this column that discusses the use of binary HTCs.

       HTCs can do everything a good behavior should do. They can expose properties, methods, and custom events, access the containing page's document object model, and receive notifications. Therefore, an HTC behavior can do everything a Windows Script Component (WSC), formerly called a scriptlet, can do.

       You use an HTC behavior just like you would a WCS behavior. If you have an HTC behavior called hilite.htc, you can tie it to an HTML element using the proposed Cascading Style Sheet (CSS) behavior attribute. For example, the following HTML ties the hilite.htc behavior to the <P> element:



 <P STYLE="behavior:url(hilite.htc)">Testing</P>
       Instead of doing it this way, you can assign the behavior to all <P> elements or all <P> elements of a given class. In short, you can apply behaviors just like any other CSS style.

HTC Syntax

       An HTC implemented in script must use the .htc file extension. (WSC behaviors use the .sct file extension.) To start writing your first HTC behavior, simply open up your favorite text editor and create a new file with a .htc extension. Now you're ready to start writing behavior code consisting of HTC tags and script.

       Every HTC file must contain a <PUBLIC:HTC> tag to identify it as an HTC, and everything that is part of the HTC must be included in this tag (before the end tag </PUBLIC:HTC>). This tag supports the URN (uniform resource name) property. The containing page uses the URN to identify the behavior attached to an element. If you have multiple behaviors attached to a single element, you may need to distinguish between them in your HTML. Here is what your HTC file should look like with the <PUBLIC:HTC> tag included:



 <PUBLIC:HTC URN="www.skonnard.com:hilitev1">
 </PUBLIC:HTC>
       If your behavior is going to do anything substantial, you're also going to need a script block within your HTC file. The script block should (like everything else) live within the <PUBLIC:HTC> tag. All your script code should live within the script block. Here is what your HTC file looks like with the script block included:


 <PUBLIC:HTC URN="www.skonnard.com:hilitev1">
     <SCRIPT LANGUAGE="JScript"> 
     </SCRIPT>
 </PUBLIC:HTC>
       From here, what you add to your HTC depends on what kind of functionality you're trying to achieve. You'll probably want to receive notifications from the containing HTML page. Since an HTC is a component, it can also support custom properties and methods. Furthermore, you may also want to generate your own custom events. Let's look at how to accomplish each of these tasks.

Receiving Notifications

       To receive notifications from the containing HTML page, your HTC must attach to the notification type of interest. You can attach to a notification using the <PUBLIC: ATTACH> tag. The following is the syntax for this tag:



 <PUBLIC:ATTACH
     EVENT = sEvent
     FOR = "document" | "element" | "window"
     HANDLER = sEventHandler
     URN = sURN
 />
       Notice that you must specify the event you're interested in along with the object that fired it. Then you must specify the handler in your HTC file. The handler is simply the name of the function in your HTC script that will be called in response to this event.

       For example, suppose I want my behavior to modify the text color and letter spacing of the element in onmouseover, and to put back the original settings in onmouseout. To do so, I need to add the following two lines to my HTC:


 <PUBLIC:ATTACH EVENT="onmouseover" HANDLER="hilite" />
 <PUBLIC:ATTACH EVENT="onmouseout"  HANDLER="normal" />
       Once I've added the attach tags, I need to add the script for each of the handlers (hilite and normal). After adding these tags along with the associated script routines, my complete HTC now looks like this:


 <PUBLIC:HTC URN="www.skonnard.com:hilitev1">
     <PUBLIC:ATTACH EVENT="onmouseover" HANDLER="hilite" />
     <PUBLIC:ATTACH EVENT="onmouseout"  HANDLER="normal" />
     <SCRIPT LANGUAGE="JScript">
     var normalColor, normalSpacing;
  
     function hilite()
     {
          // save original values
          normalColor  = style.color;  
          normalSpacing= style.letterSpacing;
          style.color  = "red";
          style.letterSpacing = 2;
     }
 
     function normal()
     {
          // reset to original values
          style.color  = normalColor;
          style.letterSpacing = normalSpacing;
     }
     </SCRIPT>
 </HTC>

Properties and Methods

       You can add properties and methods to your HTC through the <PUBLIC:PROPERTY> and <PUBLIC:METHOD> tags. Figure 2 contains the syntax for these and other tags. These properties and methods can be accessed from within your HTC script and from the containing HTML page
.
       For example, suppose in my HTC document (shown in Figure 1) I wanted to specify the highlight color in the HTML page instead of hardcoding red into the behavior. To accomplish this, I'll add a property to the HTC called hiliteColor:



 <PUBLIC:PROPERTY NAME="hiliteColor" />
       Now instead of setting the color to red in onmouseover, I'll set the color to hiliteColor. But what if the client page doesn't specify a color? I'll need to handle this case by attaching to the window's onload event. Here is the tag and the script code to check the state of the property and set the default to red:


 <PUBLIC:ATTACH EVENT="onload" FOR="window" HANDLER="initialize" />
 
 function initialize()
 { 
     // initialize the property 
     if (hiliteColor == null) 
          hiliteColor = "red";
 }
       If I want to, I can specify a different color to be used by the behavior from the HTML:


 <P STYLE="behavior:url(hilite.htc)" HILITECOLOR="green">Testing</P>
       In this example, the text color used for highlighting will be green instead of red. If I remove the HILITECOLOR property, the text color used for highlighting would remain red.

       Methods are just as easy to add as properties. Let's add a method capable of changing the highlight color used by the behavior. To accomplish this, you need to add the HTC tag defining the method name along with the corresponding script handler:


 <PUBLIC:METHOD NAME="ModifyColor" />
 
 function ModifyColor(newColor)
 {
     // modify the hiliteColor
     hiliteColor = newColor;
 }
       You can call this method from the script code in your HTC document or from the containing HTML page. For example, you could call ModifyColor each time the user clicks on the element:


 <P STYLE="behavior:url(hilite.htc)" onclick="ModifyColor('blue')"> Testing</P>
       Although this is a very trivial example, you can take advantage of more sophisticated methods to add powerful capabilities to your behaviors.

Custom Events

       Adding custom events to your HTC is as simple as adding the <PUBLIC:EVENT> tag to your HTC document and then firing the event from within your HTC script. The tag specifies the name and ID of the event to be fired by your behavior. The name specifies the name of the method to be called when the event fires. (This is the name of the event handler in your HTML page.) You'll use the ID in your HTC script to fire the event.
For example, let's add a custom event that fires any time the ModifyColor method is called. This requires adding the following event tag:



 <PUBLIC:EVENT NAME="onColorChanged" ID="eColorChanged" />
       You must also modify the implementation of ModifyColor to take care of firing the event:


 function ModifyColor(newColor)
 {
     // modify the hiliteColor
     hiliteColor = newColor;
     oEvent = createEventObject();
     eColorChanged.fire(oEvent);
 }
       To handle this event in the containing HTML page, you simply need to add the onColorChanged handler to the element in question:


 <P STYLE="behavior:url(hilite.htc)" onColorChanged="alert('color changed')">
 Testing</P>
       Well, that's it. I've walked you through the major syntactic elements needed to create a fully functional HTML component. In case you're still trying to piece things together, I've provided the complete HTC file in Figure 3 and the complete HTML for a sample client page in Figure 4.

Syntax Differences

       If you're most familiar with HTML, then HTCs are the best choice for developing behaviors. WSC is still great for XML fans and hardcore developers. If you've done much work with behaviors using WSCs, you've probably noticed already that they are a bit easier to develop using HTCs. What happened to the <IMPLEMENTS> tag and the attachNotification method? Well to make a long story short, you don't need them anymore. To help you understand how to convert a WSC behavior to an HTC, take a look at Figure 5.

       Instead of using an ID to identify the behavior, HTCs use a URN. Another not-so-obvious difference has to do with firing events. The WSC syntax requires you to call fireEvent, passing in the name of the event along with the event object. The HTC syntax simply exposes a fire method that can be called directly on your event object. With HTCs, you also don't have to call attachNotification anymore. Simply supply the appropriate <PUBLIC:ATTACH> tag and you're finished.

       The rest of the changes have to do with the XML tag syntax, all of which are a nice refinement to the WSC syntax. All notifications, properties, methods, and custom events can be specified using a single XML tag, and the <IMPLEMENTS> tag has been removed completely. HTC behaviors are easier to digest and learn than their WSC counterparts.

Binary HTCs

       No one will deny that HTCs written in script are by far the easiest way to implement a behavior. However, what if you want to completely hide your behavior functionality from the user to protect your intellectual property? Or what if your behavior is very performance-sensitive and can't be bogged down by interpreted script code? The answer lies in binary (compiled) HTCs.

       While there are some very compelling arguments for using binary HTCs, most Internet developers won't want to sacrifice the productivity offered by scripting languages. Writing a binary HTC requires strong C++ skills along with experience using the Active Template Library (ATL). To accomplish this feat you must implement both the IElementBehavior and IElementBehaviorFactory interfaces, as shown in Figure 6.

       To use a binary HTC in your HTML code, you must do a little more work than usual. First, you must embed the component in your page using the <OBJECT> tag. Thereafter, you can refer to your behavior as the name of the ID assigned to the object. For example, consider the following <OBJECT> tag:



 <OBJECT ID=binaryBehavior CLSID= ... > </OBJECT> 
       You could then refer to this behavior in HTML like this:


 <P STYLE="behavior:url(#binaryBehavior)">Testing</P>
       It will be interesting to see how often binary behaviors are used in the future. Although they can increase performance on the client side and hide code from the user, I'm not sure developers will be willing to ride the learning curve when there is such a friendly alternative. Furthermore, a binary behavior might take significantly longer to download than a script HTC (depending on the compiled image size, of course).

Samples Galore!

       As you start developing your own HTCs, be sure to point your Web browser to the Site Builder Network at http://msdn.microsoft.com/workshop/author/behaviors/library/behaviorslibrary.asp and check out the growing behavior library. This page contains a set of HTC behaviors developed for Internet Explorer 5.0. You can view a demo of the HTC, download the HTC code, and see how the HTC is being used in the corresponding HTML page.
Figure 7: The Calendar Behavior
Figure 7: The Calendar Behavior

       The calendar behavior (see Figure 7) inserts a calendar control into a Web page. The calendar consists of three main sections. The title area displays the month, year, and month and year listboxes. Days of the week are ordered horizontally below the title area. The individual days of the month, including overlapping days from the previous month and the following month, are contained in a grid that's displayed below the days of the week.
Figure 8: Coolbar
Figure 8: Coolbar
       The coolbar behavior (see Figure 8) inserts a toolbar into a Web page populated with coolbuttons. Toolbars are a familiar interface for users. The coolbar behavior applies effects (3D borders, colored text, and colored images), and supports ToolTips to bring each button to life.

       The coolbutton behavior can only be used within the coolbar behavior. It inserts a button into a Web page as a part of the coolbar behavior. Coolbuttons provide a visual cue with an icon and/or a text cue in the form of a label indicating which action will be performed. Both the icon and the text can be assigned hover effects for the onmouseout event. The coolbar behavior defaults to a familiar Win32® style, but can be edited with a full range of Dynamic HTML and CSS properties. These properties can be set at runtime so an application can allow the user to turn the button text tables on and off.

       The imageRollover behavior allows Web authors to specify a replacement image to be displayed when the mouse cursor hovers over an <IMG> object, or when the <IMG> object is clicked. Use the HOVERSRC and PRESSEDSRC attributes to specify the image sources for the events.
Figure 9: Mask Edit
Figure 9: Mask Edit

       The mask edit behavior (see Figure 9) is applied to <INPUT> elements that allow data entry to provide a combination of restricted input as well as formatted output. When information is entered, visual cues are provided about the type of acceptable information, and feedback is provided about incorrect entries. This behavior can be applied to many common types of form fields such as date, time, and phone number fields. These masks can be applied through one of several preset formats.

       The menu behavior allows authors to create expanding and collapsing menus on Web pages. Each menu node can enclose other nodes or standard HTML elements, such as an anchor.

       The moveable behavior allows a Web author to specify that all contained HTML elements are moveable by the user.
Figure 10: The Rowover Behavior
Figure 10: The Rowover Behavior

       The rowover behavior (see Figure 10) enables alternate row shading and row highlighting for <TABLE> objects.

       The slider behavior enables Web authors to insert a slider control into a Web page and allows users to select a value from a gradient. A slider can be placed on the page with a vertical or horizontal orientation. Values are selected by dragging the slider with the mouse. Tick marks are provided according to an author-specified range.

       The soundRollover behavior allows Web authors to specify an audio source to be played when the mouse cursor hovers over an element, or when the element is clicked. You can use the HOVERSOUND and PRESSEDSOUND attributes to specify the image sources for the events.
Finally, the tooltip behavior adds a rich HTML tooltip control to the document.

Conclusion

       Behaviors are definitely going to be a driving force during the next few years of Internet development. They make it possible for developers to write components that can be shared among elements, pages, projects, or even sites. You'll probably see a new market born overnight when Internet Explorer 5.0 ships and everyone starts looking for the most effective and easy-to-use behavior. Behaviors also make it possible to completely remove the script that seems to constantly clutter HTML pages.

       What I've shown you this month is the new technology for implementing behaviors. While you could previously implement behaviors in Internet Explorer 5.0 beta 1 using WSCs, you can now simplify your components using the much-improved HTC syntax.

       As you get ramped up for the behavior transition, make sure that you understand the HTML Component syntax, as well as the differences between the old and the new syntaxes. Finally, if your company has some pretty tight intellectual property standards or performance issues to consider, you may need to look into developing binary behaviors using C++ and ATL.

From the April 1999 issue of Microsoft Internet Developer.