function $(element_id) {
	/*returns an element by ID*/
	if (document.getElementById(element_id)) {
		return document.getElementById(element_id);
	} else {
		return null;
	}
}

function $$(tag_name) {
	/*returns an array of elements by tag name (e.g. A, BR, DIV)*/
	return document.getElementsByTagName(element_id);
}

function $a(tag_name, attribute, value, root_node) {
	/*returns an array of elements by attribute/value
		tag_name: tag name to search
		attribute: attribute name
		value: (optional) attribute value*/
	root_node = root_node || document.body;
	var elements = root_node.getElementsByTagName(tag_name);
	var return_elements = new Array();
	
	for (var a = 0; a < elements.length; a++) {
		if (attribute == "class") {
			attr = elements[a].className;
		} else {
			attr = elements[a].getAttribute(attribute);
		}
		
		if (typeof(value) == "function" || typeof(value) == "object") {
			if (value.test(attr) == true)
				return_elements.push(elements[a]);
		} else {
			if ((attr != null && value == null) || attr == value)
				return_elements.push(elements[a]);
		}
	}
	
	return return_elements;
}

function tag_value(dom_root, tag_name) {
	/*retrieves the value of a (unique) tag within a DOM compatible document
	of the tag name isn't unique, an array of all the values are returned.
		dom_root: DOM compatible document
		tag_name: name of the <tag/> to search for*/
	var elements = dom_root.getElementsByTagName(tag_name)
	var val = null;
	
	if (elements.length > 1) {
		val = new Array();
		
		for (var a = 0; a < elements.length; a++) {
			if (elements[a].childNodes[0] != null)
				val.push(elements[a].childNodes[0].nodeValue);
		}
	} else if (elements.length == 1) {
		if (elements[0].childNodes[0] != null) {
			val = elements[0].childNodes[0].nodeValue;
		} else {
			val = null;
		}
	}
	
	return val;
}

function create_element(root_element_id, tagname, id, class_name) {
	//post_log("Creating " + tagname + " element with id: " + id + ", class: " + class_name
	//  + ", under element: " + root_element_id);
	//creates and returns an html DOM element
	var element;
	
	if (!$(id)) {
		if (root_element_id != null) {
			root_element = $(root_element_id)
		
			if (root_element == null) {
				alert("create_element() - Root element with ID '" 
					+ root_element_id + "' not found!");
				return false;
			}
		} else {
			var root_element = document.body;
		}
	
		var element = document.createElement(tagname);
	
		if (id != null) {
			element.setAttribute("id", id);
		}
	
		root_element.appendChild(element);
	} else {
		//if it already exists, return it
		element = $(id);
	}

	if (class_name != null) {
		element.className = class_name;
		element.setAttribute("class", class_name);
	}
	
	return element;
}

function destroy_element(element, quiet, reinstate_selects) {
	//removes an element by ID
	if (typeof(element) == "string")
		element = $(element);
	
	if (quiet == null)
		quiet = true;
		
	if (element == null && quiet) {
		return false;
	} else if (element == null && !quiet) {
		alert("destroy_element() - Element not found!");
	}
		
	var element_arr = Array();
	//element_arr['next_sibling'] = element.nextSibling;			
	element_arr['parent_node'] = element.parentNode;
	
	//remove parent if it's a dynamic DOM container (and now empty), or just remove element
	if (element.parentNode.className == "dynDomContainer" 
		&& element.parentNode.childNodes.length == 1) {
		element_arr['node'] = element.parentNode.parentNode.removeChild(element.parentNode);
	} else {
		element_arr['node'] = element.parentNode.removeChild(element);
	}
	
	//store element in deleted nodes array
	DOM_CACHE[element.id] = element_arr;
	
	if (reinstate_selects) ie6_top_objects(false);
	
	return false;
}

