Adding getChildNode Function to YUI

One of the well-known differences between IE and FireFox is the treatment of whitespace when searching the DOM. In IE whitespace between tags is stripped out, while in FireFox those white spaces remain. This can be a problem when using DOM pointers like firstChild, nextSibling, etc., because in FireFox, they may not return the node you expected, unless you compress white spaces out of your HTML. One solution is to write a method cleanWhitespaces that iterates through the children of a node and removes any unnecessary white space textnodes. YUI took a different approach, writing methods to replace the native pointers, that ignore white spaces; so firstChild becomes getFirstChild. Generally, unless frequently needing to reference the children of a node, the performance is better using the YUI methods than to use cleanWhitespaces.

However, the YUI team did not write a method to replace using the childNodes nodelist. Here is my implementation of it:

Example 1: getChildNode

getChildNode: function(elem, i) {
	var j = 0,
		node = YAHOO.util.Dom.get(elem);

	if (! node) {return null;}

	return YAHOO.util.Dom.getFirstChildBy(node, function() {
		if (i === j) {return true;}
		j += 1;
	});
},

This method simply does what the childNodes nodelist does, except it always skips empty white spaces. The method leverages the getFirstChildBy method already built into YUI, which finds the first child, then its siblings until the the provided function returns true, at which point it returns the node. In this case, the evaluation function returns true when the node index matches that of the desired index. The only difference, is that childNodes will return undefined if you exceed its length, while this method will return NULL.

I do not think I have written an article about the cleanWhitespaces method, so let me share it with you here:

Example 2: cleanWhitespaces

cleanWhitespace: function(elem) {
	var node = Dom.get(elem);
	if (! node) {return null;}
	var cld = node.firstChild;

	while (cld) {
		var nextNode = cld.nextSibling;
		if (8 === cld.nodeType || (3 === cld.nodeType && ! /\S/.test(cld.nodeValue))) { // comment and text nodes
			node.removeChild(cld);
		}
		cld = nextNode;
	}

	return node;
},

The method iterates on the children, using a while loop to test for the existence of the nextSibling. If the child is an empty text node or a comment node, it is removed from the document. This will ensure that using the built in DOM pointers will work correctly on a given node, however, there is the drawback that it must iterate through all the children of a node, even if there are 50 children and you really only care about the first child.