Some time ago, I needed to find out if a DOM element is a descendant of another. A simple and elegant way to accomplish this is:

/**
 *
 * @param mixed granpa
 *
 */
Element.prototype.isDescendantOf = function( granpa ) {
	if ( typeof( granpa ) == 'string' ) {
		granpa = document.getElementById( granpa );
	}
	if ( !granpa ) {
		return false;
	}
	child = this;
	do {
		if (child == granpa ) {
			return true;
		}
		child = child.parentNode;
	}
	while ( child );
	return false;
}

…and afterwards…

var foo = document.getElementById( 'foo' );
var bar = document.getElementById( 'bar' );
if ( foo.isDescendantOf( bar ) ) {
	/* whatever */
}

Cool, isn’t it?

Element.prototype in IE

This kind of approach to js apps works perfect in all modern browsers. But not in “that browser”. Not in the browser of the many. Because Microsoft doesn’t allow adding custom methods to the “Element” object. Of course, I’ve tried to use “Object” instead of “Element”, but this doesn’t work either – contrary to the ECMA specifications. In other words, it simply sucks.

But after some googling around, I`ve reach deep into the realm of darkness, the MSDN. And there I’ve read about IE behaviors, a strange mixture of JScript and XML stored in a HTC file. So I’ve decided to make one last attempt to get the script working, before smashing my forehead into the keyboard. First of all, an Element object is needed. So I’ve added these lines to my js file.

if ( !window.Element ) {
	Element = function() {};
}

After that, I’ve started writing the HTC file. It looked like:

<PUBLIC:COMPONENT>
	<PUBLIC:METHOD NAME="isDescendantOf" INTERNALNAME="_isDescendantOf" />
		<script type="text/javascript">
			var element = new Element;
			_isDescendantOf = element.isDescendantOf;
		</script>
</PUBLIC:COMPONENT>

Now this behaviour must be added to all elements if the browser is Internet Explorer. Time to use some simple conditional comments and the CSS universal selector:

<!--[if IE]>
<style type="text/css">
* { behavior: url(ie_fix.htc) }
</style>
<![endif]-->

And it worked. Eurika. You can download the gzipped example here. Behaviours are not supported by the wine emulated versions of Internet Explorer, so this must be tested on Microsoft Windows ®.

Prototype’s (the framework) $ function

I consider prototype to be one of best javascript frameworks ever. Yes, I know there are other smaller, less bloated, better documented frameworks out there, but for me, prototype does the job to well to even consider switching.

Using prototype is another way to add custom methods to the Element object. Declare your methods as elements of a javascript hashtable (an array) and then call Element.addMethods().

var methods = {
	isDescendantOf: function( granpa ) {
		if ( typeof( granpa ) == 'string' ) {
			granpa = document.getElementById( granpa );
		}
		if ( !granpa ) {
			return false;
		}
		child = this;
		do {
			if ( child == granpa ) {
				return true;
			}
			child = child.parentNode;
		}
		while ( child );
		return false;
	}
}
Element.addMethods( methods );

Please note that the custom methods will only be available on nodes retrieved by prototype’s $() function, and not on those retrieved by good old fashioned document.getElementById(). That’s how prototype works.