function restore_element(element_id, highlight) {
	/*restore a previously destroyed element*/
	if (DOM_CACHE[element_id] != null) {
		var element = DOM_CACHE[element_id]['parent_node'].appendChild(DOM_CACHE[element_id]['node']);
		
		if (highlight) {
			//highlight the element with a fun colour
			highlight_element(element);
		}
	}
}

function destroy_element_children(element) {
	/*removes all element children
		element: element or element ID reference to remove children of*/
	if (typeof(element) == "string")
		element = $(element);
		
	if (element != null) {
		while (element.firstChild) {
			element.removeChild(element.firstChild);
		}
	} else {
		alert("destroy_element_children() - Element not found!");
	}
}

function switch_element_parent(element_id, new_parent_id, new_id) {
	//moves an element from one parent to another, with the option
	//to give it a new id specieid by new_id
	var element, new_parent;

	if (element = $(element_id)) {
		element = element.parentNode.removeChild(element);

		if (new_parent = $(new_parent_id)) {
			new_parent.appendChild(element);

			if (new_id != "") {
				element.setAttribute("id", new_id);
			}

			return element;
		} else {
			alert("switch_element_parent() - New parent element with ID '" +
			 	new_parent_id + "' not found!");	
		}
	} else {
		alert("switch_element_parent() - Element with ID '" + element_id + "' not found!");
	}
}

function copy_element(element_id, new_id) {
	//copies an element, gives it a new ID and returns it
	var element, new_parent;

	if (element = $(element_id)) {
		
		new_element = element.cloneNode(true);
		
		if (!$(new_id) && new_id != "") {
			new_element.setAttribute("id", new_id);
		} else {	
			alert("copy_element() - New ID '" + new_id + "' alredy exists or is blank!");
			return false;
		}
		
		return new_element;
	} else {
		alert("copy_element() - Element with ID '" + element_id + "' not found!");
	}
}

function element_left_pos(element) {
	var left = 0;
	
	while (element.offsetParent) {
		left += element.offsetLeft;
		element = element.offsetParent;
	}

	return left;
}

function get_source(e) {
	if (e.srcElement) {
		return e.srcElement;
	} else if (e.target) {
		return e.target;
	} else {
		return false;
	}
}

function element_top_pos(element) {
	var	top = 0;
	
	while (element.offsetParent) {
		top += element.offsetTop;
		element = element.offsetParent;
	}

	return top;
}

function scroll_left() {
	if (document.documentElement) {
		if (document.body.scrollLeft != 0) {
			return document.body.scrollLeft;
		} else if (document.documentElement.scrollLeft != 0) {
			return document.documentElement.scrollLeft;
		} else {
			return 0;
		}
	} else {
		return window.pageXOffset;
	}
}

function scroll_top() {
	if (document.documentElement) {
		if (document.body.scrollTop != 0) {
			return document.body.scrollTop;
		} else if (document.documentElement.scrollTop != 0) {
			return document.documentElement.scrollTop;
		} else {
			//uff :(
			return 0;
		}
	} else {
		return window.pageYOffset;
	}
}

function get_cursor_pos(e) {
	var posx = 0;
	var posy = 0;
	
	e = e||window.event;
	
	if (e.pageX || e.pageY) {
		posx = e.pageX;
		posy = e.pageY;
	} else if (e.clientX || e.clientY) 	{
		posx = e.clientX + document.body.scrollLeft	+ document.documentElement.scrollLeft;
		posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	}
	
	return Array(posx, posy);	
}

function attach_event(element, event_name, action) {
	/*attaches an event to an HTML element.
		element: element object to attach
		event_name: name of the event (e.g. "focus", "mouseover", "click")
		action: function to execute
	*/
	if (element.addEventListener) {
		element.addEventListener(event_name, action, false);
	} else {
		element.attachEvent("on" + event_name, action);
	}
	
	/*in IE (6), there is a memory leak associated with attachEvent, so the event 
	is removed when the page is unloaded.
	http://www.quirksmode.org/blog/archives/2005/08/addevent_consid.html*/
	if (element.attachEvent) {
		window.attachEvent("onunload", function() {
				try {
					//heh, IE 6 eh?
					detach_event(element, event_name, action);
				} catch(e) {}
			});
	}
}

