Viva Components!

As of December 2011, this topic has been archived. As a result, it is no longer actively maintained. For more information, see Archived Content. For information, recommendations, and guidance regarding the current version of Internet Explorer, see Internet Explorer Developer Center.

Michael Wallent
Microsoft Corporation

January 3, 2000

Contents

ViewLink
Element Behaviors
Summary

When we were developing Internet Explorer 4.0, one of the development team's primary goals was to create a client platform that enabled rich, powerful, easy-to-use applications. The cool thing was that developers started to do just that. However, a big bit was missing—a component model. Dynamic HTML (DHTML) pages for Internet Explorer 4.0 tended to be long, monolithic expressions of HTML and script—not really the perfect model for ease of reuse and development. In Internet Explorer 5, we began to address this problem with DHTML behaviors. These behaviors could be written in script or in a compiled language, and you could use them to add your own properties, methods, and events to existing HTML or new XML tags. We employed this technology internally as well. The Vector Markup Language implementation was done as a behavior, and was a separate code base from the core browser technology.

Internet Explorer 5 was certainly a positive step toward a powerful component model platform, but it wasn't quite done yet. There were two holes that we needed to fill to make the components even more powerful.

ViewLink

One important part of any component model is its encapsulation model. DHTML behaviors in Internet Explorer 5 had good encapsulation for their private properties and methods—but there was an encapsulation leak in one key area. Quite often authors composited or aggregated additional HTML elements or properties to create new effects. The common example for this was the calendar behavior. When a page author put a simple <my:calendar/> tag on the page, the behavior might insert a complex HTML table into that document to express the calendar. Here was the leak. Those elements were inserted into the primary document. Cascading style sheet (CSS) rules from the primary document would apply to those inserted elements as well. The IDs of elements that were inserted via a behavior would show up in the namespace of the document as well. This added much complexity to creating well-behaved behaviors.

We needed a solution that would allow behaviors to express themselves via compositing, but not allow the document in which they were hosted to affect their behavior. The solution we've created for Internet Explorer 5.5 is a technology we call ViewLink. Simply put, ViewLink allows the contents of a second document to be displayed in the place of an element displayed in the primary document.

Here's a ViewLink sample (you must be running Internet Explorer 5.5 or later to view this demo).

Here's the source for the HTML page:

<HTML xmlns:MS>

<?IMPORT namespace = MS implementation = "input.htc" >

<BODY STYLE="font-family: verdana">
<H2>Simple View Linking</H2>

<MS:INPUT/>

</BODY>
</HTML>

Here's the source for the HTML Components (HTC) file:

<PUBLIC:COMPONENT tagName=INPUT >
<public:defaults viewLinkContent />
<public:property name="value" put="setValue" get="getValue"/>
<public:attach event=oncontentready onevent="init();" />
</public:component>

<SCRIPT>
function init() {
}

function setValue(v) {
  TheInput.value = v;
}

function getValue() {
  return text;
}

</SCRIPT>

<BODY STYLE="width:100%; height:100%">

<INPUT TYPE=text ID=TheInput>

</BODY>

To get the same effect for Internet Explorer 5, the HTC would have injected the HTML for the <input> into the original document by using innerHTML, createElement(), or some other method. However, this would have caused that input to be visible to the object model of that first document.

Now, with Internet Explorer 5.5, I simply put content in the body of my HTC, and declare that the rendering of the contents of my element should be replaced with the content of the body of my HTC. This is done by including the following line in the header of the HTC.

<public:defaults viewLinkContent />

You can also declare the ViewLink procedurally, as in the following code:

defaults.viewLink = document;

where "document" is the reference to the document in the HTC. You could also create a document fragment, and ViewLink to that as well.

The content in the ViewLinked document doesn't leak out, either. Events started in ViewLinked content are not forwarded out of that document. For an event to leave a ViewLinked document, the behavior must explicitly handle and refire the event. The next example will do just that.

ViewLink lets you build completely encapsulated components. With this complete encapsulation, these components will be less fragile, and more likely to work on a wide variety of Web pages.

For more information on ViewLink, check out Viewlink and What's New in Internet Explorer 6.

Element Behaviors

DHTML behaviors in Internet Explorer 5 could contribute new properties, methods, and events—but doing so really didn't change the identity of a tag. An input with a mask behavior was still an input. An XML tag was just a tag with some stuff added. There were two distinct things: the element and the behavior. This linkage wasn't very strong; behaviors could be added and removed just like any other CSS property. Because DHTML behaviors were applied with CSS, and because they were non-persistent, they were also asynchronous. Even if you had specified that all <X:EXAMPLE> tags got the example.htc behavior, your X:EXAMPLE wouldn't necessarily have the behavior applied to it at all times. This was most apparent when you tried to use the createElement() method to create elements that had DHTML behaviors specified in a style sheet. For example, in the following code:

<html xmlns:x>
<HEAD>
  <STYLE>
     x/:example {behavior: url(example.htc)}
  </STYLE>
</HEAD>

<BODY>

<SCRIPT LANGUAGE=JScript>
var newTag;

newTag = document.createElement("x:example");

