mobile=0;
tip=null;

// ERROR

try {window.onerror=otherjserror;} catch(e) {}  // catch any other errors
function otherjserror(errmsg,page,line,chr) {
	logjserror(0,errmsg+' (line '+line+')');
	return true;	// return false for browser error alert
	}

logging=(document.cookie.indexOf('logging=5')>=0);
jserrormem='';
function logjserror(x,m) {
	if(x) m+='  ['+x.name+': '+x.message+']';
	jserrormem+="\n"+m;
	if(logging) alert(m);
	else {
		try {document.form1.jserror.value=jserrormem;} catch(e) {}
		}
	}


// BROWSER

x=navigator.userAgent.indexOf('MSIE');
if(x!=-1) {
	browser='MSIE';
	browservers=navigator.userAgent.substr(x+5,2)-0;
	}
else if(navigator.userAgent.indexOf('Safari')!=-1) browser='Safari';
else if(navigator.userAgent.indexOf('Firefox')!=-1 || navigator.userAgent.indexOf('Netscape')!=-1 || navigator.userAgent.indexOf('SeaMonkey')!=-1) browser='Mozilla';
else browser='?';
mozilla=(browser=='Mozilla');


// TIP BOX

function showtip() {
	if(!tip) return;
	var msg=tipmsg1();
	if(!msg) return hidetip();
	var box=document.getElementById('tipbox');
	setspan('tipspan',msg);
	setstyle('tipbox','tipbox');
	tipwidth=box.offsetWidth;
	tipheight=box.offsetHeight;
	tipopen=true;
	// same as mousemove:
	box.style.left=(Math.min(mousex+8,windowx-18-tipwidth))+'px';
	if(windowy-(mousey+tipheight)>60 || !windowy) box.style.top=(mousey+20)+'px';  // IE6 always this way
	else box.style.top=(mousey-32-tipheight)+'px';
	}

function hidetip() {
	if(tiptimer) clearTimeout(tiptimer);
	if(!tipopen) return;
	setstyle('tipbox','hide');
	tipopen=false;
	}

function mouseover(e) {  // this called after inline onmouseover
	var f=(mozilla)?e.target:event.srcElement;
	var t=f.getAttribute('tip');
	if(t!='preset') tip=t;  // 'preset' means inline onmouseover already defined tip
	if(!t) return;
	if(tiptimer) clearTimeout(tiptimer);
	if(tipopen) showtip();  // update immediately if already open
	else tiptimer=setTimeout('showtip()',1500);  // wait 1.5 sec if not already open
	}

function mouseout(e) {
	if(tiptimer) clearTimeout(tiptimer);
	if(tipopen) tiptimer=setTimeout('hidetip()',50);  // delay 0.05 sec to see if mouseover new tip
	}

function mousemove(e) {
	var box=document.getElementById('tipbox');
	if(!box) return;
	if(browser!='MSIE') {mousex=e.pageX; mousey=e.pageY;}  // Firefox, Safari
	else if(browservers>=8) {mousex=event.x; mousey=event.y;}  // MSIE 8+
	else {mousex=event.x+document.documentElement.scrollLeft; mousey=event.y+document.documentElement.scrollTop;}  // MSIE 7-
	windowx=document.documentElement.clientWidth+document.documentElement.scrollLeft+document.body.scrollLeft;  // visible width inside scrollbar; Firefox/Explorer + Safari
	windowy=document.documentElement.clientHeight+document.documentElement.scrollTop+document.body.scrollTop;
	box.style.left=(Math.min(mousex+8,windowx-18-tipwidth))+'px';
	if(windowy-(mousey+tipheight)>48) box.style.top=(mousey+20)+'px';
	else box.style.top=(mousey-32-tipheight)+'px';
	}

// KEYBOARD