function detach_event(element, event_name, action) {
	/*removes an event from an HTML element.
		element: element ID or element object to remove
		event_name: name of the event (e.g. "focus", "mouseover", "click")
		action: function to remove
	*/
	if (typeof(element) == "string") {
		element = $(element);
	}
	
	if (element != null) {

		if (window.detachEvent) {
			element.detachEvent("on" + event_name, action);
		} else {
			element.removeEventListener(event_name, action, true);
		}
	} else {
		alert("remove_event() - Element with ID '" + element + "' not found!");
	}

}

function obj_event(obj, method_name, args, prevent_default) {
	/*associates a javascript object with a DOM listener event
		obj: object within which the method is contained
		method_name: object method to execute
		args: arguments to send to the method
		prevent_default: prevent the default action (i.e. href in A)
	*/
	return (function(e){
		e = e||window.event;

		if (prevent_default) {
			try {
				e.preventDefault();
			} catch(err) {
				e.returnValue = false;
			}
		}
		
		if (obj[method_name] == undefined) {
			alert("obj_event(): method " + method_name + " doesn't exist");
			return false;
		} else {
			return obj[method_name](e, this, args);
		}
	});
}

function func_event(func, args, prevent_default) {
	/*associates a javascript function with a DOM listener event
		obj: object within which the method is contained
		method_name: object method to execute
		args: arguments to send to the method
		prevent_default: prevent the default action (i.e. href in A)
	*/
	return (function(e){
		e = e||window.event;

		if (prevent_default) {
			try {
				e.preventDefault();
			} catch(err) {
				e.returnValue = false;
			}
		}
		
		return func(e, this, args);
	});
}

function add_class(element, class_name) {
	//adds a classname element to an html tag <tag class="[foo bar whatsit]">

	//make sure the class doesn't already exist
	remove_class(element, class_name);

	if (element.className != "") {
		element.className = element.className + " " + class_name;
	} else {
		element.className = class_name;			
	}
}

function switch_class(element, class_name, new_class_name) {
	/*switches one class for another within the element
		element: element to alter
		class_name: class name to replace
		new_class_name: class name to insert*/
	re = new RegExp(class_name, "i")
	element.className = element.className.replace(re, new_class_name);
}

function remove_class(element, class_name) {
	//removes class_name class from an element with element_id ID
	var new_class_def = "", element;
	
	classArray = element.className.split(" ");

	for (var a = 0; a < classArray.length; a++) {
		if (classArray[a] != class_name)
			new_class_def += classArray[a] + " ";
	}

	new_class_def = new_class_def.trim();
	element.className = new_class_def;
}

function remove_all_classes(element, exception) {
	//removes all classes from an element with element_id ID, except for that matching exception
	var new_class_name = "", element;
	
	classArray = element.className.split(" ");

	for (var a = 0; a < classArray.length; a++) {
		if (classArray[a] == exception) {
			new_class_name += classArray[a] + " ";
		}
	}

	new_class_name = new_class_name.trim();
	element.className = new_class_name;
}

function class_exists(element, class_name) {
	//checks if an html tag has a specific classname applied to it.
	if (element.className.indexOf(" ") != -1) {
		//multiple classnames within one element
		classes = element.className.split(" ");

		for (var a = 0;  a < classes.length; a++) {
			if (classes[a] == class_name)
				return true;
		}
	} else {
		//single classname
		if (element.className == class_name)
			return true;
	}
	
	return false;
}

function element_display(element, display_type) {
	/*changes the display type of an element by using the display: rule
		element: element to alter
		display_type: (mixed) display type to use (e.g. none, inline, block, table-row...)
			if a boolean is specified, "false" is assumed to mean "none" and "true"
			will translate to "block"*/
	if (typeof(element) == "string")
		element = $(element);
	
	//convert true/false to block/none.
	if (display_type === true) {
		display_type = "block";
	} else if (display_type === false) {
		display_type = "none";
	}
	
	if (IS_IE6) {
		//ie6 specific code
		if (typeof(element.style.styleFloat) != "undefined" && display_type == "block") {
			//force floated elements display type to inline when using IE6 (heh)
			element.style.display = "inline";
		} else {
			//use original display type
			element.style.display = display_type;
		}
	} else {
		element.style.display = display_type;
	}
}

function enable_form_elements(container, enabled) {
	//enables or disables form elements within the specified container
	elements = container.getElementsByTagName("INPUT");
	
	for (a = 0; a < elements.length; a++) {
		elements[a].disabled = (!enabled);
	}
	
	elements = container.getElementsByTagName("TEXTAREA");
	
	for (a = 0; a < elements.length; a++) {
		elements[a].disabled = (!enabled);
	}
	
	elements = container.getElementsByTagName("SELECT");
	
	for (a = 0; a < elements.length; a++) {
		elements[a].disabled = (!enabled);
	}
}

function ie6_top_objects(remove) {
	//remove all SELECT elements, because IE 6 is a big fat pile of [deleted]
	if (!IS_IE6) return;	
	
	var elements = document.getElementsByTagName("SELECT");
	var a;
	
	for (a = 0; a < elements.length; a++) {
		if (remove) {
			//remove all objects
			elements[a].style.visibility = "hidden";
		} else {
			//show all objects
			elements[a].style.visibility = "visible";
		
		}
	}
}

function max_size_obj(element) {
	/*changes an element's style to be 100% high and wide. use on absolutely positioned elements.
	the element's CSS should already contain width & height of 100% for this to work*/
	var x, y, left, top;
	
	if (self.innerHeight != null) {
		//fx, safari
		if (document.body.offsetHeight > self.innerHeight) {
			y = self.innerHeight + (document.body.offsetHeight - self.innerHeight);
		} else {
			y = self.innerHeight;
		}
	} else if (document.body.clientHeight != null) {
		//ie
		x = document.body.clientWidth;
		
		if (document.body.offsetHeight > document.documentElement.clientHeight) {
			y = document.documentElement.clientHeight + (document.body.offsetHeight - document.documentElement.clientHeight);
		} else {
			y = document.documentElement.clientHeight;
		}
		element.style.width = x + "px";
	}
		
	element.style.top = "0";
	element.style.left = "0";
	element.style.height = y + "px";
}

function switch_inset(inset_id) {
	/*(de)activates an inset editform container for the purposes of showing/hiding its contents
		inset_id: inset node you want to toggle the visibility of*/
	var inset = $(inset_id);
	var switch_button;
	
	//find inner div and switch button
	for (a = 0; a < inset.childNodes.length; a++) {
		switch (inset.childNodes[a].tagName) {
			case "DIV":
				inner_div = inset.childNodes[a];
				break;
			case "A":
				if (switch_button == null)
					switch_button = inset.childNodes[a];
				break;
		}
	}
	
	if (switch_button == null) {
		alert("Inset div switch button not found. An anchor element must exist as a child node of the outer inset div");
		return false
	}
	
	//lose focus from the switch button because the selection highlight is ugly at this size
	switch_button.blur();
	
	if (inner_div != null) {
		if (inner_div.className == "hidden") {
			inner_div.className = "innerInsetContent";
			switch_class(switch_button, "innerInsetSwitch", "innerInsetSwitchActive");
		} else {
			inner_div.className = "hidden";
			switch_class(switch_button, "innerInsetSwitchActive", "innerInsetSwitch");
		}
	} else {
		alert("switch_inset(): element with id '" + inset_id + "' does not exist!");
	}
	
	return false;
}

