/** *	device.js for round 3 *///Optionsvar feedbackDelay = 700; //in millisecondsvar traceOn = false;var smallScrollThumb = true;var scrollheight = 38;var viewportlines = 3;var items, i;//Sugarfunction objectify(id) {    if (typeof id == 'string') {        id = document.getElementById(id);    }    return id;}function addClass(target, classStr) {    target = objectify(target);    if (!target.className) {        target.className = classStr;    }    else if (!containsClass(target, classStr)){        target.className = target.className + " " + classStr;    }    return target;}function removeClass(target, classStr) {    target = objectify(target);    if (!!target.className) {        var re = new RegExp("\\s*\\b" + classStr + "\\b");        target.className = target.className.replace(re, "");    }    return target;}function containsClass(target, classStr) {    target = objectify(target);    var regex = new RegExp("\\b" + classStr + "\\b");    return (!!target && !!target.className && target.className.match(regex));}function toggleClass(target, classStr) {    if (containsClass(target, classStr)) {        removeClass(target, classStr);    }    else {        addClass(target, classStr);    }    return target;}// Tracevar trace = {	on : traceOn,	add : function(func) {		if (this.on) {			var traceListObj = objectify("trace");			var newListItemObj = document.createElement("LI");			var funcStr = func.toString();			if (funcStr.indexOf("function") === 0) {				funcStr = funcStr.substring(funcStr.indexOf(" "), funcStr.indexOf("("));				newListItemObj.setAttribute("class", funcStr);			}			var newTextObj = document.createTextNode(funcStr);			newListItemObj.appendChild(newTextObj);			traceListObj.appendChild(newListItemObj);			traceListObj.scrollTop = traceListObj.scrollHeight;		}	},	init : function() {		var newListObj = document.createElement("UL");		newListObj.setAttribute("id", "trace");		document.documentElement.appendChild(newListObj);	}};// Basic behaviors and helpersfunction getHiIndex() {	trace.add(arguments.callee);	for(var i=0; i<items.length; i++){		if (containsClass(items[i], "hi")) {			return i;		}	}	return -1;}function scrollUp() {	trace.add(arguments.callee);	for(var i=0; i<items.length; i++){		if (containsClass(items[i], "on")) {			removeClass(items[i+viewportlines-1], "on");			addClass(items[i-1], "on");			break;		}	}}function highlightUp() {	trace.add(arguments.callee);	var hiIndex = getHiIndex();	removeClass(items[hiIndex], "hi");	addClass(items[hiIndex-1],"hi");}function scrollDown() {	trace.add(arguments.callee);	for(var i=0; i<items.length; i++){		if (containsClass(items[i], "on")) {			removeClass(items[i], "on");			addClass(items[i+viewportlines], "on");			break;		}	}}function highlightDown() {	trace.add(arguments.callee);	var hiIndex = getHiIndex();	removeClass(items[hiIndex], "hi");	addClass(items[hiIndex+1],"hi");}function updateScroll() {	trace.add(arguments.callee);	if (items.length <= viewportlines){		addClass(objectify("scroll"), "off");		return;	}	var height = (smallScrollThumb) ? scrollheight*(1/items.length) : scrollheight*(viewportlines/items.length);	objectify("scrollindicator").style.height=height + "px";	for(var i=0; i<items.length; i++){		if (containsClass(items[i], "hi")) {			var position = ((scrollheight-height)/(items.length-2))*i+"px";			objectify("scrollindicator").style.top=position;		 	break;		}	}}function moveToTop() {	trace.add(arguments.callee);	if (items.length <= viewportlines) {		for(var i=0; i<items.length; i++) { //clear elements			removeClass(items[i], "hi");		}		for(var i=0; i<items.length; i++) {			if (!containsClass(items[i], "info") && !containsClass(items[i], "entervalue") && !containsClass(items[i], "unitofmeasure") && (items[i].id != "endofmenu")) {				addClass(items[i], "hi");				break;			}		}		return;	}	for(var i=0; i<items.length; i++) { //clear elements		removeClass(items[i], "on");		removeClass(items[i], "hi");	}	for(var i=0; i<viewportlines; i++) { //turn on the right ones		addClass(items[i], "on");	}	for(var i=0; i<viewportlines; i++) { //turn on the right ones		if (!containsClass(items[i], "info") && !containsClass(items[i], "entervalue") && !containsClass(items[i], "unitofmeasure") && (items[i].id != "endofmenu")) {			addClass(items[i], "hi");			break;		}	}}function moveToBottom() {	trace.add(arguments.callee);	if (items.length <= viewportlines) {		for(var i=0; i<items.length; i++) { //clear elements			removeClass(items[i], "hi");		}		addClass(items[items.length-1], "hi");		return;	}	for(var i=0; i<items.length; i++) { //clear elements		removeClass(items[i], "on");		removeClass(items[i], "hi");	}	for(var i=items.length-1; i>=items.length-viewportlines; i--) {		addClass(items[i], "on");	}	for(var i=items.length-1; i>=items.length-viewportlines; i--) {		if (!containsClass(items[i], "info") && !containsClass(items[i], "entervalue") && !containsClass(items[i], "unitofmeasure") && (items[i].id != "endofmenu")) {			addClass(items[i], "hi");			break;		}	}}function getFeedback(obj) {	trace.add(arguments.callee);	return obj.getAttribute('feedback') || false;}function showFeedback(feedbackClassStr) {	trace.add(arguments.callee);	var deviceObj = objectify('device');	for (i in deviceObj.childNodes) {		if (deviceObj.childNodes[i].nodeType == 1) {			deviceObj.childNodes[i].style.display = "none"; //hide children of "device" DIV		}	}	var newDivObj = document.createElement("DIV");	newDivObj.setAttribute("class", feedbackClassStr);	newDivObj.setAttribute("id", "feedback");	deviceObj.appendChild(newDivObj);}// Button actionsfunction down() {	trace.add(arguments.callee);	if (items.length <= viewportlines) { //if a non-scrolling menu		if (containsClass(items[items.length-1], "hi")) { //if the last item in the menu is highlighted			moveToTop();		}		else {			highlightDown();		}		updateScroll();	}	else { //a scrolling menu		if (containsClass(items[items.length-1], "on")) { //if the last item in the menu is visible			moveToTop();			updateScroll();			return;		}		else if (!containsClass(items[0], "hi")) { //if the first item in the entire menu is not highlighted			scrollDown();		}		highlightDown();		updateScroll();	}}function up() {	trace.add(arguments.callee);	var hiIndex = getHiIndex();	if (items.length <= viewportlines) { //if a non-scrolling menu		if (containsClass(items[0], "hi") || containsClass(items[hiIndex-1], "info")) { //if the first item in the menu is highlighted OR the item above the highlight is informational			moveToBottom();		}		else if (!containsClass(items[hiIndex-1], "info")) { //the item above the highlight is not informational			highlightUp();		}		updateScroll();	}	else { //a scrolling menu		if (containsClass(items[0], "hi") || containsClass(items[hiIndex-1], "info")) { //if the first item in the menu is highlighted OR the item above the highlight is informational			moveToBottom();			updateScroll();			return;		}		else if (!containsClass(items[0], "on")) { //if the first item in the entire menu is not yet visible			scrollUp();		}		if (!containsClass(items[hiIndex-1], "info")) { //the item above the highlight is not informational			highlightUp();		}		updateScroll();	}}function handleButton(anchorObj) {	trace.add(anchorObj.id);	anchorObj.blur();	var hrefStr = anchorObj.getAttribute('href');	if (hrefStr != "#" && hrefStr !== "" && (hrefStr.indexOf("#") != (hrefStr.length-1))) {		trace.add("direct");		var feedback = getFeedback(anchorObj);		if (feedback) {			showFeedback(feedback);			deferNavigation(hrefStr);			return false;		}		return true;	}	else {		trace.add("indirect");		switch(anchorObj.id) {			case ("up"):				up();				break;			case ("down"):				down();				break;			case ("esc"): // this may be vestigial				trace.add("used history.back() on ESC button");				history.back();				break;			case ("act"):				var hiIndex = getHiIndex();				var actObj = objectify("act");				if (hiIndex != -1) {					var hrefStr = items[hiIndex].getAttribute('href');					var feedback = getFeedback(anchorObj) || getFeedback(items[hiIndex]);					if (feedback) {						showFeedback(feedback);						deferNavigation(hrefStr);					}					else {						actObj.href = hrefStr;						return true;					}				}				break;			default:				alert("Button not implemented.");		}	}	return false;}function deferNavigation(hrefStr) {	self.setTimeout( function() {		location.href = hrefStr;	}, feedbackDelay);}				// Initwindow.onload = function() {	if (trace.on) {		trace.init();	}	items = objectify("Menu").getElementsByTagName("LI");	var buttons = objectify("controls").getElementsByTagName("A");	for(var i=0; i<buttons.length; i++) {		buttons[i].onclick = function() {			return handleButton(this);		};	}	updateScroll();};/* Notes	Reserved words: http://www.irt.org/script/1076.htm	TODO:		Thorough test		Optimize/streamline/modularize		Clean up trace logging*/	