function keydown(e) {  // check arrow & return & escape keys
	if(tipopen) hidetip();
	var k=(mozilla)?e.keyCode:event.keyCode;  // which key
	if(k==27 && document.form1.find) {  // escape to select Find
		if(!document.form1.admin) {
			focusfind();  // teacher
			selectf('find');
			}
		else if(!mobile) {  // admin
			if(!studmenuopen) clickstudbtn();
			else selectf('find');
			}
		return false;
		}
	var f=(mozilla)?e.target:event.srcElement;
	if(f.type!='text' && f.type!='password') return true;  // use normal behavior in textareas for arrow keys, return & enter
	var i=f.getAttribute('keyindex')-0;
	if(!i) return true;  // pass keystrokes for anything that wasn't captured in initjs()
	if(k==40 || k==13 || k==10 || k==3 || k==63233) {  // down arrow or return/enter
		if((k==13 || k==10 || k==3)) {  // return/enter may do an action
			if(f.getAttribute('onshiftreturn') && ((mozilla)?e.shiftKey:event.shiftKey)) {  // shift return
				setTimeout(f.getAttribute('onshiftreturn'),1);
				return false;  // don't type return/enter
				}
			else if(f.getAttribute('onreturn')) {  // regular return
				f.blur();  // force onchange first
				setTimeout(f.getAttribute('onreturn'),1);
				return false;  // don't type return/enter
				}
			}
		do {
			i++;  // identify next field
			if(fields[i]=='') return false;
			} while(document.form1.elements[fields[i]].getAttribute('skip')==1)  // if next fld has attribute skip==1, find next fld after
		}
	else if(k==38 || k==63232) {  // up arrow
		do {
			if(i==1) return false;  // can't go before 1st field
			i--;  // identify previous field
			} while(document.form1.elements[fields[i]].getAttribute('skip')==1)  // if previous fld has attribute skip==1, find fld before
		}
	else if((k==37 || k==63234) && f.getAttribute('keyleft'))  // left
		i-=f.getAttribute('keyleft');
	else if((k==39 || k==63235) && f.getAttribute('keyright')) {  // right
		var i1=f.getAttribute('keyright')-0+i;
		if(fields[i1]) i=i1;
		}
	else return true;  // type any other key
	document.form1.elements[fields[i]].select();
	return false;
	}

function setskip(f,x,errok) {  // flag if field should be skipped for key order
	try {document.form1.elements[f].setAttribute('skip',x);}
	catch(e) {if(!errok) logjserror(e,'setskip('+f+','+x+')');}
	}

function initjs() {  // index all text boxes for return & arrow keys
	setTimeout('initjs1()',1);  // delay helps Safari
	}
function initjs1() {
	fields=new Array();
	var z=document.form1.length;
	var k;
	for(k=0;k<z;k++) {
		var f=document.form1.elements[k];
		if(f.type!='text' && f.type!='password') continue;  // find all text and password input; skip textarea and other inputs
		if(!f.name) continue;  // ignore element if it has no name, eg: a hidden spacer
		var c=f.getAttribute('col');  // text fields may optionally have a col attribute
		c=(c)?c-0:0;  // change NaN to 0, string to number
		if(!fields[c]) fields[c]='';  // organize text fields by column
		fields[c]+=','+f.name;
		}
	fields=fields.join('')+',';  // join columns together in order
	fields=fields.split(',');  // all fields in linear order; 0th and last item is blank
	var fieldcount=fields.length-1;
	for(k=1;k<fieldcount;k++)  // give each field a number
		document.form1.elements[fields[k]].setAttribute('keyindex',k);  // assign keyindex attribute to fields
	keyflag=false;
	document.onkeydown=keydown;
	tipopen=false;
	if(!mobile) {
		tip=null;
		tipwidth=0;
		tipheight=0;
		mousex=0;
		mousey=0;
		windowx=0;
		windowy=0;
		document.onmouseover=mouseover;
		document.onmouseout=mouseout;
		document.onmousemove=mousemove;
		}
	}
tiptimer=null;  // set before initjs in case click body -> hidetip()

function autorows(f,e,minrows,maxrows,extra,func) {  // onkeyup in textarea
	var k=e.keyCode;  // which key
	if(k!=13 && k!=3 && k!=8 && k!=46) return;  // return or delete keys only
	var t=f.value.split("\n");
	var rows=Math.min(maxrows,Math.max(minrows,t.length+extra));
	r=(mozilla && rows>1)?rows-1:rows;  // firefox always shows one too many rows, so r = 1 less than visible rows
	if(r==f.rows) return;
	f.rows=r;
	if(func) eval(func);
	}