function order_row(row_id, x, allow_loop) {
	/*reorders a table row within the DOM
		row_id: id of the row to order
		x: order amount (negative numbers to move up)
		allow_loop: (bool, optional) allow the row to loop back to the top if the order amount 
			is greater than	the capacity of the table's row count*/	
	var element = document.getElementById(row_id);
	var table = element.parentNode;
	var new_index = parseInt(element.rowIndex + x);
	
	if ((new_index < 0 || new_index == table.rows.length) && allow_loop == null)
		//stop looping, if requested
		return false;
	
	//allow for looping of the rows
	if (new_index < 0 ) new_index += table.rows.length;
	if (new_index == table.rows.length ) new_index = 0;
	
	//remove and replace at new index
	table.removeChild(element);
	
	var new_row = table.insertRow(new_index);
	table.replaceChild(element, new_row);
}

function order_element(element, x) {
	/*reorders a sibling of children within a parent element
		element: element to order
		x: order amount (negative numbers to move up)*/
	//get element parent
	var parent = element.parentNode;
	var current_index = 0;
	
	if (class_exists(parent, "dynDomContainer")) {
		//element is a process_xml_standard inserted node and its auto-container 
		//should be referenced instead
		element = element.parentNode;
		parent = parent.parentNode;
	}
	
	if (parent == null)
		//cannot reorder the top level element (what on earth for anyway?)
		return false;
		
	if (parent.childNodes.length == 1)
		//no point in ordering one element!
		return false;
		
	//number of child nodes
	var parent_num = parent.childNodes.length;
		
	//get current index
	for (a = 0; a < parent_num; a++) {
		if (parent.childNodes[a] == element) {
			current_index = a;
			break;
		}
	}
	
	new_index = current_index + parseInt(x);
	
	if (new_index < 0) new_index += parent.childNodes.length;
	if (new_index >= parent.childNodes.length) new_index = 0;
	
	//remove element for replacement
	element = parent.removeChild(element);
	
	//place back at correct index
	if (new_index == (parent_num - 1)) {
		parent.appendChild(element);
	} else {
		for (a = 0; a < parent_num; a++) {
			if (a == new_index) {
				parent.insertBefore(element, parent.childNodes[a]);
				break;
			}
		}
	}
	
	return false;
}

function enter_element_orders(input_collection) {
	/*enter order numbers for distinct elements into a collection of passed
	<input> elements (or any element with a "value" attribute than can be altered)
		input_collection: a single or DOM collection of input element(s)*/
	if (input_collection != null) {
		for (a = 0; a < input_collection.length; a++)
			input_collection[a].value = (a + 1);
	}
}

function breadcrumb(parent_node, breadcrumb) {
	/*creates a breadcrumb list within the parent_node div given an array of links
	breadcrumb should be formed as such:
		[#]
			[label]: link label, or text
			[href]: link href
			[onclick]: onclick event*/
	while (parent_node.firstChild)
		parent_node.removeChild(parent_node.firstChild);
		
	for (a = breadcrumb.length - 1; a >= 0; a--)
		parent_node.appendChild(new this.node(this, breadcrumb[a], a, breadcrumb.length));
}

breadcrumb.prototype.node = function(parent_obj, link, num, total) {
	//create a node link	
	this.node = document.createElement("a");
	this.node.className = "crumb";
	this.node.id = "nodeLink" + num;
	this.node.href = link['href'];
	
	if (num < (total - 1)) {
		//all but the first node
		img_path = PATH_ROOT + "/templates/admin/images/rte_tools/node_chevron_int.gif";
	} else {
		//the first node looks different
		img_path = PATH_ROOT + "/templates/admin/images/rte_tools/node_chevron.gif";
	}
	
	if (num == 0) {
		//last node gets a right border
		this.node.style.borderRight = "1px solid #999";
	}
	
	this.node.style.background = "url('" + img_path + "') no-repeat left top";
	
	//create internal span for text and background image
	this.node_label = document.createElement("span");
	
	var label_text = link['label'].replace(/\s/g, "&nbsp;");
	this.node_label.innerHTML += label_text;
	
	if (link['label'].length < 2) {
		this.node_label.style.paddingRight = "6px";
	}
	
	this.node.appendChild(this.node_label);
		
	if (IS_IE6) {
		//ahh, the ever wonderous ie6 decides that float = 100% wide!
		this.node.style.width = this.node_label.offsetWidth;
	}
	
	if (link['onclick'] != null)
		//attach_event(this.node, "click", link['onclick']);
		attach_event(this.node_label, "click", obj_event(parent_obj, "nodeclick", link['onclick'], true));
	
	attach_event(this.node_label, "mouseover", obj_event(parent_obj, "nodeover", null, true));
	attach_event(this.node_label, "mouseout", obj_event(parent_obj, "nodeout", null, true));
	
	return this.node;
}

breadcrumb.prototype.nodeover = function(e, event_obj, args) {
	source = get_source(e);
	source.style.backgroundPosition = "12px bottom";
	source.parentNode.style.backgroundPosition = "left bottom";
	
	//hover next node
	if (source.parentNode.nextSibling) {
		source.parentNode.nextSibling.style.backgroundPosition = "left 50%";
	}
}


breadcrumb.prototype.nodeout = function(e, event_obj, args) {
	source = get_source(e);
	source.style.backgroundPosition = "12px top";
	source.parentNode.style.backgroundPosition = "left top";
	
	//unhover next node
	if (source.parentNode.nextSibling) {
		source.parentNode.nextSibling.style.backgroundPosition = "left top";
	}
}

breadcrumb.prototype.nodeclick = function(e, event_obj, callback) {
	callback();
}

/*
Tab-able textarea elements
*/

function textarea_tab(e, element) {
	var tab = 9;
	var tab_str = String.fromCharCode(tab);
	
	e = e || window.event();
	
	if (e.ctrlKey || e.shiftKey)
		return false;
		
	scroll_pos = element.scrollTop;

	if (e.keyCode == tab && get_source(e) == element) {
		/*if (document.selection) {
			//ie
			if (document.selection.type != "Control") {
				element.selection = document.selection.createRange();
				element.selection.text = tab_str;
			}
		
			e.returnValue = false;
		} else if (window.getSelection) {
			//firefox, safari
			var start = element.selectionStart;
			var end = element.selectionEnd;
			
			element.value = element.value.substring(0, start) +  
				tab_str +
				element.value.substring(end, element.value.length);
			
			element.focus();
			element.selectionStart = start+1;
			element.selectionEnd = start+1;
		
			e.preventDefault();
		}*/
		
		textarea_insert_at_selection(element, tab_str)
		
		element.scrollTop = scroll_pos;
	
		try {
			e.preventDefault();
		} catch(err) {
			e.returnValue = false;
		}
	
		return false;
	}
}

function textarea_insert_at_selection(element, text, cursor_after) {
	/*inserts into a textarea the specified text at the current cursor position*/
	if (document.selection) {
		//ie
		element.focus();
		
		if (document.selection.type != "Control") {
			element.selection = document.selection.createRange();
			element.selection.text = text;
		}
	} else if (window.getSelection) {
		//firefox, safari
		var start = element.selectionStart;
		var end = element.selectionEnd;
		
		element.value = element.value.substring(0, start) +  
			text +
			element.value.substring(end, element.value.length);
		
		element.focus();
		
		if (cursor_after == true) {
			element.selectionStart = start + text.length;
			element.selectionEnd = start + text.length;
		} else {
			element.selectionStart = start+1;
			element.selectionEnd = start+1;
		}
	}
}

/*
<select> element manipulation
*/

