If you're like me, and you bought into Microsoft IE HTC behaviors, it is pretty obvious by now that this feature of IE is not going to be supported by any other browser. A few years back when IE was the dominant browser, the concept of "IE Only" feature would not have been a problem, but by now other browsers are not only gaining in momentum over IE, but are much faster and better designed too.

HTC behaviors offered a nice programming methodology, that allowed a web designer to attach behaviors to HTML elements, and in addition allowed for attaching both standard and custom events, via the class attribute declaration.
It was easy and fast, and offered encapsulation of variables and data, and many designers using this technology were hoping to have that standard be adopted by all browsers, which never happened.

4 years ago I started working for a company called Liquid Robotics, and I developed the Wave Glider Management System to track and control the company expanding fleet of gliders. I was facing an insurmountable task of developing a fairly complex data acquisition, database and web based UI.
With limited development and test budgets the choice was made to go "IE Only", which seemed reasonable at the time, because IE seemed like the only browser around. I used HTCs in the UI because I liked the concept of attaching behaviors to HTML controls on a form, and I could quickly create smart forms on the fly without having to duplicate code all over the place.

In recent years Liquid Robotics has been expanding it's customer base, and consequently the Wave Glider Management System (WGMS for short) has been expanding it's user base and functionality as well. This larger pool of users raised the priority for the need to convert WGMS UI to become "Cross-Browser".

One of the first tasks that I had to do was to find an alternative for HTC behavior scripts, and as much as I researched this topic, I couldn't find any real examples of work that demonstrated that successfully.

After researching this issue, I decided to implement my own JavaScript behavior classes using "Object Oriented" JavaScript objects, that would basically be drop-in compatible with HTC code. This will allow IE browsers to continue running HTCs, but at the same time any other browser (Chrome/Safari/Firefox/Mobile Safari) could execute the equivalent objects in JavaScript.

What are the requirements for developing a drop-in replacement to an HTC behavior in JavaScript:
1) Provide the equivalent access to methods, properties
2) Provide ability to handle both "standard" and "custom" events
3) Provide an ability to reference JavaScript objects extending HTML elements

In this part 1, I will cover the creation of the "Cross-Browser" JavaScript Object from an HTC script.

A typical HTC header format for a form control called "DateControl" would look something like this:

<?xml version="1.0" encoding="ISO-8859-1"?>
<public:component xmlns:public="urn:HTMLComponent" lightweight="true">
<public:attach event="ondocumentready" onevent="init()" />
<public:attach event="onblur" onevent="onBlur()" />
<public:property name="IsDirty" get="isDirty" />
<public:property name="Data" get="getDataXml" />
<public:property name="Content" get="getContent" put="putContent" />
<public:property name="Disabled" get="getDisabled" put="setDisabled" />
<public:method name="SetFocus" internalname="setFocus" />

<public:event name="oncontrolchange" id="OnChange" />

This header is a fairly typical implementation of a form control that provides methods, properties, event handlers for events that it wants to "listen" to, and a custom event that it can generate.

The cross browser JavaScript object that would be the drop-in replacement would look like:

function DateControl(sElementId)
// private vars
var element;
var _bInitialized = false;
var _defaultValue;

// public methods
this.Init = init;
this.SetFocus = setFocus;
this.GetData = getDataXml;
this.GetContent = getContent;
this.PutContent = putContent;
this.GetDisabled = getDisabled;
this.PutDisabled = putDisabled;
this.GetIsDirty = getIsDirty;

// public memebers
this.ElementId = sElementId;
this.Element = element;

function init()
if (!_bInitialized)
element = getHtmlObj(document, sElementId);
AttachEvent(element, "onchange", onChange);
AttachEvent(element, "onblur", onBlur);

// Set initial value
_defaultValue = element.value;


_bInitialized = true;
element.defaultValue = element.value;

// additional methods defined ...

function AddProperties(obj)
if (typeof Object.defineProperty == 'function')
var descriptor;
descriptor = { get: function() { return this.GetDataXml(); } };
Object.defineProperty(obj, "Data", descriptor);
descriptor = { get: function() { return this.GetContent(); }, set: function(vVal) { this.PutContent(vVal); } };
Object.defineProperty(obj, "Content", descriptor);
descriptor = { get: function() { return this.GetDisabled(); }, set: function(vVal) { this.PutDisabled(vVal); } };
Object.defineProperty(obj, "Disabled", descriptor);
descriptor = { get: function() { return this.GetIsDirty(); } };
Object.defineProperty(obj, "IsDirty", descriptor);

DateControl.prototype.toString = function()
return "[Date Control object <" + this.ElementId + ">]";

In this skeleton object definition only two methods are shown:
AddProperties: which is the method that maps public properties to internal methods.
Init: called on document ready to initialize the object values, and declare it's properties.

Additional details about the internals of the JavaScript object will be discussed in Part 4.

A utility function called from the above DateControl code:
function getHtmlObj(oDoc, sId)
if (typeof(oDoc.getElementById) == 'undefined')
  return oDoc.all[sId];
  return oDoc.getElementById(sId);

Extending a form control with the old HTC behavior was a style declaration that only IE browser could interpret:

behavior: url(/forms/datecontrol.htc);

and subsequently the input HTML control with the appropriate style ...
<input type="text" id="ControlId" name="ControlId" tabindex="0" class="date" title="12/15/2009" value="12/15/2009" />

Extending a form control with the new "Cross-Browser" object would require a JavaScript statement in the header section of the HTML file:

var ControlId = new DateControl("ControlId");
_jsDom.addItem("ControlId ",ControlId );

This defines a new object of type DateControl that is named as the ID of the HTML control that it extends. There would be definitions like this for all controls that require that behavior extensions.
The second declaration is a special JavaScript class (JsDom) which provides a standard collection of all these type of objects be cached and retrieved for use. JsDom will be discussed in detail in the Second part of this article.


View comments