// TEXT BOXES

function text(f,errok) {
	try {return document.form1.elements[f].value;}
	catch(e) {if(!errok) logjserror(e,'text('+f+')');}
	}

function settext(f,x,errok) {
	try {document.form1.elements[f].value=x;}
	catch(e) {if(!errok) logjserror(e,'settext('+f+','+x+')');}
	}

function cleantext(f,cap,def) {
	try {
		var x=clean(document.form1.elements[f].value);
		if(x=='' && def) x=def;
		else if(cap) x=caps(x,cap);
		document.form1.elements[f].value=x;
		return x;
		}
	catch(e) {return logjserror(e,'cleantext('+f+')');}
	}

function focusf(f,errok) {
	try {document.form1.elements[f].focus();}
	catch(e) {if(!errok) logjserror(e,'focusf('+f+')');}
	}

function selectf(f,errok) {
	try {
		if(browser=='MSIE') {  // IE has tab order problems on select, so focus first
			document.form1.elements[f].focus();
			document.form1.elements[f].select();
			}
		else if(browser=='Safari') {  // Safari fails to select all text
			document.form1.elements[f].focus();
			var len=document.form1.elements[f].value.length;
			setTimeout("document.form1."+f+".selectionStart=0; document.form1."+f+".selectionEnd="+len,1);
			}
		else  // Mozilla okay
			document.form1.elements[f].select();
		}
	catch(e) {if(!errok) logjserror(e,'selectf('+f+')');}
	}

function blurf(f,errok) {
	try {document.form1.elements[f].blur();}
	catch(e) {if(!errok) logjserror(e,'blurf('+f+')');}
	}


// TEXT SPAN

function setspan(i,x,errok) {
	try {document.getElementById(i).innerHTML=x;}
	catch(e) {if(!errok) logjserror(e,'setspan('+i+','+x+')');}
	}

function getspan(i,errok) {
	try {return document.getElementById(i).innerHTML;}
	catch(e) {if(!errok) logjserror(e,'getspan('+i+')');}
	}

function err(f,m) {
	setspan('alert',m,'errok');
	setstyle('showalert',(m=='')?'hide':'show','errok');
	if(f) (document.form1.elements[f].type=='text' || document.form1.elements[f].type=='password')? selectf(f):focusf(f);
	}


// CHECKBOXES

function checked(f,errok) {
	try {return document.form1.elements[f].checked;}
	catch(e) {if(!errok) logjserror(e,'checked('+f+')');}
	}

function setcheck(f,x,errok) {
	try {document.form1.elements[f].checked=x;}
	catch(e) {if(!errok) logjserror(e,'setcheck('+f+','+x+')');}
	}

function check(f,errok) {
	try {document.form1.elements[f].checked=true;}
	catch(e) {if(!errok) logjserror(e,'check('+f+')');}
	}

function uncheck(f,errok) {
	try {document.form1.elements[f].checked=false;}
	catch(e) {if(!errok) logjserror(e,'uncheck('+f+')');}
	}

function clickcheck(f,errok) {
	try {
		if(document.form1.elements[f].disabled) return showtip();
		document.form1.elements[f].checked=!document.form1.elements[f].checked;
		if(document.form1.elements[f].onclick) document.form1.elements[f].onclick();
		}
	catch(e) {if(!errok) logjserror(e,'clickcheck('+f+')');}
	}


// RADIO BUTTONS

function radio(f,errok) {  // returns empty string if none selected
	try {
		var z=document.form1.elements[f].length;
		for(n=0;n<z;n++) {
			if(!document.form1.elements[f][n].checked) continue;
			var x=document.form1.elements[f][n].value;
			return (x=='0')?0:x;  // ensure 0 counts as false integer instead of true string
			}
		return '';
		}
	catch(e) {if(!errok) logjserror(e,'radio('+f+')');}
	}

function setradio(f,x,errok) {
	try {
		var z=document.form1.elements[f].length;
		for(n=0;n<z;n++) {
			if(document.form1.elements[f][n].value!=x) continue;
			document.form1.elements[f][n].checked=true;
			return;
			}
		logjserror(0,'setradio('+f+','+x+'): no such value');
		}
	catch(e) {if(!errok) logjserror(e,'setradio('+f+','+x+')');}
	}

