/* Generic DHTML functions, for use with DOM-compatible browsers (IE 5+, Gecko, Opera 7+ */

/*
   This library is written by Alun David Bestor (abestor@washboardabs.net) 2004
   This work is licensed under the Creative Commons Attribution-ShareAlike License (http://creativecommons.org/licenses/by-sa/2.0/).
   It is free for use on commercial and non-commercial projects, as long as attribution is given and any modifications are released under the same license.
*/

//Return a proper object-reference from any input
//Accepts both id strings and objects as input, so can be used transparently when you're
//not sure whether the variable you're dealing with is already an object-reference
function getRef(el)
{
	if		(typeof(el) == 'object') return el;
	else if	(typeof(el) == 'string' && document.getElementById) return document.getElementById(el);
	else return false;
}

function getOpenerRef(el)
{
	if (!window.opener || window.opener.closed) return false;

	if		(typeof(el) == 'object') return el;
	else if	(typeof(el) == 'string' && window.opener.document.getElementById) return window.opener.document.getElementById(el);
	else return false;
}

//Return true/false whether an element has specified class
//Note: this function is case-sensitive, just like classnames themselves
//Updated using regex so 'classname' won't match 'classname-1' 
function hasClass(el, string)
{
	el = getRef(el);
	if (!el || !el.className) return false;
	if (window.RegExp)
	{
		classEx = new RegExp("(\\s|^)(" + string + ")(\\s|$)");
		if (el.className.search(classEx) > -1) return true;
		else return false;
	}
	else
	{
		if (el.className.indexOf(string) > -1) return true;
		else return false;
	}
}

//Add specified class to element, if it doesn't already have it
function addClass(el, string)
{
	el = getRef(el);
	if (!el) return false;
	if (!el.className) el.className = string;
	else if (!hasClass(el, string))	el.className += ' ' + string;
	return true;
}

//Remove specified class from element
//Note: this function is case-sensitive, just like classnames themselves
//Updated using regex so 'classname' won't match 'classname-1'
//Todo: remove leading whitespace if classname was at end of string (may cause probs in IE5)
function removeClass(el, string)
{
	el = getRef(el);
	if (!el || !el.className) return false;

	if (window.RegExp)
	{
		classEx = new RegExp("(\\s|^)(" + string + ")(\\s|$)", "g");
		el.className = el.className.replace(classEx, '$1');
	}
	else el.className = el.className.replace(string, '');

	return true;
}

//toggle the class on and off the item
function toggleClass(el, string)
{
	el = getRef(el);
	if (hasClass(el, string)) removeClass(el, string);
	else addClass(el, string);
}

//find out whether childEl is a child of parentEl
function isChildOf(el, parentEl)
{
	el			= getRef(el);
	parentEl	= getRef(parentEl);
	if (!el || !parentEl) return false;

	//climb through parents to see if one matches
	while (el = el.parentNode) { if (el == parentEl) return true; }
	return false;
}

//get a reference to a parent with a specific tag (and optionally class)
function getParentTag(el, parentTag, className)
{
	el = getRef(el);
	if (!el || !parentTag) return false;
	parentTag	= parentTag.toLowerCase();

	while ((el = el.parentNode) && el.tagName)
	{
		if (el.tagName.toLowerCase() == parentTag &&
			(!className || hasClass(el, className))) return el;
	}
	return false;
}

//function to return array of elements that match tag and classname
//useful drop-in alternative to el.getElementsByTagName()
//accepts optional parentEl - if none specified, uses document
function getElementsByTagClass(tag, classname, parentEl)
{
	parentEl = (parentEl) ? getRef(parentEl) : document;

	var tagArray = parentEl.getElementsByTagName(tag);
	var returnArray = new Array();
	for (var i = 0; i < tagArray.length; i++)
	{
		if (!classname || hasClass(tagArray[i], classname)) returnArray[returnArray.length] = tagArray[i];
	}
	return returnArray;
}



//attach an event handler to an event for the specified element (cross-browser compatible)
function captureEvent(el, eventName, eventHandler)
{
	el = getRef(el);
	if (el.addEventListener)
	{
		eventName = eventName.substring(2, eventName.length); //trim off 'on'
		el.addEventListener(eventName, eventHandler, false);
	}
	else if (el.attachEvent) el.attachEvent(eventName, eventHandler);
	else if (el[eventName])
	{
		el['old' + eventName] = el[eventName];
		el[eventName] = function() { el['old' + eventName](); eventHandler(); }
	}
	else el[eventName] = eventHandler;
}

//attaches a function to the body onLoad event
//(needed for template-driven pages that don't have access to body element)
function callOnLoad(eventHandler)	{ captureEvent(window, 'onload', eventHandler); }


//get next/previous element (ignores whitespace and text nodes)
function getNextSibling(el)
{
	el = getRef(el);
	if (!el) return false;

	while (el = el.nextSibling) if (el.nodeType == 1) return el;
	return false;
}

function getPreviousSibling(el)
{
	el = getRef(el);
	if (!el) return false;

	while (el = el.previousSibling) if (el.nodeType == 1) return el;
	return false;
}

//highlights the element targeted by the URL fragment when page is loaded (emulates CSS3 :target selector)
function highlightTarget()
{
	if (location.hash)
	{
		fragment = location.hash.substr(1);
		addClass(fragment, 'target');
	}
}
callOnLoad(highlightTarget);