/*
* HemsleyFraser website JavaScript
* (C) Optimalworks.net, http://www.optimalworks.net/
*/

// startup event
function Main(e) {

	SearchHandler();
	CourseScrollHandler();
	CourseTableHandler();
    ResultsTableHandler();
    InitialiseExternalLinks();


	// are images enabled?
	var img = $t("img", "header");
	if (img.length > 0) {
		img = img[0];
		var fImage = new Image;
		fImage.src = img.getAttribute("src");
		if (fImage.complete) ImageFunctions(fImage);
		else new Event(fImage, "load", function(e) { ImageFunctions(fImage); });
	}
}

// functions that require images to be enabled
function ImageFunctions(fImage) {
	if (fImage.width > 0) {
		CustomTickHandler();
	}
}

// ############################################################################
// search form handler
function SearchHandler() {
	var search = $("search");
	if (search) {
		var sform = search, sfName;
		do
		{
			sform = sform.parentNode;
			sfName = sform.nodeName.toLowerCase();
		} while (sform && sfName != "form" && sfName != "body")
		var ieRefresh = function() { Graphic.ClassApply(search, "focus"); Graphic.ClassRemove(search, "focus"); }; // stop IE shunting
		ieRefresh();
		new Event(window, "resize", ieRefresh);
		if (sfName == "form") new Event (sform, "submit", function() { if (search.value == search.defaultValue) search.value = ""; });
		new Event(search, "focus", function() { Graphic.ClassApply(search, "focus"); if (search.value == search.defaultValue) search.value=""; });
		new Event(search, "blur", function() { Graphic.ClassRemove(search, "focus"); if (search.value == "") search.value = search.defaultValue; });
	}
}

function SearchSubmitHandler()
{
    var searchField = document.getElementById("search");
    if( searchField ){
        document.location = "/OpenCourses/Search/Results?start=Y&searchPhrase=" + escape(searchField.value);   
    }
    return false;
}

function SearchBoxKeyPressHandler(e){
    if( !e) e = window.event;
    if( e.keyCode == 13 ){
        SearchSubmitHandler();
        return false;
    }
    return true;
}

// ############################################################################
// Initialises external links with Javascript to allow XHTML strict compliance
function InitialiseExternalLinks() {
    if (!document.getElementsByTagName) return;
    
    var anchors = document.getElementsByTagName("a");
    for (var i=0; i<anchors .length; i++) {
        var anchor = anchors[i];
        if (anchor.getAttribute("href") && anchor.getAttribute("rel") == "external") {
            anchor.target = "_blank";
            anchor.title = (anchor.title != "") ? anchor.title+" (opens in a new window)" : "opens in a new window";
            anchor.className = (anchor.className != '') ? anchor.className+' external' : 'external';
        }
    }
}

// ############################################################################
// course scroll handler
function CourseScrollHandler() {
	var courses =  $class("course", "div", "content");
	for (var c = 0; c < courses.length; c++) DefineCourse(courses[c]);
}

// course class
function DefineCourse(coursediv) {

	var i, p, href, cItem;
	var links = [];
	var info = $class("info", "div", coursediv);
	if (info.length == 1) links = $t("a", info[0]);

	// find course links
	for (i=0; i < links.length; i++) {
		href = links[i].getAttribute("href");
		p = href.lastIndexOf("#");
		if (p >= 0) href = href.substr(p+1)
		cItem = $(href);
		if (href != "" && cItem) {
			links[i].cItem = cItem;
			new Event(links[i], "click", CourseLinkClick);
		}
	}

}

// course link clicked
function CourseLinkClick(evt) {
	evt.Raised.StopDefaultAction();
	evt.Raised.StopPropagation();
	evt.Raised.Element.blur();
	if (evt.Raised.Element.cItem) CourseScroll(evt.Raised.Element.cItem);
}


// course scroller
var ActiveParent, ActiveContent, ActiveStep;
var AnimationSteps = 25;
var AnimationDelay = 25;
function CourseScroll(cItem) {
	if (typeof cItem === "object") {
		ActiveContent = cItem;
		ActiveParent = cItem.parentNode;
		ActiveStep = AnimationSteps;
	}
	var sF = ActiveParent.scrollTop;
	var sT = ActiveContent.offsetTop;
	if (sF != sT) {
		ActiveParent.scrollTop = sF + Math.ceil((sT - sF) / Math.sqrt(ActiveStep));
		ActiveStep--;
		if (ActiveStep > 0) setTimeout(CourseScroll, AnimationDelay);
	}

}


// ############################################################################
// course table handler
function CourseTableHandler() {
	var dates = $class("dates", "table", "content");
	for (var d = 0; d < dates.length; d++) {
		new Event(dates[d], "mouseover", CourseTableHover);
		new Event(dates[d], "mouseout", CourseTableHover);
	}
}

// hover course table
function CourseTableHover(evt) {
	evt.Raised.StopPropagation();
	var tr = evt.Raised.Element;
	while (tr.nodeName.toLowerCase() != "tr" && tr.parentNode) tr = tr.parentNode;
	if (tr.nodeName.toLowerCase() == "tr") {
		if (evt.Raised.Type == "mouseover") Graphic.ClassApply(tr, "hover");
		else Graphic.ClassRemove(tr, "hover");
	}

}