function add_select_value(select, text, value, collision_action, select_after) {
	/*adds an <option> to a <select>, optionally checking for duplicates
		select: element you're adding the option nodes to
		text: text to display on the added node
		value: value of the node
		collision_action: an integer representing what to do when an existing 
			option is detected with identical attributes. the possible values are:
				null|false: do nothing - allow multiples
				1|true: enforce unique option values
				2: enforce unique labels
				3: enforce unique combined option values and labels
		select_after: select the added option after creation*/
    var option = new Option(text, value, true, true);
    var length = select.length;
	var a;
	
	//if the element is only 1 high, unselect everything else
	if (!select.height) {
		for (var i = 0; i < select.options.length; i++) {
			select.options[i].selected = false;
		}
	}
	
	if (collision_action !== false && collision_action !== null) {
		//detect multiples
		collision_num = parseInt(collision_action);
		found_existing = false;
		
		for (a = 0; a < select.length; a++) {
			if (collision_num == 1 || collision_action === true) {
				//enforce unique values
				if (select.options[a].value == value) {
					found_existing = true;
					break;
				}
			} else if (collision_num == 2) {
				//enforce unique labels
				if (select.options[a].text == text) {
					found_existing = true;
					break;
				}			
			} else if (collision_num == 3) {
				//enforce unique combined values & labels
				if (select.options[a].value == value && select.options[a].text == text) {
					found_existing = true;
					break;
				}
			}
		}
		
		if (found_existing) {
			if (select_after == true)
				select.options[a].selected = true;
			return false;
		}
	}
	
   	select.options[length] = option;
	
	if (select_after == true) {
		select.options[length].selected = true;
	} else {
		select.options[length].selected = false;
	}
	
	//delete the pre-set options
	for (var i = 0; i < select.options.length; i++) {
		if (select.options[i].value == "REMOVE_ON_UPDATE") {
			select.options[i] = null;
		}
	}
}

function remove_select_value(select, value) {
	/*removes an option from the specified <select> tag
		select: select element to scan
		value: value to remove*/
	var sel = select.selectedIndex;

	for (var a = (select.options.length - 1); a >= 0; a--) {
		if (select.options[a].value == value) {
			select.options[a] = null;
		}
	}
	
	//select element after it (if something was selected)
	if (sel != null && sel != -1) {
		if (sel < select.options.length) {
			select.selectedIndex = sel;
		} else {
			select.selectedIndex = (select.options.length - 1);
		}
	}
}

function remove_select_index(select, index) {
	/*removes the specified option from the specified <select> tag
		select: select element to scan
		index: zero-based option index to remove*/
	var sel = select.selectedIndex;

	select.options[index] = null;	
	
	//select element after it (if something was selected)
	if (sel != null && sel != -1) {
		if (sel < select.options.length) {
			select.selectedIndex = sel;
		} else {
			select.selectedIndex = (select.options.length - 1);
		}
	}
}

function wipe_select(select_element) {
	//removes all the <option>s from a <select> element
	select_element.length = 0;
}

function select_all_select(select_element) {
	//selects every element within a multiple choice selector
	for (var a = 0; a < select_element.options.length; a++)
		select_element.options[a].selected = true;
}

function select_val(select, value, add_text) {
	/*selects an <option> within a <select> matching the value sent
		select: <select> object
		value: <option> value to look for
		add_text: add an option (<option value="value">add_text</option>) if not found*/
	for (var a = 0; a < select.length; a++) {
		if (select.options[a].value == value) {
			select.selectedIndex = a;
			return true;
		}
	}
	
	//if the function gets here the item doesn't exist - so add it!
	if (add_text != null) {
		add_select_value(select, add_text, value);
		select_val(select, value);
	}
}

function get_select_val(select) {
	if (typeof(select) == "string")
		select = $(select);
	
	return select.options[select.selectedIndex].value;
}

/*
Radio element manipulation
*/

function radio_val(radio, value) {
	for (a = 0; a < radio.length; a++) {
		if (radio[a].value == value) {
			radio[a].checked = true;
		} else {
			radio[a].checked = false;
		}
	}
}

/*
Checkbox element manipulation
*/

function checkbox_val(checkbox, value) {
	if (checkbox.value == value) {
		checkbox.checked = true;
	} else {
		checkbox.checked = false;
	}
}