// non-deterministic if the next line will work
newTag.someMethod();

</SCRIPT>

</BODY>
</HTML>

it isn't clear whether the someMethod() call that the example.htc contributes to all x:example tags will work immediately after the element has been created. To be sure, you would have to check the readyState property of the element to see whether the behavior had been fully attached.

This also was a problem on a page like the following:

<html xmlns:x>
<HEAD>
  <STYLE>
     x/:example {behavior: url(example.htc)}
  </STYLE>
</HEAD>

<BODY>

<x:example ID=MyExample>

<SCRIPT LANGUAGE=JScript>

MyExample.someMethod();
</SCRIPT>

</BODY>
</HTML>

In this case, I have some immediate script going after the someMethod() method. The problem is that sometimes this will work, and sometimes it won't. If the HTC is cached locally, it probably will work. On a slow line, it won't. Once again, you would have to wait until the document.onload event had fired, or until the readyState property of the element was complete.

The asynchronous nature of DHTML behaviors caused confusion, and bugs in code that wasn't protected against this asynchrony.

To resolve this problem, we've introduced the concept of element behaviors for Internet Explorer 5.5. They aren't specified with CSS, but through an IMPORT processing instruction. Here's an example:

<?IMPORT namespace = MS implementation = "input.htc" >

The parser will "stall" on loading this instruction, and will not continue until the HTC or object ID specified in the IMPORT is fully loaded. This means that elements specified with an IMPORT can be considered synchronous, just like other HTML and XML elements.

Also, the HTC for an element behavior must specify an additional line:

<PUBLIC:COMPONENT tagName=INPUT >

This declares that the HTC is an element behavior, and specifies the tag name for that element.

Element behaviors can also be built as binary behaviors. We've done this internally to create a set of rich controls. For example, we've built a new combo box that can contain rich HTML.

The last example I'll review isn't very pretty, but it shows off some important points about both ViewLink and element behaviors.

Key points are:

  • Element behaviors and ViewLinking can both be nested. The document for a ViewLinked behavior can itself contain other Element Behaviors which are themselves ViewLinked.
  • Events stop at ViewLink boundaries. They must be manually fired to get "out" of a ViewLinked document.

View the sample. Click the first button, and the word "Clicked" appears in the input.

Here's the source for main.htm:

<HTML xmlns:MS>

<?IMPORT namespace = MS implementation = "mypage.htc" >

<BODY>
<MS:MYPAGE STYLE="width:100%; height:100%; " />
</BODY>
</HTML>

This page has only the MS:MYPAGE tag defined in it; there is no other code. Let's look at the mypage.htc file:

<HTML xmlns:MS>

<?IMPORT namespace = MS implementation = "button.htc" >
<?IMPORT namespace = MS implementation = "input.htc" >

<PUBLIC:COMPONENT tagName=MYPAGE >
<public:defaults viewLinkContent />
<public:attach event=oncontentready onevent="init();" />
</public:component>

<SCRIPT>
function init() {
}

function clicked() {
  MyInput.value = "Clicked";
}

</SCRIPT>

<BODY STYLE="xwidth:100%; xheight:100%; font-family: verdana">

<H2>View Linked Element Behaviors</H2>
<MS:BUTTON ID=MyButton CLICK="clicked()" TEXT="Click Me"/>
<BR>
<MS:INPUT ID=MyInput />

</BODY>

This HTC is ViewLinked, and also includes the declarations for the MS:BUTTON and MS:INPUT tags. Note that the MS:BUTTON tag exposes a click event, and we've declared that when the click event occurs, the clicked() method should be called. This click event is a synthetic event that the MS:BUTTON control defines. Event manipulation is very similar to DHTML behavior event management from Internet Explorer 5. However, these events become even more important, as now they are the only way to get events out of a ViewLinked element behavior.

Lets take a look at how that's done.

<PUBLIC:COMPONENT tagName=BUTTON >
<public:defaults viewLinkContent />
<public:property name="text" put="setText" get="getText"/>
<public:event id=MyClick name="click" />
<public:attach event=oncontentready onevent="init();" />
</public:component>

<SCRIPT>
function init() {
  TheButton.attachEvent("onclick", doOnclick);
}

function doOnclick() {
  MyClick.fire();
}

function setText(v) {
  TheButton.innerHTML = v;
}

function getText() {
  return text;
}

</SCRIPT>

<BODY STYLE="width:100%; height:100%">

<BUTTON ID=TheButton></BUTTON>

</BODY>

Note that this HTC defines the click event in the following line:

<public:event id=MyClick name="click"/>

When the onclick event of the button occurs, the behavior translates that into the firing of the synthetic click event. If I had a more complex situation, such as a calendar, an onclick event on a <TD> element representing a day might be translated into a behavior-specific dayclick event. In this way, the implementation of your behaviors is truly separate from the properties, methods, and events that they expose to the outside world.

Summary

Having a powerful component model is a requirement for a full-fledged development platform. The component model delivered by Internet Explorer 5.5 has many features that allow the development of reusable components.

 

DHTML Dude

Michael Wallent is Microsoft's group program manager for Internet Explorer.


  
Show: