/*	Versie:					1.0
	Datum:					9 mei 2005
	Auteur:					Koen Peters	
	Backwards compatible: 	n.v.t. dit is de eerste versie
	Korte Beschrijving: 	Script waarmee de DOM tree van een bestand kan worden doorlopen, om specifieke elementen te zoeken
	Changes: 				-
	Dependencies:			-
*/

/************************************************************/
/*								BY ID						*/
/************************************************************/

// Deze functie retourneert het element binnen de DOMtree waarvan het id gelijk is aan de meegegeven searchId. 
// Er wordt alleen gezocht binnen de subDOMtree van element startNode.
// @param searchId		Het id waarnaar wordt gezocht.
// @param startNode		De Node waarbinnen moet worden gezocht.
function getElementByIdFromStartNode(searchId, startNode) {
	// Loop de DOM structuur af en controleer op id.
	if (startNode.nodeType == 1 || startNode.nodeType == 9 ) /* ELEMENT_NODE OF DOCUMENT_NODE */ {
		var elem		= startNode.id == searchId? startNode: null;
		var i			= 0;			
		var children	= startNode.childNodes;
		if (startNode.tagName != 'SELECT') /* Niet zoeken in lange select lijsten. Dit vreet tijd */ {
			while (!elem && i < children.length) {				
				elem = getElementByIdFromStartNode(searchId, children[i]);
				i+=1;
			}
		}
		return elem;
	}
}


/************************************************************/
/*								BY TAGNAME					*/
/************************************************************/


// Deze functie retourneert het eerste element binnen de DOMtree waarvan de tagName gelijk is aan de meegegeven tagName. 
// Er wordt alleen gezocht binnen de subDOMtree van element startNode.
// @param tagName		De tagName waarnaar moet worden gezocht.
// @param startNode		De Node waarbinnen moet worden gezocht.
function getFirstElementByTagNameFromStartNode(tagName, startNode) {
	var elements = getElementsByTagNameFromStartNode(tagName, startNode, 1);
	if (elements) return elements[0]
	else return null;
}


// Deze functie retourneert alle elementen binnen de DOMtree waarvan de tagName gelijk is aan de meegegeven tagName. 
// Er wordt alleen gezocht binnen de subDOMtree van element startNode. Eventueel wordt er gezocht naar een maximaal aantal
// elementen. Het zoeken stopt zodra dit aantal is bereikt.
// @param tagName		De tagName waarnaar moet worden gezocht.
// @param startNode		De Node waarbinnen moet worden gezocht.
// @param maxElements	(optioneel) Het aantal elementen dat moet worden gevonden voordat het zoeken wordt gestaakt. Indien niet opgegeven dan worden alle elementen gezocht.
function getElementsByTagNameFromStartNode(tagName, startNode, maxElements) {
	if (startNode && (!maxElements || maxElements > 0)) {
		var arr = new Array();	
		rec(tagName, startNode, arr, maxElements);
		if (arr.length > 0) return arr
		else return null;
	} 
}

// Recursieve helperfunctie van de getElementsByTagNameFromStartNode functie 
// Niet direct aanroepen.
function rec(tagName, startNode, arr, maxElements) {
	if (startNode.nodeType == 1 || startNode.nodeType == 9) /* ELEMENT_NODE OF DOCUMENT_NODE */ {
		if (startNode.tagName == tagName) arr.push(startNode);
		if (tagName != 'OPTION' && startNode.tagName != 'SELECT') /* Niet zoeken in lange select lijsten. Dit vreet tijd */ {			
			if (!maxElements || maxElements > arr.length) {
			// Het aantal elementen dat moet worden gevonden is nog niet bereikt of er zit geen grens aan dit aantal.
				var children = startNode.childNodes;
				for(var i=0; i < children.length; i+=1) {				
					rec(tagName, children[i], arr);
				}
			}
		}
	}
}


/************************************************************/
/*								BY NAME						*/
/************************************************************/


// Deze functie retourneert het eerste element binnen de DOMtree waarvan het name attribuut gelijk is aan de meegegeven string. 
// Er wordt alleen gezocht binnen de subDOMtree van element startNode.
// @param name			De naam waarnaar moet worden gezocht.
// @param startNode		De Node waarbinnen moet worden gezocht.
function getElementsByNameFromStartNode(name, startNode) {
	if (startNode) {
		var arr = new Array();	
		rec2(name, startNode, arr);
		if (arr.length > 0) return arr
		else return null;
	} 
}