function clickradio(f,x,errok) {
	try {
		if(document.form1.elements[f][x].disabled) return showtip();
		document.form1.elements[f][x].checked=true;
		if(document.form1.elements[f][x].onclick) document.form1.elements[f][x].onclick();
		}
	catch(e) {if(!errok) logjserror(e,'clickradio('+f+','+x+')');}
	}


// MENUS

function menu(f,errok) {
	try {
		var x=document.form1.elements[f].options[document.form1.elements[f].selectedIndex].value;
		return (x=='0')?0:x;  // ensure 0 counts as false integer instead of true string
		}
	catch(e) {if(!errok) logjserror(e,'menu('+f+')');}
	}

function setmenu(f,x,errok) {  // if value not found, no change, no error
	try {
		var z=document.form1.elements[f].options.length;
		for(n=0;n<z;n++) {
			if(document.form1.elements[f].options[n].value!=x) continue;
			document.form1.elements[f].selectedIndex=n;
			return;
			}
		if(!errok) logjserror(0,'setmenu('+f+','+x+'): no such value');
		}
	catch(e) {if(!errok) logjserror(e,'setmenu('+f+','+x+')');}
	}

function menui(f,errok) {
	try {return document.form1.elements[f].selectedIndex;}
	catch(e) {if(!errok) logjserror(e,'menui('+f+')');}
	}

function setmenui(f,x,errok) {
	try {document.form1.elements[f].selectedIndex=x;}
	catch(e) {if(!errok) logjserror(e,'setmenui('+f+','+x+')');}
	}


// LIST BOX

function listbox(f,errok) {
	try {
		var v='';
		var z=document.form1.elements[f].length;
		for(n=0;n<z;n++)
			v+=document.form1.elements[f][n].value+'='+((document.form1.elements[f][n].selected)?1:0)+',';
		return v.substr(0,v.length-1);
		}
	catch(e) {if(!errok) logjserror(e,'listbox('+f+')'); return '';}
	}

function savelistbox(f,errok) {
	var v=listbox(f+'list',errok);
	settext(f,v,errok);
	}


// STYLE

function setstyle(i,x,errok) {
	try {document.getElementById(i).className=x;}
	catch(e) {if(!errok) logjserror(e,'setstyle('+i+','+x+')');}
	}

function setstylef(f,x,errok) {
	try {document.form1.elements[f].className=x;}
	catch(e) {if(!errok) logjserror(e,'setstylef('+f+','+x+')');}
	}

function getstyle(i,errok) {
	try {return document.getElementById(i).className;}
	catch(e) {if(!errok) logjserror(e,'getstyle('+i+')');}
	}

function getstylef(f,errok) {
	try {return document.form1.elements[f].className;}
	catch(e) {if(!errok) logjserror(e,'getstylef('+f+')');}
	}

function setdisplay(s,r,x) {  // starting with style block #0, rule #0; none=hide, inline/block/''
	try {
		if(document.styleSheets[s].rules)
			document.styleSheets[s].rules[r].style.display=x;
		else
			document.styleSheets[s].cssRules[r].style.display=x;
		}
	catch(e) {logjserror(e,'setdisplay('+s+','+r+','+x+')');}
	}

function setvisibility(s,r,x) {  // starting with style block #0, rule #0; hidden=spacer, visible/''
	try {
		if(document.styleSheets[s].rules)
			document.styleSheets[s].rules[r].style.visibility=x;
		else
			document.styleSheets[s].cssRules[r].style.visibility=x;
		}
	catch(e) {logjserror(e,'setvisibility('+s+','+r+','+x+')');}
	}


// OTHER ATTRIBUTES

function setdisabled(f,x,errok) {
	try {document.form1.elements[f].disabled=x;}
	catch(e) {if(!errok) logjserror(e,'setdisabled('+f+','+x+')');}
	}

function atti(i,a,errok) {
	try {return document.getElementById(i).getAttribute(a);}
	catch(e) {if(!errok) logjserror(e,'atti('+i+','+a+')');}
	}

