// Generic script to consolidate different browser DOM models
// Last change by: $Author: ara $
// Last changed: $Date: 2006-04-19 12:11:52 +0100 (Wed, 19 Apr 2006) $
// This file @ sub rev: $Rev: 2632 $

// This script provides a variety of functions for determining and accessing the DOM capabilities of the browser

// By setting debug=true anywhere in the javascript on a page incorporating this file
// you activate debug functionality that tells you the name of any non-existing element
// that you try and access. With the debug flag off, errors are silently ignored.

var isDHTML=0;
var isLayers=0;
var isAll=0;
var isID=0;
var isIE = !window.opera && navigator.userAgent.indexOf('MSIE') != -1;

// Work out capabilities of this browser
if (document.getElementById) {
	isID=1; 
	isDHTML=1;
 } else {
	if (document.all) {
		isAll=1;
		isDHTML=1;
	} else {
		browserVersion = parseInt(navigator.appVersion);
		if ((navigator.appName.indexOf('Netscape') !=-1)
				&& (browserVersion==4)
				) {
			isLayers=1;
			isDHTML=1;
		}
	}
 }

// Return a reference to objectID in the DOM, 
// if withStyle, then a reference to that object's style properties
function findDOM(objectID, withStyle) {
	var retVar;

	if (isLayers) {
		return (document.layers[objectID]);
	}

	if (withStyle==1) {
		if (isID) {
			if (document.getElementById(objectID) == null ) {
				er(objectID);	return;
			}
			return (document.getElementById(objectID).style);
		} else {
			if (isAll) {
				if ((document.all[objectID].style) == null ) {
					er(objectID);	return;
				}
				return (document.all[objectID].style);
			}
		}
	} else {
		if (isID) {
			if (document.getElementById(objectID) == null) {
				er(objectID);	return;
			}
			return (document.getElementById(objectID));
		} else {
			if (isAll) {
				if (document.all[objectID] == null) {
					er(objectID); return;
				}
				return (document.all[objectID]);
			}
		}
	}
};

// Find the next node of a given name after the specified node
function findNext(startNode, name) {
	var currentNode=startNode;
	while (currentNode.nextSibling) {
		if (currentNode.nextSibling.tagName==name) {
			return currentNode.nextSibling;
		}
		currentNode=currentNode.nextSibling;
	}
	return false;
}

// Check whether we're debugging
function debugging() {
	if ( (typeof(debug)!="undefined") && (debug===true) && (debug!=0)) {
		return true;
	} else {
		return false;
	}
}

// Handle trying to access elements that don't exist
function er(object) {
	if (debugging()) {
		alert('You tried to access null object: '+object);
	}
}

// Based on findPos*, by ppk (http://www.quirksmode.org/js/findpos.html)
// Return the x position of the specified object
function findPosX(obj) {
  var curLeft = 0;
  if (obj.offsetParent) {
    do {
      curLeft += obj.offsetLeft;
    } while (obj = obj.offsetParent);
  }
  else if (obj.x) {
    curLeft += obj.x;
  }
  return curLeft;
}

// Return the y position of the specified object
// BUG Different answers in IE and FF?
function findPosY(obj) {
	if (document.getBoxObjectFor) {
		// Firefox - position within DOM
		var bo = document.getBoxObjectFor(obj);
		y = bo.y;
	} else if (obj.getBoundingClientRect) {
		// IE - position on screen
		if (!document.documentElement.scrollTop) {
			scrollY = document.body.scrollTop;
		} else {
			scrollY = document.documentElement.scrollTop;
		}
		var rect = obj.getBoundingClientRect();
		y = rect.top+scrollY;
	}
	return y;
}

// Add an event listener to a specified event on a specified object
// obj = object name
// evType = event type, eg. "load", "change"
// fn = function to call. Not quoted and no parenthesis
// useCapture = event capturing - specify false
function addEvent(obj, evType, fn, useCapture) {
	if (isIE) {
		obj.attachEvent('on' + evType, fn);
	} else if (obj.addEventListener) {
		obj.addEventListener(evType, fn, useCapture);
	} else {
		obj['on' + evType] = fn;
	}
}

// Removes an event handler, if it exists
function removeEvent(obj, evType, fn) {
	if (isIE) {
		obj.detachEvent('on'+evType, fn);
	} else {
		obj.removeEventListener(evType, fn, false);
	}
}

// Find the target of an event
function findTarget(e) {
  var target; 

  if (window.event && window.event.srcElement) 
    target = window.event.srcElement;
  else if (e && e.target)
    target = e.target;
  if (!target)
    return null;

	return target;
}