// Recursieve helperfunctie van de getElementsByTagNameFromStartNode functie 
// Niet direct aanroepen.
function rec2(name, startNode, arr) {
	if (startNode.nodeType == 1 || startNode.nodeType == 9) /* ELEMENT_NODE OF DOCUMENT_NODE */ {
		if (startNode.name && startNode.name == name) arr.push(startNode);
		if (startNode.tagName != 'SELECT') /* Niet zoeken in lange select lijsten. Dit vreet tijd */ {			
			var children = startNode.childNodes;
			for(var i=0; i < children.length; i+=1) {				
				rec2(name, children[i], arr);
			}			
		}
	}
}



/************************************************************/
/*							HAS CLASSNAME					*/
/************************************************************/


/* Methode die bepaalt of een van de de classes die zijn gekoppeld aan een node overeenkomt met een meegegeven className */
function nodeHasClass(node, className) {
	var c = node.className;				
	if (c) {
		if (c.indexOf(className + ' ') == 0) return true; 																			// eerste class van een rij van classes 
		if (c.indexOf(className) == 0  && c.length == className.length) return true;												// eerste en enige class 
		if ((c.indexOf(' ' + className) == (c.length - (className.length + 1))) && c.indexOf(' ' + className) > 0) return true; 	// laatste class van een rij van classes 
		if (c.indexOf(' ' + className + ' ') != -1)  return true;																	// een van de middelste classes van een rij van classes 
	}
	return false;
}

/* Methode die bepaalt of een van de de classes die zijn gekoppeld aan een node begint met een meegegeven string (className)*/
function nodeHasClassThatStartsWith(node, className) {
	var c = node.className;			
	if (c) {
		if (c.indexOf(className) == 0) return true;
		if (c.indexOf(' ' + className) != -1) return true;	/* een van de middelste classes of de laatste van een rij van classes */
	} 
	return false;
}



/************************************************************/
/*							BY CLASS						*/
/************************************************************/


// Deze functie retourneert het eerste element binnen de DOMtree waarvan de className gelijk is aan de meegegeven className. 
// Er wordt alleen gezocht binnen de subDOMtree van element startNode.
// @param className		De className waarnaar moet worden gezocht.
// @param startNode		De Node waarbinnen moet worden gezocht.
function getFirstElementThatHasClassFromStartNode(className, startNode) {
	var elements = getElementsThatHaveClassFromStartNode(className, startNode, 1);
	if (elements) return elements[0]
	else return null;
}


	// Deze functie retourneert alle elementen binnen de DOMtree waarvan de className gelijk is aan de meegegeven className. 
	// Er wordt alleen gezocht binnen de subDOMtree van element startNode. Eventueel wordt er gezocht naar een maximaal aantal
	// elementen. Het zoeken stopt zodra dit aantal is bereikt.
	// @param className		De className waarnaar moet worden gezocht.
	// @param startNode		De Node waarbinnen moet worden gezocht.
	// @param maxElements	(optioneel) Het aantal elementen dat moet worden gevonden voordat het zoeken wordt gestaakt. Indien niet opgegeven dan worden alle elementen gezocht.
	function getElementsThatHaveClassFromStartNode(className, startNode, maxElements) {
		if (startNode && (!maxElements || maxElements > 0)) {
			var arr = new Array();	
			rec3(className, startNode, arr, maxElements);
			if (arr.length > 0) return arr
			else return null;
		} 
	}

	// Recursieve helperfunctie van de getElementsThatHaveClassFromStartNode functie 
	// Niet direct aanroepen.
	function rec3(className, startNode, arr, maxElements) {
		if (startNode.nodeType == 1 || startNode.nodeType == 9) /* ELEMENT_NODE OF DOCUMENT_NODE */ {
			if (nodeHasClass(startNode, className)) arr.push(startNode);
			if (startNode.tagName != 'SELECT') /* Niet zoeken in lange select lijsten. Dit vreet tijd */ {
				if (!maxElements || maxElements > arr.length) {
				// Het aantal elementen dat moet worden gevonden is nog niet bereikt of er zit geen grens aan dit aantal.
					var children = startNode.childNodes;
					for(var i=0; i < children.length; i+=1) {				
						rec3(className, children[i], arr);
					}
				}
			}
		}
	}