// JavaScripts used throughout the site...


/* ----------------------------------------------------------------------
addEvent
Adds functions to the window.onload function.

Based on these pages:
http://simonwillison.net/2004/May/26/addLoadEvent/
http://www.dustindiaz.com/top-ten-javascript
http://www.dustindiaz.com/rock-solid-addevent/
*/
function addEvent( obj, type, fn ) {
	type = type.replace(/^on/, '');
	if (obj.addEventListener) {
		obj.addEventListener( type, fn, false );
		EventCache.add(obj, type, fn);
	}
	else if (obj.attachEvent) {
		obj["e"+type+fn] = fn;
		obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
		obj.attachEvent( "on"+type, obj[type+fn] );
		EventCache.add(obj, type, fn);
	}
	else {
		obj["on"+type] = obj["e"+type+fn];
	}
}

var EventCache = function(){
	var listEvents = [];
	return {
		listEvents : listEvents,
		add : function(node, sEventName, fHandler){
			listEvents.push(arguments);
		},
		flush : function(){
			var i, item;
			for(i = listEvents.length - 1; i >= 0; i = i - 1){
				item = listEvents[i];
				if(item[0].removeEventListener){
					item[0].removeEventListener(item[1], item[2], item[3]);
				};
				if(item[1].substring(0, 2) != "on"){
					item[1] = "on" + item[1];
				};
				if(item[0].detachEvent){
					item[0].detachEvent(item[1], item[2]);
				};
				item[0][item[1]] = null;
			};
		}
	};
}();
addEvent(window,'unload',EventCache.flush);


function addLoadEvent(func) {
	addEvent(window, 'onload', func);
}

/* ----------------------------------------------------------------------
toggle
show or hide an item
*/
function toggle(obj, force) {
	var el = document.getElementById(obj);
	if(el) {
		if(typeof(force) == 'string') {
			el.style.display = force;
		} 
		else if ( el.style.display != 'none' ) {
			el.style.display = 'none';
		}
		else {
			el.style.display = '';
		}
	}
}

function $() {
	var elements = new Array();
	for (var i = 0; i < arguments.length; i++) {
		var element = arguments[i];
		if (typeof element == 'string')
			element = document.getElementById(element);
		if (arguments.length == 1)
			return element;
		elements.push(element);
	}
	return elements;
}



/* ----------------------------------------------------------------------
FormFocus
This function places the focus on a form field when a page loads
if it finds a field designated "inputFocusTarget"

Call using this code:
<body onload="FormFocus()"...
<input type="text" name="WHATEVER" id="inputFocusTarget"/>
*/
function FormFocus() {
	if(document) {
		if(document.getElementById) {
			if(document.getElementById("inputFocusTarget")) {
				document.getElementById("inputFocusTarget").focus();
			}
		}
	}
}

/* ----------------------------------------------------------------------
StartList
This function adds onmouseover functions to the dropdown menu for
compatibility with internet explorer.
*/
StartList = function() { 
	if (document.all&&document.getElementById) {
		// Get the first child node - the UL containing our menu items
		navRoot = document.getElementById("nav"); //.childNodes[0];
		for (i=0; i<navRoot.childNodes.length; i++) {
			node = navRoot.childNodes[i];
			if (node.nodeName=="LI") {
				node.onmouseover=function() {
					// Make the menu appear
					this.className+=" over";
					// Take the focus off the inputFocusTarget
					if(document.getElementById("inputFocusTarget")) {
						document.getElementById("inputFocusTarget").blur();
					}
					// Hide any dropdown menus
					FlipFormVisibility(0);
				
				}
				node.onmouseout=function() {
					// Make the menu disappear
					this.className=this.className.replace(" over", "");
					// Unhide any dropdown menus
					FlipFormVisibility(1);

				}
			}
		}
	}
}

/* ----------------------------------------------------------------------
FlipFormVisibility
This function hides and unhides SELECT form items so that the menu will 
appear properly.  We store the form fields in an array so we don't have 
to scan the whole file every time the function is called.
*/
var FormFields = null;
var LastVisibilitySwitch = 1;