// climb up the tree to the supplied tag.
function ascendDOM(e, target) {
  while (e.nodeName.toLowerCase() != target && 
				 e.nodeName.toLowerCase() != 'html')
    e = e.parentNode;
  
  return (e.nodeName.toLowerCase() == 'html') ? null : e;
}

// Function removes a class from an object
function removeClassFromObject(object, classToRemove) {
	object.className=object.className.replace(" "+classToRemove, "");
	object.className=object.className.replace(classToRemove+" ", "");
}

// Function tests to see whether a given object is of the given class
function isOfClass(ob, className) {
	var regex=new RegExp();
	regex.compile(className+"|^"+className+"\s+|\s+"+className+"$|\s+"+className+"\s+");
	
	if (regex.test(ob.className)) {
		return true;
	} else {
		return false;
	}
}

// Function returns a list of all nodes under 'startNode' of class 'className'
function getElementsByClassName(startNode, className) {
	var arr = new Array();
	var elems = startNode.getElementsByTagName("*");
	var regex=new RegExp();
	regex.compile(className+"|^"+className+"\s+|\s+"+className+"$|\s+"+className+"\s+");

	for(var i = 0; i < elems.length; i++) {
		//			alert('Got: '+elems[i].className);
		if (regex.test(elems[i].className)) {
			arr[arr.length]=elems[i];
		}		
	}
	return arr;
}

// this function sets the specified property to the specified value
// on all members of the specified class, within the specified object
function setPropOnClassMembers(rootObject, className, propertyName, propertyValue) {
	var nodes=getElementsByClassName(rootObject, className);
	for (var i=0; i<nodes.length; i++) {
		nodes[i].style[propertyName] = propertyValue;
	}
}

// Finds a rule from this documents stylesheets for this class
function findClassRule(ruleName) {
	var rules;
	for (var i=0; i<document.styleSheets.length; i++){
		if (isIE) {
			rules=document.styleSheets[i].rules;
		} else {
			rules=document.styleSheets[i].cssRules;
		}
		for (var j=0; j<rules.length; j++) {
			var rule=rules[j];
			if (rule.selectorText=="."+ruleName) {
				if (debugging()) {
					alert('Found selector '+ruleName);
				}
				return rule;
			}
		}
	}
	return false;
}

// This function modifies an existing CSS rule - effectively should accomplish the same thing as
// setPropOnClassMembers, but probably a lot faster
// THIS FUNCTION WILL NOT OVERRIDE STYLE SETTINGS IN THE ELEMENT TAG ITSELF, as the tag has
// precedence over the stylesheet. Use setPropOnClassMembers.
function changeClassRule(ruleName, selName,  selValue) {
	var myCss="";
	var rule=findClassRule(ruleName);
	if (! (rule===false)) {
		rule.style[selName]=selValue;
	} else {
		// Rule wasn't found
		var sheet=document.styleSheets[document.styleSheets.length-1];
		if (debugging()) {
			alert('No existing rule found for '+ruleName+', so adding');
		}
		if (isIE) {
			sheet.addRule("."+ruleName, selName+": "+selValue);
		} else {
			sheet.insertRule("."+ruleName+"{"+selName+": "+selValue+";}", sheet.cssRules.length-1);
		}
	}
}

// Function allows setting the value of a select box by providing the value, not the 
// option index
function setSelect(select, val) {
	if (val=='') {
		select.selectedIndex=-1;
	}

	for (var i=0; i<select.options.length; i++) {
		if (select.options[i].value==val) {
			select.selectedIndex=i;
			return true;
		}
	}
	return false;
}

// This doesn't really belong here, but it needs to be present on nearly every page
function printfire() {
	if (document.createEvent) {
		printfire.args = arguments;
		var ev = document.createEvent("Events");
		ev.initEvent("printfire", false, true);
		dispatchEvent(ev);
	}
}

// Function to update a get parameter within a URL
function updateGetParameter(url, param, val) {
	// Check if there are any parameters in the url yet
	if (url.indexOf('?')==-1) {
		// Append new one to the end
		url+="?"+param+"="+val;
		return url;
	}
	// Check to see if parameter is in URL
	if (url.indexOf(param)!=-1) {
		// Remove it
		var re=new RegExp("&?"+param+"=.*?[^&$]", "i");
		url.replace(re, "");
	}
	if (val!="") {
		url+="&"+param+"="+val;
	}
	return url;
}