// ############################################################################
// results table handler
function ResultsTableHandler() {
	var dates = $class("results", "table", "content");
	for (var d = 0; d < dates.length; d++) {
		new Event(dates[d], "mouseover", ResultsTableHover);
		new Event(dates[d], "mouseout", ResultsTableHover);
	}
}

// hover results table
function ResultsTableHover(evt) {
	evt.Raised.StopPropagation();
	var tr = evt.Raised.Element;
	while (tr.nodeName.toLowerCase() != "tr" && tr.parentNode) tr = tr.parentNode;
	if (tr.nodeName.toLowerCase() == "tr") {
		if (evt.Raised.Type == "mouseover") Graphic.ClassApply(tr, "hover");
		else Graphic.ClassRemove(tr, "hover");
	}

}

// ############################################################################
// custom tickbox handler
function CustomTickHandler() {

	var tbf, f, tb, t, tl, l, label;

	// find all forms
	tbf = $class("form", "div", "content");
	for (f = 0; f < tbf.length; f++) {

		// find input nodes
		tb = $t("input", tbf[f])
		for (t = 0; t < tb.length; t++) {

			// find checkboxes
			if (tb[t].getAttribute("type") == "checkbox") {
				Graphic.ClassApply(tb[t], "customtick");

				// append custom tickbox
				var ct = document.createElement("div");
				ct.className = "customtick";

				var ctNode = tb[t].parentNode.insertBefore(ct, tb[t]);
				ctNode.tickbox = tb[t];
				tb[t].custombox = ctNode;
				if (tb[t].checked) Graphic.ClassApply(ctNode, "on");

				// find label (required for correct IE functionality)
				label = null;
				if (tb[t].id) {
					tl = $t("label", tb[t].parentNode);
					l = 0;
					do {
						if (tl[l].htmlFor == tb[t].id) label = tl[l];
						l++;
					} while (!label && l < tl.length);
				}

				// add events
				new Event(tb[t], "change", TickClicked);
				new Event(ctNode, "click", TickClicked);
				if (label) {
					label.tickbox = tb[t];
					new Event(label, "click", TickClicked);
				}
			}

		}
	}

}

// change custom tickbox
function TickClicked(evt) {

	evt.Raised.StopDefaultAction();
	evt.Raised.StopPropagation();

	var tb = evt.Raised.Element;
	if (evt.Raised.Type == "click") {
		tb = tb.tickbox;
		tb.checked = !tb.checked;
	}

	if (tb.checked) Graphic.ClassApply(tb.custombox, "on");
	else Graphic.ClassRemove(tb.custombox, "on");
}


// ############################################################################
// string trimming
String.prototype.Trim = function() { return this.replace(/^\s*|\s*$/g, ""); }

// array stack push (if unsupported)
if (!Array.prototype.push) { Array.prototype.push = function(element) { this[this.length] = element; } }

// getElementById
function $(id) { return (document.getElementById ? document.getElementById(id) : null); }

// getElementsByTagName
function $t(tag, root) {
	if (typeof root == 'string') root = $(root);
	if (!root) root = document;
	return (document.getElementsByTagName ? root.getElementsByTagName(tag) : null);
}

// getElementsByClassName
function $class(className, tag, rootElement) {
	className = " "+className.Trim()+" ";
	var thisClass;
	var classNodes = new Array();
	var allNodes = (typeof tag == 'string' && tag.length > 0 ? $t(tag, rootElement) : $all(rootElement));
	for (var i = 0; i < allNodes.length; i++) {
		thisClass = " "+allNodes[i].className+" ";
		if (thisClass.indexOf(className) >= 0) classNodes.push(allNodes[i]);
	}
	return classNodes;
}

// returns all tags
function $all(rootElement) {
	var nl = new Array(0);
	var RecurseElements = function(element) {
		var cnodes = $c(element);
		for (var i =0; i< cnodes.length; i++) {
			nl.push(cnodes[i]);
			RecurseElements(cnodes[i]);
		}
	}
	if (typeof rootElement == 'string') rootElement = $(rootElement);
	if (!rootElement) rootElement = document;
	RecurseElements(rootElement);
	return nl;
}

// get child elements (ignoring whitespace and comments)
function $c(element) {
	var ce = [];
	if (typeof element == 'string') element = $(element);
	if (element) {
		for (var i=0; i<element.childNodes.length; i++) {
			if (element.childNodes[i].nodeType == 1 && element.childNodes[i].nodeName != "!") ce.push(element.childNodes[i]);
		}
	}
	return ce;
}

// graphic routines
var Graphic = new function() {
	// apply class
	this.ClassApply = function(element, cname) {
		if (typeof element == 'string') element = $(element);
		if (element && cname.length > 0) {
			var cc = " "+element.className+" ";
			if (cc.indexOf(" "+cname+" ") < 0) cc += cname;
			element.className = cc.Trim();
		}
	}
	// remove class
	this.ClassRemove = function(element, cname) {
		if (typeof element == 'string') element = $(element);
		if (element && cname.length > 0) {
			var cc = " "+element.className+" ";
			cc = cc.replace(new RegExp(" "+cname+" ", "gi"), " ");
			element.className = cc.Trim();
		}
	}
}