function att(f,a,errok) {
	try {return document.form1.elements[f].getAttribute(a);}
	catch(e) {if(!errok) logjserror(e,'att('+f+','+a+')');}
	}

function setatt(f,a,x,errok) {
	try {document.form1.elements[f].setAttribute(a,x);}
	catch(e) {if(!errok) logjserror(e,'setatt('+f+','+a+','+x+')');}
	}


// BUTTONS

function overbtn(i) {
	if(btndim(document.getElementById(i))) return;
	setstyle(i,'btnlit btntxt');
	setstyle(i+'l','btnlitl');
	setstyle(i+'r','btnlitr');
	}
function outbtn(i) {
	if(btndim(document.getElementById(i))) return;
	setstyle(i,'btn btntxt');
	setstyle(i+'l','btnl');
	setstyle(i+'r','btnr');
	}

function clickbtn(i) {
	document.getElementById(i).onclick();
	}

function btndim(o) {
	return o.getAttribute('dim')-0;
	}

function setbtndim(i,dim,inv,errok) {
	if(!document.getElementById(i)) return;  // ignore if doesn't exist
	var btn=(inv)?'btni':'btn';
	setstyle(i,((dim)?btn+'dim':btn)+' btntxt');
	if(!inv) {
		setstyle(i+'l','btnl');
		setstyle(i+'r','btnr');
		}
	try {document.getElementById(i).setAttribute('dim',(dim)?1:0);}
	catch(e) {if(!errok) logjserror(e,'setbtndim('+i+','+dim+','+inv+')');}
	}


// PROMPT

promptopen=0;
defaultprompt=0;
function showprompt(p,nohide) {
	if(promptopen) setstyle(promptopen,'hide');  // close anything already open
	if(p==promptopen && !nohide || !p) p=defaultprompt;  // close prompt or show default
	promptopen=p;
	if(p) setstyle(p,'show');
	return promptopen;
	}


// STRING FUNCTIONS

function isin(needle,haystack) {
	return (haystack.indexOf(needle)>=0);
	}

function clean(x) {  // for ALL input strip whitespace, disallow \
	if(!x) return '';
	var f=String.fromCharCode(32,160,9,10,13); // white space
	while(f.indexOf(x.charAt(0))>=0 && x.length>0)  // trim leading
		x=x.substring(1,x.length);
	while(f.indexOf(x.charAt(x.length-1))>=0 && x.length>0)  // trim trailing
		x=x.substring(0,x.length-1);
	while(x.indexOf('\\')>=0)
	  x=x.substring(0,x.indexOf('\\'))+'✓'+x.substring(x.indexOf('\\')+1,x.length);  // replace \ with /
	return x;
	}

function filter(x,f,r) {
	var y='';
	if(r==null) r='';
	var z=x.length;
	for(i=0;i<z;i++)
		y+=(f.indexOf(x.charAt(i))>=0)? x.charAt(i):r;
	return y;
	}

function number(x,format) {  // parses number, blank if NAN; format='.-%+' to allow decimals, negatives, percents, show positive sign
	var f='0123456789.';
	if(format.indexOf('-')>=0) f+='-';
	var y=filter(x,f);
	if(y-0!=y || y=='') return '';  // NAN
	if(format.indexOf('.')<0) y=Math.round(y);  // round integers
	if(format.indexOf('+')>=0 && y>0) y='+'+y;  // show positive sign
	if(format.indexOf('%')>=0) y += '%';  // append percent sign
	return y;
	}

function roundit(x,d) {  // d = 0 or 1
	if(x=='') return '';
	x=x-0;
	if(d==0) return Math.round(x+0.00001);
	x=(Math.round(x*10+0.00001)/10)+'';
	if(x.indexOf('.')<0) x+='.0';
	return x;
	}

