Dave Massy
Microsoft Corporation
January 2000
Summary: Describes how to build your own DHTML element behavior with script and HTML for use in a DHTML page. (6 printed pages)
Introduction
Starting Our Behavior
Behavior Content
Including Content
Behavior Defaults
Furthering the Behavior
Microsoft® Internet Explorer 5.5 Platform Preview (http://msdn.microsoft.com/downloads/webtechnology/ie/iepreview.asp) is packed with exciting new functionality for the dynamic HTML (DHTML) developer. To see a full overview of the new DHTML features, take a look at the MSDN Online Voices article at http://msdn.microsoft.com/voices/ie55.asp. In this article we're going to walk through building our own DHTML element behavior out of script and HTML for use in a DHTML page. Before we get started, though, let's cover a little background for element behaviors, the full reference documentation for which is available in the Web Workshop at http://msdn.microsoft.com/workshop/author/behaviors/overview/identityb_ovw.asp.
An element behavior distinguishes itself from the behaviors supported in Internet Explorer 5.0 because it is really the implementation for the custom element. Custom elements and what we now refer to as attached behaviors were introduced in Internet Explorer 5.0 and allow an XML syntax to be used to add your own custom elements, such as <VEG:TURNIP>, to an HTML document. Attached behaviors could then be added to these and any elements in the HTML document using the CSS behavior property or the addbehavior() method. The disadvantage here is that the attached behavior can become detached if the behavior property is redefined and the behavior may not be immediately attached. To solve these issues in Internet Explorer 5.5 we introduce support for what we refer to as element behaviors, which are permanently and irrevocably bound to the custom element. Just to be clear here, attached behaviors remain useful for functionality that you wish to add to any arbitrary element in an HTML document, but if you are defining a custom element, element behaviors is definitely the recommended approach.
Let's start our project to build our own robust custom element.
For our DHTML element behavior I've chosen to develop an include tag that will include the content of a text file as part of a DHTML page. Element behaviors can get a lot more capable than this, but for the purposes of this article I've chosen something that allows us to concentrate on the core functionality that element behaviors provide.
Let's start off with a very simple element behavior implemented as an HTML component (HTC) file. Take a look at include1.htc:
<PUBLIC:COMPONENT tagname="include">
<PUBLIC:ATTACH event="oncontentready" onevent="init();" />
</PUBLIC:COMPONENT>
<SCRIPT>
function init()
{
window.status="Include has been initialized";
}
</SCRIPT>
Here the tag name include is specified on the public:component element of the behavior. Take a look at includedemo1.htm, which uses this element behavior:
<HTML xmlns:MYNS >
<HEAD>
<?IMPORT namespace="MYNS" implementation="include1.htc">
</HEAD>
<BODY>
This HTML file uses the include element to include a block of text from another file in an HTML page. Here is the included content of the include.htc file:
<BR>
<MYNS:INCLUDE />
<BR>
This text comes after the included file:
</BODY>
</HTML>
We see here the namespace for the custom element defined on the HTML tag and the IMPORT processing instruction that tells us where the implementation of our element behavior can be found. Currently, this element behavior does nothing, so I placed some script in the behavior that will be run on initialization to write some text to the status bar. This can be a useful technique for debugging; in this case it confirms that our behavior has been instantiated.
Before we get carried away and start adding useful functionality to our behavior, let's stop for a moment and make sure we understand what is taking place here. When the browser parses the HTML file that uses our custom element it encounters the IMPORT processing instruction. The thing about processing instructions is that they do pretty much what you'd think—they process instructions. This is different from HTML element content, which gets built as part of the document. A processing instruction will have the effect of stopping all parsing until the instruction has been executed. In our case, the import has the effect of saying that for the namespace of "MYNS," which we defined earlier on the HTML element, there is an implementation for a tag name. The tag name is defined by the implementation—that is, the HTML component .htc file; when the import is encountered the HTML parser will ensure that the implementation is available (technically, we say it instantiates the factory) when it subsequently encounters the appropriate tag in the HTML document. This results in the fact that when the HTML parser does get to the <MYNS:INCLUDE> element, the element behavior can be created at the same instance the element is built in the document.
Another thing to note here is that our element <MYNS:INCLUDE /> is what we refer to as a no-scope element. That means it has a closing / after the tag name and no equivalent </MYNS:INCLUDE> will be looked for by the HTML parser. It would be equally valid for me to use the following tag construct in this case so that a non-element aware browser can render the alternative content:
<MYNS:INCLUDE> this is where the included content would be displayed if you were using Internet Explorer 5.5 </MYNS:INCLUDE>
Now that we have a basic element behavior, the next step is to display some content. For this we'll use the new ViewLink functionality in Internet Explorer 5.5, which allows us to have HTML content shown in a separate document fragment. Let's take a look at include2.htc. (You'll need includedemo2.htm to see this working, but the only difference is the .htc file it uses as the implementation for the element behavior.)
<HTML>
<PUBLIC:COMPONENT tagname="include">
<PUBLIC:DEFAULTS viewLinkContent="true" />
<PUBLIC:ATTACH event="oncontentready" onevent="init();" />
</PUBLIC:COMPONENT>
<SCRIPT>
function init()
{
window.status="Include has been initialised";
}
</SCRIPT>
<BODY>
Here's some ViewLinked content for our element behavior:
</BODY>
</HTML>
Here we've added a BODY tag to the .htc file with some text content, and also added a new PUBLIC:DEFAULTS element, which specifies that the content of the .htc file should be used as the ViewLinked content for this behavior. When we run the includedemo2.htm file we now see that content appear as the content for the element. This works because an .htc file is, in effect, an HTML file and the content gets parsed by the HTML parser. The ViewLinking technology now allows us to display that content without having to insert it into the main document that is using the element behavior.
The next stage in this include behavior is to get the text file and include it in the HTC's ViewLinked content. To do this we'll make use of a behavior that is available in Internet Explorer 5.0 to download data asynchronously. Let's take a look at include3.htc. (Once again, you'll need includedemo3.htm, which uses include3.htc as it's behavior implementation, to see the demonstration work.)
<PUBLIC:COMPONENT tagname="include">
<PUBLIC:PROPERTY name="src" />
<PUBLIC:DEFAULTS viewLinkContent="true" />
<PUBLIC:ATTACH event="oncontentready" onevent="init();" />
</PUBLIC:COMPONENT>
<SCRIPT>
function init()
{
if (src)
{
dwn.startDownload(src, onDone);
}
}
function onDone(s)
{
dwn.innerText=s;
}
</SCRIPT>
<BODY id=dwn style = "behavior:url(#default#download)">
</BODY>
The first thing to notice is that we've added a property declaration for our behavior with the name of "src," which we'll use as the source of the file we wish to download. Note that for security reasons the download behavior will only allow us to download files from the same domain (in effect, that means Web site) as the HTML using it. We've also added the default download behavior to the body of the HTC, and the script necessary to download the file on initialization and place the content into the body when it is received.
So, here we have a simple element that we can use to download content and display that as text in the document. Now let's enhance it a little by making use of the default styles facility on element behaviors. This allows us to specify the default style information for the element behavior while still allowing it to be overridden by the HTML page that uses the custom element. In the next iteration of our include4.htc behavior we have just changed the PUBLIC:DEFAULTS element as follows:
<PUBLIC:DEFAULTS viewLinkContent="true" style="background-color:beige; color:Blue; width:100%" />
This change has the effect of giving our included content a blue color on a beige background. If you experiment with the HTML file, however, you can see that these settings can be overridden in the document using the element behavior. Try changing the include element of the includedemo4.htm file to something like:
<MYNS:INCLUDE src="include4.htc" style="color:beige;background-color:blue"/>
which results in the default styles being overridden at the command of the file using the behavior.
I also decided that I'd like the default width of this element to be as wide as the document in which it is being used, so I added to the default style to have a width of 100 percent.
Play with this behavior yourself to get some idea of how it works. Ideas for enhancements include allowing HTML content to be used rather than just text, including a title of where the source of the include is from, and so on.