// event handler
function Event(element, type, handler) {
this.Raised = null; if (typeof element.AttachedEvents == 'undefined' || element.AttachedEvents == null) {
element.AttachedEvents = new EventStore(); var existingEvent = element["on"+type];
if (existingEvent) new Event(element, type, existingEvent);EventStore.ElementList[EventStore.ElementList.length] = element;
if (EventStore.ElementList.length == 1) new Event(window, "unload", EventStore.CleanUp); }
var hIndex = element.AttachedEvents.Add(element, type, this);
this.Handler = function(evtinfo) { this.Raised = evtinfo; return handler(this);}
this.Detach = function() { element.AttachedEvents.Detach(type, hIndex); } }
function EventStore() { this.Type = []; }
EventStore.prototype.Add = function(element, type, EventObj) {
if (typeof this.Type[type] == 'undefined') { this.Type[type] = []; element["on"+type] = EventStore.Handler; }
var hIndex = this.Type[type].length; this.Type[type][hIndex] = EventObj; return hIndex; }
EventStore.prototype.Detach = function(type, hIndex) { if (typeof this.Type[type][hIndex] == 'object') delete this.Type[type][hIndex]; }
EventStore.prototype.RunEvents = function(evtinfo) {
var ret = true; if (typeof this.Type[evtinfo.Type] != 'undefined') {
var EventObj; for (var h = 0; h < this.Type[evtinfo.Type].length; h++) {
EventObj = this.Type[evtinfo.Type][h]; if (typeof EventObj == 'object') ret &= (EventObj.Handler(evtinfo) !== false); } }
return ret; }
EventStore.Handler = function(evt) { return (this.AttachedEvents ? this.AttachedEvents.RunEvents(new EventInformation(evt)) : null); }
EventStore.ElementList = []; EventStore.CleanUp = function() { for (var e = 0; e < EventStore.ElementList.length; e++) EventStore.ElementList[e].AttachedEvents = null; EventStore.ElementList = null; }
function EventInformation(event) { if (event) { this.Event = event; this.StopPropagation = function() { this.Event.stopPropagation(); }; this.StopDefaultAction = function() { this.Event.preventDefault(); }; } else { this.Event = window.event; this.StopPropagation = function() { this.Event.cancelBubble = true; }; this.StopDefaultAction = function() { this.Event.returnValue = false; }; }
this.Type = ""; this.Element = null; this.Key = ""; this.ControlKey = ""; this.Shift = false; this.Ctrl = false; this.Alt = false; this.MouseX = 0; this.MouseY = 0;
if (this.Event) { this.Type = String(this.Event.type).toLowerCase(); this.Element = (this.Event.target ? this.Event.target : this.Event.srcElement); this.Ctrl = this.Event.ctrlKey; this.Alt = this.Event.altKey; this.Shift = this.Event.shiftKey; if (this.Type.indexOf("key") == 0) { var keyCode = this.Event.keyCode; var charCode = (typeof this.Event.charCode != 'undefined' ? this.Event.charCode : null); if (charCode > 0) this.Key = String.fromCharCode(charCode); else {
if (Event.CK[keyCode] && (charCode != null || keyCode < 32 || (this.Type != "keypress" || (!this.Shift && keyCode < 112 && keyCode != 35 && keyCode != 39 && keyCode != 45 && keyCode != 46)))) this.ControlKey = Event.CK[keyCode];
else if (keyCode >= 32) this.Key = String.fromCharCode(keyCode); } }
var mre = /mouse|click/i; if (mre.test(this.Type)) { this.MouseX = (this.Event.pageX ? this.Event.pageX : this.Event.clientX + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft)); this.MouseY = (this.Event.pageY ? this.Event.pageY : this.Event.clientY + Math.max(document.documentElement.scrollTop, document.body.scrollTop)); } } }
Event.CK = []; Event.CK[8] = "backspace"; Event.CK[9] = "tab"; Event.CK[13] = "enter"; Event.CK[19] = "break"; Event.CK[27] = "esc"; Event.CK[33] = "pageup"; Event.CK[34] = "pagedown"; Event.CK[35] = "end"; Event.CK[36] = "home"; Event.CK[37] = "left"; Event.CK[38] = "up"; Event.CK[39] = "right"; Event.CK[40] = "down"; Event.CK[45] = "insert"; Event.CK[46] = "delete"; Event.CK[112] = "f1"; Event.CK[113] = "f2"; Event.CK[114] = "f3"; Event.CK[115] = "f4"; Event.CK[116] = "f5"; Event.CK[117] = "f6"; Event.CK[118] = "f7"; Event.CK[119] = "f8"; Event.CK[120] = "f9"; Event.CK[121] = "f10"; Event.CK[122] = "f11"; Event.CK[123] = "f12"; Event.CK[144] = "numlock"; Event.CK[145] = "scrolllock";


// ############################################################################
// startup event
new Event(window, "load", Main);