function FlipFormVisibility(visible) {

	// Return if we are not changing from the previous state
	if(LastVisibilitySwitch == visible) { return; }
	else { LastVisibilitySwitch = visible; }
	
	// If we haven't gotten the form fields yet do so.
	if(FormFields == null) {
		FormFields = new Array();
		
		if(document.forms) {
			// Get all the form objects into an array.
			Item = new Array();
			for(i=0; i < document.forms.length; i++) {
				Item.push(document.forms[i]);
			}
			// Find all the childNodes of the form objects.
			for(i=0; i < Item.length; i++) {
				for(j=0; j < Item[i].childNodes.length; j++) {
					Item.push(Item[i].childNodes[j]);
				}
				// If the childNode is a SELECT field, store it.
				if(Item[i].nodeName == 'SELECT') {
					FormFields.push(Item[i]);
				}	
			}
		}	
	}
	
	// Flip all the form fields
	for(i=0; i < FormFields.length; i++) {
		FormFields[i].style.visibility = (visible ? 'visible' : 'hidden');
	}
	

}

/* ----------------------------------------------------------------------
Tree
This function adds styles to the unordered list <ul id="tree"> to make
it look more like a tree.  Only needed for ie as mozilla handles this
with styles.
*/
function Tree() {
	if(document.all && document.getElementById("tree")) {
		var Item = new Array(document.getElementById("tree"));
		
		for(var i=0; i < Item.length; i++) {
			if(Item[i].lastChild.nodeName == 'LI') 
				Item[i].lastChild.className = "last";
			
			for(j=0; j < Item[i].childNodes.length; j++) {
				if(Item[i].childNodes[j].nodeName == 'LI' || 
					Item[i].childNodes[j].nodeName == 'UL')
					Item.push(Item[i].childNodes[j]);
			}
		}
	}
}

/* ----------------------------------------------------------------------
HighlightChanges
This function adds styles and functions to every form on the page, so
that when the user makes changes to the information the field that
was changed is highlighted.  When they submit to the same page, 
the fields will return to their original color.

Useful on our editing pages where the form submits and displays
the information for editing again immediately, so that it is not
clear whether the information has been saved or not.
*/
function HighlightChanges() {
	
	var SetStyle = function(obj) {
		obj.style.background = '#ffffff';
		obj.style.border = '1px solid #999999';
		obj.style.padding = '2px';
	}
	
	var Highlight = function() { this.style.background = '#ffff99'; }
	
	var Item = document.getElementsByTagName('input');
	for(i=0; i<Item.length; i++) {
		if(Item[i].type == 'text') {
			SetStyle(Item[i]);
			addEvent(Item[i], 'onkeyup', Highlight);
			addEvent(Item[i], 'onchange', Highlight);
		}
		if(Item[i].type == 'submit') {
			addEvent(Item[i], 'onclick', function() { this.value += ' . . .'; });
		}
	}
	
	var Item = document.getElementsByTagName('textarea');
	for(i=0; i<Item.length; i++) {
		SetStyle(Item[i]);
		addEvent(Item[i], 'onkeyup', Highlight);
		addEvent(Item[i], 'onchange', Highlight);
	}
	
	var Item = document.getElementsByTagName('select');
	for(i=0; i<Item.length; i++) {
		SetStyle(Item[i]);
		addEvent(Item[i], 'onchange', Highlight);
	}

}


/* ----------------------------------------------------------------------


marked for deletion


ReScroll
This function keeps a textarea in your form scrolled to the same place
even after submitting the form.  Useful for the Memex where you are 
saving often and don't want to have to scroll back to where you were
after every save.

Use the following code to call this function:
<body onload="ReScroll()"...>
<textarea name="WHATEVER"></textarea>
<input type="hidden" name="WHATEVER_scrolltop" id="WHATEVER_scrolltop"
	value="<?php echo $_POST["WHATEVER_scrolltop"]; ?>"/>
	
The function must be called onload to work properly in Mozilla.
*/
function ReScroll() {
	if(document.forms) {
		// Get all the form objects into an array.
		Item = new Array();
		for(i=0; i < document.forms.length; i++) {
			Item.push(document.forms[i]);
		}
		// Find all the childNodes of the form objects.
		for(i=0; i < Item.length; i++) {
			for(j=0; j < Item[i].childNodes.length; j++) {
				Item.push(Item[i].childNodes[j]);
			}
			
			// Add re-scrolling functions to TEXTAREAs.
			if(Item[i].nodeName == 'TEXTAREA') {
				// Figure out how the rescroller field would be named.
				rescroller = Item[i].name + "_scrolltop";
				// If the rescroller field exists...
				if(document.getElementById(rescroller)) {
					// Set the scrolltop back to the rescroller value
					if(document.getElementById(rescroller).value > 0) {
						Item[i].scrollTop = document.getElementById(rescroller).value;
					}
					// When the scrolltop value changes add it to the field.
					// Mozilla doesn't support onscroll, use onblur instead
					Item[i].onblur=function() {
						document.getElementById(rescroller).value = this.scrollTop;
					}
				}
			}
		}
	}
}