function caps(x,maxacro) {  // changes all-caps or all-lower to title case
	if(x=='') return x;
	var upper=x.toUpperCase();
	var lower=x.toLowerCase();
	if(x!=upper && x!=lower) return x;  // don't change if already mixed case
	var len=x.length;
	if(x==upper && len<=maxacro) return x;  // allow acronyms with all caps
	var sep=" ,.-'‘’()[]\"“”";
	var y='';
	var capnext=true;
	for(i=0;i<len;i++) {
		var c=lower.charAt(i);
		y+=(capnext)?c.toUpperCase():c;
		capnext=(sep.indexOf(c)>=0);
		}
	return y;
	}

function ecaps(email) {  // if email is all caps, change to lower; ok if mixed caps
	if(email==email.toUpperCase()) return email.toLowerCase();
	return email;
	}

function changeemail(f,multi,def) {  // multi=allow multiple address; def=default if blank
	var x=text(f);
	var ok='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
	var punc="@._-/'";  // okay in middle, but not at start/end
	x=x+' ';
	x=repstr('%20',' ',x);
	var y='';  // final list
	var a='';  // one address
	var b='';  // questionable chars
	var l=x.length;
	for(k=0;k<l;k++) {
		var c=x.charAt(k);
		if(ok.indexOf(c)>=0) {
			if(a=='') a=c;  // first char: discard any punc
			else a+=b+c;  // middle: include punc
			b='';
			}
		else if(punc.indexOf(c)>=0)  // punc: tentatively keep
			b+=c;
		else {  // non-char: check if valid email
			var at=a.indexOf('@');
			var dot=a.lastIndexOf('.');
			if(at && dot>at) {  // valid email
				a=ecaps(a);
				if(y=='') y=a;
				else y+=', '+a;
				if(!multi) break;
				}
			a='';
			b='';
			}
		}
	if(!y && def) y=def;
	settext(f,y);
	}

function changeweb(f) {
	x=clean(text(f));
	if(x.indexOf('.')==-1 || x.indexOf(' ')!=-1 || x.indexOf('@')!=-1) x='';
	settext(f,x);
	}

function cleandate(mdy,defaultyear) {  // input m/d/y, yr1=default year if Jan-July, yr8=default year if Aug-Dec
	mdy=repstr(' ','',mdy);
	mdy=filter(mdy,'0123456789/','/');
	mdy=mdy.split('/');
	var m=mdy[0]-0;
	var d=mdy[1]-0;
	var y=mdy[2]-0;
	if(m<1 || m>12 || m+''=='NaN') return '';
	if(d<1 || d>31 || d+''=='NaN') return '';
	if(!(y>=1 && y<=99 || y>=2000 && y<=2099) || y+''=='NaN') {
		defaultyear=defaultyear+'';
		y=(m>=8)?defaultyear.substr(2,2):defaultyear.substr(defaultyear.length-2,2);  // must be 01-99 or 2000-2099, else default year
		}
	else if(y<10) y='0'+y;
	return m+'/'+d+'/'+y;
	}

function repstr(x,y,t) {
	while(true) {
		var n=t.indexOf(x);
		if(n<0) return t;
		t=t.substring(0,n)+y+t.substring(n+x.length,t.length);
		}
	}

function noempty(x) {
	return (x=='')?'&nbsp;':x;
	}


// NAVIGATION

function gopost(url) {
	if(url) document.form1.action=(url);
	document.form1.submit();
	}

function gohelp(page,helpcontext) {  // if no page, go helpcontext
	var url;
	if(!page) url='../help/index.php?'+helpcontext;
	else if(page.indexOf('.')<0) url='../help/'+page+'.html';  // go to specific help page
	else url='../help/'+page;  // usually for contact.php
	helpwin=window.open(url,'helpwin','width=560,height=500,scrollbars=yes,resizable=yes,toolbar=no,location=no,directories=no,status=no');
	try {helpwin.focus();}  // for msie
	catch(e) {alert('Turn off your pop-up blocker to see the Help window.');}
	}


// COOKIE

function savecookie(cookie,value,expire) {
	if(expire+''!='0') {  // default one year unless; specify 0 to expire on browser quit
		e=new Date();
		e.setTime(e.getTime()+(365*24*60*60*1000));  // one year
		document.cookie=cookie+'='+escape(value)+'; expires='+e.toGMTString()+'; path=/';
		}
	else
		document.cookie=cookie+'='+escape(value)+'; path=/';
	}