/* ----------------------------------------------------------------------
ActivateSearchForm
This function shows or hides the search form in the page banner.

<a href="http://library.williams.edu/search/" 
	onclick="return ActivateSearchForm()">SEARCH</a>
	
<form style="visibility:hidden" id="searchForm" method="get" action="http://library.williams.edu/search/">
	Search this site:<br/>
	<input id="searchField" type="text" name="s" size="14" maxlength="255"/>
	</form>
*/
function ActivateSearchForm() {
	// If the form exists...
	if(document && document.getElementById && document.getElementById("searchForm")) {
		
		// If the form field is visible
		if(document.getElementById("searchForm").style.visibility == "visible") {
					
			// If there is text in the form field, submit the form.
			if(document.getElementById("searchField") && 
				document.getElementById("searchField").value != "") {
				
				document.getElementById("searchForm").submit();
				return false;
			}
					
			// Otherwise, hide the form.
			document.getElementById("searchForm").style.visibility = "hidden";
			if(document.getElementById("headerSplash"))
				document.getElementById("headerSplash").style.visibility = "visible";
			return false;
			
		} 
		// If the form field is hidden
		else {
			if(document.getElementById("headerSplash"))
					document.getElementById("headerSplash").style.visibility = "hidden";
				// Make the form visible.
			document.getElementById("searchForm").style.visibility = "visible";
			// Put the focus on the form field.
			if(document.getElementById("searchField")) {
				document.getElementById("searchField").focus();
			}
			return false;				
		}
	}
	// If the script couldn't find the form, return true and allow the user
	// to proceed to the search page.
	return true;
}

/* ----------------------------------------------------------------------
BounceTo


mark for deletion


This function takes a link and sends it through a redirect page
in order to track the traffic on the site.

Here is a properly formatted link:

<a href="/staff/" onclick="BounceTo(this)">Staff</a>

In this case, the visit to /staff/ would be logged 
and the user would be directed to the staff page seamlessly.
*/
function BounceTo(thisLink) {
	if(thisLink) {
		if(thisLink.href) {
			if(thisLink.href.indexOf('bounce.php') < 0) {
				thisLink.href = 
					'http://library.williams.edu/bounce.php?uri=' + thisLink.href;
			}
		}
	}
	return true;
}

// Cookie Functions  ////////////////////  (:)

// Set the cookie.
// SetCookie('your_cookie_name', 'your_cookie_value', exp);

// Get the cookie.
// var someVariable = GetCookie('your_cookie_name');

var expDays = 30;
var exp = new Date(); 
exp.setTime(exp.getTime() + (expDays*24*60*60*1000));
//exp.setTime(exp.getTime() + (3*60*1000));

function getCookieVal (offset) {  
	var endstr = document.cookie.indexOf (";", offset);  
	if (endstr == -1) { endstr = document.cookie.length; }
	return unescape(document.cookie.substring(offset, endstr));
}

function GetCookie (name) {  
	var arg = name + "=";  
	var alen = arg.length;  
	var clen = document.cookie.length;  
	var i = 0;  
	while (i < clen) {    
		var j = i + alen;    
		if (document.cookie.substring(i, j) == arg) return getCookieVal (j);    
		i = document.cookie.indexOf(" ", i) + 1;    
		if (i == 0) break;   
	}  
	return null;
}

function SetCookie (name, value) {  
	var argv = SetCookie.arguments;  
	var argc = SetCookie.arguments.length;  
	var expires = (argc > 2) ? argv[2] : null;  
	var path = (argc > 3) ? argv[3] : null;  
	var domain = (argc > 4) ? argv[4] : null;  
	var secure = (argc > 5) ? argv[5] : false;  
	document.cookie = name + "=" + escape (value) + 
	((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + 
	((path == null) ? "" : ("; path=" + path)) +  
	((domain == null) ? "" : ("; domain=" + domain)) +    
	((secure == true) ? "; secure" : "");
}

function DeleteCookie (name) {  
	var exp = new Date();  
	exp.setTime (exp.getTime() - 1);  
	var cval = GetCookie (name);  
	document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();
}


/* ----------------------------------------------------------------------

marked for deletion


DisplayCampusLinks
This function hides the campus links on the home page if the user's
window is set to a small enough size that they would need to scroll.
It keeps the campus links from interfering with our content.

This runs both onload and onresize.
*/

function DisplayCampusLinks() {
	
	// If the campus link layer cannot be found return.
	if(!document.getElementById("campusLinks")) {
		return;
	}
	
	// Figure out the height of the visible window.
	if(document.documentElement && document.documentElement.clientHeight) {
		windowHeight = document.documentElement.clientHeight; // IE 6
	} else if(window && window.innerHeight) {
		windowHeight = window.innerHeight; // Mozilla, Netscape
	} else {
		windowHeight = 0;
	}
	
	// Figure out the height of the content
	if(document.body && document.body.scrollHeight) {
		contentHeight = document.body.scrollHeight;
	} else {
		contentHeight = 0;
	}
	
	// If we figured both out, determine where to show campus links.
	if(contentHeight > 0 && windowHeight > 0 && windowHeight >= contentHeight) {
		//document.getElementById("campusLinks").style.visibility = "visible";
		document.getElementById("campusLinks").className = "campusCorner";
	} else {
		//document.getElementById("campusLinks").style.visibility = "hidden";	
		document.getElementById("campusLinks").className = "campusBottom";	
	}
}


/* ----------------------------------------------------------------------

marked for deletion


KeepSessionAlive
This function rotates an image on the page to keep the session alive.
Requires the following code in the page:
<img src="/admin/hourglass.php" width="13" height="22" id="ksa"/>
*/

function KeepSessionAlive() {
	if(document.getElementById("ksa")) {
		var now = new Date();
		document.getElementById("ksa").src = '/admin/hourglass.php?'+now.getTime();
		setTimeout("KeepSessionAlive()", 10*1000);
	}
	
}

/*
Ajax()
Uses XML formed like this:
<response>
	<method>
		<function>1ST JAVASCRIPT FUNCTION TO CALL</function>
		<parameter>FIRST PARAMETER</parameter>
		<parameter>ETC...</parameter>
	</method>
	<method>
		<function>NTH FUNCTION TO CALL</function>
		<parameter>FIRST PARAMETER</parameter>
		<parameter>SECOND PARAMETER</parameter>
		<parameter>ETC...</parameter>
	</method>
</response>

Based on documentation from this excellent tutorial:
http://www.xml.com/pub/a/2005/02/09/xml-http-request.html
*/
var req;
function Ajax(url) {
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
        req = new XMLHttpRequest();
        req.onreadystatechange = AjaxProcessor;
        req.open("GET", url, true);
        req.send(null);
    // branch for IE/Windows ActiveX version
    } else if (window.ActiveXObject) {
        req = new ActiveXObject("Microsoft.XMLHTTP");
        if (req) {
            req.onreadystatechange = AjaxProcessor;
            req.open("GET", url, true);
            req.send();
        }
    }
}
/*
Processes the XML when the request is returned.  Works with Ajax();
*/
function AjaxProcessor() {
    
	if (req.readyState == 4) { // only if req shows "complete"
		
		if (req.status == 200) { // only if "OK"
				
			response = req.responseXML.documentElement;
			
			if(response == null) {
				AjaxError("The XML response was not well formed.");
			} else {
			
				if(response.getElementsByTagName('method')[0] == null) {
					AjaxError("No method call defined.");
				} else {
				
					// Get the method to call from the XML returned
					method = response.getElementsByTagName('method'); //[0].firstChild.data;
					
					for(var j=0; j<method.length; j++) {
						
						// Get the function name
						functionName = method[j].getElementsByTagName('function')[0].firstChild.data
						
						// Get the parameters to call from the XML.
						params = method[j].getElementsByTagName('parameter');
						
						// Build a parameters list from the params.
						pList = '';			
						for(i=0; i < params.length; i++) {
							pList += (pList == '' ? '' : ', ') +
								(params[i].firstChild != null ? 
									'params['+i+'].firstChild.data' : 
									'\'\'');
						}
						
						// Execute the method with the given parameters.
						eval(functionName + '('+pList+')');
					
					} // end each method
				} // end if method defined
			} // end if well formed
		} // end if ok
	} // end if complete
}

function AjaxError(errorMsg) {
	if(errorMsg != null) { alert(errorMsg); }
}
function AjaxSilent() { }


/*


marked for deletion



Used to fade out and in items on the home page to draw attention to them.
*/
var fadeItem = 1;
var fadeDegree = 0;
var fadeInterval = 6;
function FadeIn() {
	if(document.getElementById("fader"+fadeItem)) {
	
		var opacity = Math.abs(Math.round(Math.cos(fadeDegree*Math.PI/180)*100)/100);
		
		document.getElementById("fader"+fadeItem).style.opacity = opacity;
		document.getElementById("fader"+fadeItem).style.filter = 'alpha(opacity=' + opacity*100 + ')';
		fadeDegree = fadeDegree * 1 + fadeInterval;
		if(fadeDegree > 180) {
			fadeDegree = 0;
			fadeItem += 1;
		}
		delay = (fadeDegree == 90 + fadeInterval) ? 200 : 0;
		setTimeout('FadeIn()', delay);
	} 
	//else { fadeItem = 1; setTimeout('FadeIn()', delay); }
}

/* Functions for installing Firefox plugins */
function InstallFirefoxPlugin(pluginTitle, fileName){
   var xpi = new Object();
   xpi[pluginTitle] = "http://library.williams.edu/assets/plugins/" + fileName;
   if(typeof(InstallTrigger) != 'undefined') {
	   InstallTrigger.install(xpi);
   } else {
	   alert('Sorry, this plugin is only available for Firefox.');
   }
}

/* Functions for dealing with class name */
function SetClassName(mid, cn) {
	if(document.getElementById(mid))
		document.getElementById(mid).className = cn;
}

/* 
getElementsByClassName
*/
if(typeof(document.getElementsByClassName) == "undefined") {
	document.getElementsByClassName = function(cl) {
		var retnode = [];
		var myclass = new RegExp('\\b'+cl+'\\b');
		var elem = this.getElementsByTagName('*');
		for (var i = 0; i < elem.length; i++) {
			var classes = elem[i].className;
			if (myclass.test(classes)) retnode.push(elem[i]);
		}
		return retnode;
	}; 
}


/* Encode variables for use in URLs */
function UrlEncode(url) {
	return escape(url.replace(/\s/g, '+'));
}


/* Get relative coordinates of an image within the page */
function getCoord(obj) {
	var curleft = curtop = curwidth = curheight = winwidth = winheight = 0;

	// Find the dimensions of the element
	if(obj.offsetWidth) { curwidth = obj.offsetWidth; }
	if(obj.offsetHeight) { curheight = obj.offsetHeight; }

	// Find the position of the element
	if (obj.offsetParent) {
		do {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	
	// Figure out the width and height of the visible window.
	if(document.documentElement && document.documentElement.clientWidth) {
		winwidth = document.documentElement.clientWidth; // IE 6
		winheight = document.documentElement.clientHeight; // IE 6
	} else if(window && window.innerWidth) {
		winwidth = window.innerWidth; // Mozilla, Netscape
		winheight = window.innerHeight; // Mozilla, Netscape
	} else {
		winwidth = 0;
		winheight = 0;
	}
	
	return [curleft,curtop,curwidth,curheight,winwidth,winheight];
}