--- /dev/null
+function $(id) { return getId(id); }
+function getId(id) {
+ return document.getElementById(id);
+}
+
+function swapCSSClass(obj, old, newc ) {
+ removeCSSClass(obj, old );
+ addCSSClass(obj, newc );
+}
+
+
+function addCSSClass(e,c) {
+ if(!e || !c) return;
+
+ var css_class_string = e.className;
+ var css_class_array;
+
+ if(css_class_string)
+ css_class_array = css_class_string.split(/\s+/);
+
+ var string_ip = ""; /*strip out nulls*/
+ for (var css_class in css_class_array) {
+ if (css_class_array[css_class] == c) { return; }
+ if(css_class_array[css_class] !=null)
+ string_ip += css_class_array[css_class] + " ";
+ }
+ string_ip += c;
+ e.className = string_ip;
+}
+
+function removeCSSClass(e, c) {
+ if(!e || !c) return;
+
+ var css_class_string = '';
+
+ var css_class_array = e.className;
+ if( css_class_array )
+ css_class_array = css_class_array.split(/\s+/);
+
+ var first = 1;
+ for (var css_class in css_class_array) {
+ if (css_class_array[css_class] != c) {
+ if (first == 1) {
+ css_class_string = css_class_array[css_class];
+ first = 0;
+ } else {
+ css_class_string = css_class_string + ' ' +
+ css_class_array[css_class];
+ }
+ }
+ }
+ e.className = css_class_string;
+}
+
+
+/*returns the character code pressed that caused the event */
+function grabCharCode(evt) {
+ evt = (evt) ? evt : ((window.event) ? event : null);
+ if( evt ) {
+ return (evt.charCode ? evt.charCode :
+ ((evt.which) ? evt.which : evt.keyCode ));
+ } else { return -1; }
+}
+
+
+/* returns true if the user pressed enter */
+function userPressedEnter(evt) {
+ var code = grabCharCode(evt);
+ if(code==13||code==3) return true;
+ return false;
+}
+
+
+function goTo(url) {
+ /* setTimeout because ie sux */
+ setTimeout( function(){ location.href = url; }, 0 );
+}
+
+
+function removeChildren(dom) {
+ if(!dom) return;
+ while(dom.childNodes[0])
+ dom.removeChild(dom.childNodes[0]);
+}
+
+function appendClear(node, child) {
+ if(typeof child =='string') child = text(child);
+ removeChildren(node);
+ node.appendChild(child);
+}
+
+
+function instanceOf(object, constructorFunction) {
+
+ if(!IE) {
+ while (object != null) {
+ if (object == constructorFunction.prototype)
+ return true;
+ object = object.__proto__;
+ }
+ } else {
+ while(object != null) {
+ if( object instanceof constructorFunction )
+ return true;
+ object = object.__proto__;
+ }
+ }
+ return false;
+}
+
+
+/* ------------------------------------------------------------------------------------------- */
+/* detect my browser */
+var isMac, NS, NS4, NS6, IE, IE4, IEmac, IE4plus, IE5, IE5plus, IE6, IEMajor, ver4, Safari;
+function detect_browser() {
+
+ isMac = (navigator.appVersion.indexOf("Mac")!=-1) ? true : false;
+ NS = (navigator.appName == "Netscape") ? true : false;
+ NS4 = (document.layers) ? true : false;
+ IE = (navigator.appName == "Microsoft Internet Explorer") ? true : false;
+ IEmac = ((document.all)&&(isMac)) ? true : false;
+ IE4plus = (document.all) ? true : false;
+ IE4 = ((document.all)&&(navigator.appVersion.indexOf("MSIE 4.")!=-1)) ? true : false;
+ IE5 = ((document.all)&&(navigator.appVersion.indexOf("MSIE 5.")!=-1)) ? true : false;
+ IE6 = ((document.all)&&(navigator.appVersion.indexOf("MSIE 6.")!=-1)) ? true : false;
+ ver4 = (NS4 || IE4plus) ? true : false;
+ NS6 = (!document.layers) && (navigator.userAgent.indexOf('Netscape')!=-1)?true:false;
+ Safari = navigator.userAgent.match(/Safari/);
+
+ IE5plus = IE5 || IE6;
+ IEMajor = 0;
+
+ if (IE4plus) {
+ var start = navigator.appVersion.indexOf("MSIE");
+ var end = navigator.appVersion.indexOf(".",start);
+ IEMajor = parseInt(navigator.appVersion.substring(start+5,end));
+ IE5plus = (IEMajor>=5) ? true : false;
+ }
+}
+detect_browser();
+/* ------------------------------------------------------------------------------------------- */
+
+
+function text(t) {
+ if(t == null) t = "";
+ return document.createTextNode(t);
+}
+
+function elem(name, attrs, txt) {
+ var e = document.createElement(name);
+ if (attrs) {
+ for (key in attrs) {
+ if( key == 'id') e.id = attrs[key];
+ else e.setAttribute(key, attrs[key]);
+ }
+ }
+ if (txt) e.appendChild(text(txt));
+ return e;
+}
+
+
+/* sel is the selector object, sets selected on the
+ option with the given value. case does not matter...*/
+function setSelector( sel, value ) {
+ if(sel && value != null) {
+ for( var i = 0; i!= sel.options.length; i++ ) {
+ if( sel.options[i] ) {
+ var val = sel.options[i].value;
+ if( val == null || val == "" ) /* for IE */
+ val = sel.options[i].innerHTML;
+ value += ""; /* in case of number */
+ if( val && val.toLowerCase() == value.toLowerCase() ) {
+ sel.selectedIndex = i;
+ sel.options[i].selected = true;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+function setSelectorRegex( sel, regex ) {
+ if(sel && regex != null) {
+ for( var i = 0; i!= sel.options.length; i++ ) {
+ if( sel.options[i] ) {
+ var val = sel.options[i].value;
+ if( val == null || val == "" ) /* for IE */
+ val = sel.options[i].innerHTML;
+ value += ""; /* in case of number */
+ if( val && val.match(regex) ) {
+ sel.selectedIndex = i;
+ sel.options[i].selected = true;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+function getSelectorVal( sel ) {
+ if(!sel) return null;
+ var idx = sel.selectedIndex;
+ if( idx < 0 ) return null;
+ var o = sel.options[idx];
+ var v = o.value;
+ if(v == null) v = o.innerHTML;
+ return v;
+}
+
+function getSelectorName( sel ) {
+ var o = sel.options[sel.selectedIndex];
+ var v = o.name;
+ if(v == null || v == undefined || v == "") v = o.innerHTML;
+ return v;
+}
+
+function setSelectorByName( sel, name ) {
+ for( var o in sel.options ) {
+ var opt = sel.options[o];
+ if( opt.name == name || opt.innerHTML == name ) {
+ sel.selectedIndex = o;
+ opt.selected = true;
+ }
+ }
+}
+
+function findSelectorOptByValue( sel, val ) {
+ for( var i = 0; i < sel.options.length; i++ ) {
+ var opt = sel.options[i];
+ if( opt.value == val ) return opt;
+ }
+ return null;
+}
+
+function debugSelector(sel) {
+ var s = 'Selector\n';
+ for( var i = 0; i != sel.options.length; i++ ) {
+ var o = sel.options[i];
+ s += "\t" + o.innerHTML + "\n";
+ }
+ return s;
+}
+
+function findParentByNodeName(node, name) {
+ while( ( node = node.parentNode) )
+ if (node.nodeName == name) return node;
+ return null;
+}
+
+/* returns only elements in nodes childNodes list, not sub-children */
+function getElementsByTagNameFlat( node, name ) {
+ var elements = [];
+ for( var e in node.childNodes ) {
+ var n = node.childNodes[e];
+ if( n && n.nodeName == name ) elements.push(n);
+ }
+ return elements;
+}
+
+/* expects a tree with a id() method on each node and a
+children() method to get to each node */
+function findTreeItemById( tree, id ) {
+ if( tree.id() == id ) return tree;
+ for( var c in tree.children() ) {
+ var found = findTreeItemById( tree.children()[c], id );
+ if(found) return found;
+ }
+ return null;
+}
+
+/* returns null if none of the tests are true. returns sub-array of
+matching array items otherwise */
+function grep( arr, func ) {
+ var results = [];
+ if(!arr) return null;
+ if( arr.constructor == Array ) {
+ for( var i = 0; i < arr.length; i++ ) {
+ if( func(arr[i]) )
+ results.push(arr[i]);
+ }
+ } else {
+ for( var i in arr ) {
+ if( func(arr[i]) )
+ results.push(arr[i]);
+ }
+ }
+ if(results.length > 0) return results;
+ return null;
+}
+
+function ogrep( obj, func ) {
+ var results = {};
+ var found = false;
+ for( var i in obj ) {
+ if( func(obj[i]) ) {
+ results[i] = obj[i];
+ found = true;
+ }
+ }
+ if(found) return results;
+ return null;
+}
+
+function doSelectorActions(sel) {
+ if((IE || Safari) && sel) {
+ sel.onchange = function() {
+ var o = sel.options[sel.selectedIndex];
+ if(o && o.onclick) o.onclick()
+ }
+ }
+}
+
+/* if index < 0, the item is pushed onto the end */
+function insertSelectorVal( selector, index, name, value, action, indent ) {
+ if( index < 0 ) index = selector.options.length;
+ var a = [];
+ for( var i = selector.options.length; i != index; i-- )
+ a[i] = selector.options[i-1];
+
+ var opt = setSelectorVal( selector, index, name, value, action, indent );
+
+ for( var i = index + 1; i < a.length; i++ )
+ selector.options[i] = a[i];
+
+ return opt;
+}
+
+/* changes the value of the option at the specified index */
+function setSelectorVal( selector, index, name, value, action, indent ) {
+ if(!indent || indent < 0) indent = 0;
+ indent = parseInt(indent);
+
+ var option;
+
+ if(IE) {
+ var pre = elem("pre");
+ for( var i = 0; i != indent; i++ )
+ pre.appendChild(text(" "));
+
+ pre.appendChild(text(name));
+ option = new Option("", value);
+ selector.options[index] = option;
+ option.appendChild(pre);
+
+ } else {
+ indent = indent * 14;
+ option= new Option(name, value);
+ option.setAttribute("style", "padding-left: "+indent+'px;');
+ selector.options[index] = option;
+ if(action) option.onclick = action;
+ }
+
+ if(action) option.onclick = action;
+ return option;
+}
+
+
+/* split on spaces. capitalize the first /\w/ character in
+ each substring */
+function normalize(val) {
+ return val; /* disable me for now */
+
+ if(!val) return "";
+
+ var newVal = '';
+ try {val = val.split(' ');} catch(E) {return val;}
+ var reg = /\w/;
+
+ for( var c = 0; c < val.length; c++) {
+
+ var string = val[c];
+ var cap = false;
+ for(var x = 0; x != string.length; x++) {
+
+ if(!cap) {
+ var ch = string.charAt(x);
+ if(reg.exec(ch + "")) {
+ newVal += string.charAt(x).toUpperCase();
+ cap = true;
+ continue;
+ }
+ }
+
+ newVal += string.charAt(x).toLowerCase();
+ }
+ if(c < (val.length-1)) newVal += " ";
+ }
+
+ newVal = newVal.replace(/\s*\.\s*$/,'');
+ newVal = newVal.replace(/\s*\/\s*\/\s*$/,' / ');
+ newVal = newVal.replace(/\s*\/\s*$/,'');
+
+ return newVal;
+}
+
+
+/* returns true if n is null or stringifies to 'undefined' */
+function isNull(n) {
+ if( n == null || n == undefined || n.toString().toLowerCase() == "undefined"
+ || n.toString().toLowerCase() == "null" )
+ return true;
+ return false;
+}
+
+
+/* find nodes with an attribute of 'name' that equals nodeName */
+
+function $n( root, nodeName ) { return findNodeByName(root,nodeName); }
+
+function findNodeByName(root, nodeName) {
+ if( !root || !nodeName) return null;
+
+ if(root.nodeType != 1) return null;
+
+ if(root.getAttribute("name") == nodeName || root.name == nodeName )
+ return root;
+
+ var children = root.childNodes;
+
+ for( var i = 0; i != children.length; i++ ) {
+ var n = findNodeByName(children[i], nodeName);
+ if(n) return n;
+ }
+
+ return null;
+}
+
+
+/* truncates the string at 'size' characters and appends a '...' to the end */
+function truncate(string, size) {
+ if(string && size != null &&
+ size > -1 && string.length > size)
+ return string.substr(0, size) + "... ";
+ return string;
+}
+
+
+/* style sheets must have a 'name' attribute for these functions to work */
+function setActivateStyleSheet(name) {
+ var i, a, main;
+ for (i = 0; (a = document.getElementsByTagName ("link")[i]); i++) {
+ if (a.getAttribute ("rel").indexOf ("style") != -1 && a.getAttribute ("name")) {
+ a.disabled = true;
+ if (a.getAttribute ("name").indexOf(name) != -1)
+ a.disabled = false;
+ }
+ }
+}
+
+
+/* ----------------------------------------------------- */
+var currentFontSize;
+function scaleFonts(type) {
+
+ var size = "";
+ var ssize = "";
+ var size2 = "";
+ var a;
+
+ if(!currentFontSize) currentFontSize = 'regular';
+ if(currentFontSize == 'regular' && type == 'regular' ) return;
+ if( currentFontSize == type ) return;
+ currentFontSize = type;
+
+ switch(type) {
+ case "large": /* these are arbitrary.. but they seem to work ok in FF/IE */
+ size = "142%";
+ size2 = "107%";
+ ssize = "94%";
+ break;
+ }
+
+ document.getElementsByTagName('body')[0].style.fontSize = size;
+ for (i = 0; (a = document.getElementsByTagName ("td")[i]); i++) a.style.fontSize = size;;
+ for (i = 0; (a = document.getElementsByTagName ("div")[i]); i++) a.style.fontSize = ssize;
+ for (i = 0; (a = document.getElementsByTagName ("option")[i]); i++) a.style.fontSize = ssize;
+ for (i = 0; (a = document.getElementsByTagName ("li")[i]); i++) a.style.fontSize = ssize;
+ for (i = 0; (a = document.getElementsByTagName ("span")[i]); i++) a.style.fontSize = ssize;
+ for (i = 0; (a = document.getElementsByTagName ("select")[i]); i++) a.style.fontSize = ssize;
+ for (i = 0; (a = document.getElementsByTagName ("a")[i]); i++) a.style.fontSize = size2;
+}
+
+
+function sortWordsIgnoreCase(a, b) {
+ a = a.toLowerCase();
+ b = b.toLowerCase();
+ if(a>b) return 1;
+ if(a<b) return -1;
+ return 0;
+}
+
+
+function getSelectedList(sel) {
+ if(!sel) return [];
+ var vals = [];
+ for( var i = 0; i != sel.options.length; i++ ) {
+ if(sel.options[i].selected)
+ vals.push(sel.options[i].value);
+ }
+ return vals;
+}
+
+
+function setEnterFunc(node, func) {
+ if(!(node && func)) return;
+ node.onkeydown = function(evt) {
+ if( userPressedEnter(evt)) func();
+ }
+}
+
+function iterate( arr, callback ) {
+ for( var i = 0; arr && i < arr.length; i++ )
+ callback(arr[i]);
+}
+
+
+
+
+/* taken directly from the JSAN util.date library */
+/* but changed from the util.date.interval_to_seconds invocation,
+because JSAN will assume the whole library is already loaded if
+it sees that, and the staff client uses both this file and the
+JSAN library*/
+function interval_to_seconds( $interval ) {
+
+ $interval = $interval.replace( /and/, ',' );
+ $interval = $interval.replace( /,/, ' ' );
+
+ var $amount = 0;
+ var results = $interval.match( /\s*\+?\s*(\d+)\s*(\w{1})\w*\s*/g);
+ for( var i = 0; i < results.length; i++ ) {
+ if(!results[i]) continue;
+ var result = results[i].match( /\s*\+?\s*(\d+)\s*(\w{1})\w*\s*/ );
+ if (result[2] == 's') $amount += result[1] ;
+ if (result[2] == 'm') $amount += 60 * result[1] ;
+ if (result[2] == 'h') $amount += 60 * 60 * result[1] ;
+ if (result[2] == 'd') $amount += 60 * 60 * 24 * result[1] ;
+ if (result[2] == 'w') $amount += 60 * 60 * 24 * 7 * result[1] ;
+ if (result[2] == 'M') $amount += ((60 * 60 * 24 * 365)/12) * result[1] ;
+ if (result[2] == 'y') $amount += 60 * 60 * 24 * 365 * result[1] ;
+ }
+ return $amount;
+}
+
+
+function openWindow( data ) {
+ if( isXUL() ) {
+ var data = window.escape(
+ '<html><head><title></title></head><body>' + data + '</body></html>');
+
+ xulG.window_open(
+ 'data:text/html,' + data,
+ '',
+ 'chrome,resizable,width=700,height=500');
+
+ } else {
+ win = window.open('','', 'resizable,width=700,height=500,scrollbars=1');
+ win.document.body.innerHTML = data;
+ }
+}
+
+
+/* alerts the innerhtml of the node with the given id */
+function alertId(id) {
+ var node = $(id);
+ if(node) alert(node.innerHTML);
+}
+
+function alertIdText(id, text) {
+ var node = $(id);
+ if(!node) return;
+ if(text)
+ alert(text + '\n\n' + node.innerHTML);
+ else
+ alert(node.innerHTML);
+}
+
+function confirmId(id) {
+ var node = $(id);
+ if(node) return confirm(node.innerHTML);
+}
+
+
+function goBack() { history.back(); }
+function goForward() { history.forward(); }
+
+
+function uniquify(arr) {
+ if(!arr) return [];
+ var newarr = [];
+ for( var i = 0; i < arr.length; i++ ) {
+ var item = arr[i];
+ if( ! grep( newarr, function(x) {return (x == item);}))
+ newarr.push(item);
+ }
+ return newarr;
+}
+
+function contains(arr, item) {
+ for( var i = 0; i < arr.length; i++ )
+ if( arr[i] == item ) return true;
+ return false;
+}
+
+function isTrue(i) {
+ return (i && !(i+'').match(/f/i) );
+}
+
+
+/* builds a JS date object with the given info. The given data
+ has to be valid (e.g. months == 30 is not valid). Returns NULL on
+ invalid date
+ Months are 1-12 (unlike the JS date object)
+ */
+
+function buildDate( year, month, day, hours, minutes, seconds ) {
+
+ if(!year) year = 0;
+ if(!month) month = 1;
+ if(!day) day = 1;
+ if(!hours) hours = 0;
+ if(!minutes) minutes = 0;
+ if(!seconds) seconds = 0;
+
+ var d = new Date(year, month - 1, day, hours, minutes, seconds);
+
+ _debug('created date with ' +
+ (d.getYear() + 1900) +'-'+
+ (d.getMonth() + 1) +'-'+
+ d.getDate()+' '+
+ d.getHours()+':'+
+ d.getMinutes()+':'+
+ d.getSeconds());
+
+
+ if(
+ (d.getYear() + 1900) == year &&
+ d.getMonth() == (month - 1) &&
+ d.getDate() == new Number(day) &&
+ d.getHours() == new Number(hours) &&
+ d.getMinutes() == new Number(minutes) &&
+ d.getSeconds() == new Number(seconds) ) {
+ return d;
+ }
+
+ return null;
+}
+
+function mkYearMonDay(date) {
+ if(!date) date = new Date();
+ var y = date.getYear() + 1900;
+ var m = (date.getMonth() + 1)+'';
+ var d = date.getDate()+'';
+ if(m.length == 1) m = '0'+m;
+ if(d.length == 1) d = '0'+d;
+ return y+'-'+m+'-'+d;
+}
+
+
+function debugFMObject(obj) {
+ if(typeof obj != 'object' ) return obj;
+ _debug("---------------------");
+ var keys = fmclasses[obj.classname];
+ if(!keys) { _debug(formatJSON(js2JSON(obj))); return; }
+
+ keys.sort();
+ for( var i = 0; i < keys.length; i++ ) {
+ var key = keys[i];
+ while( key.length < 12 ) key += ' ';
+ var val = obj[keys[i]]();
+ if( typeof val == 'object' ) {
+ _debug(key+' :=\n');
+ _debugFMObject(val);
+ } else {
+ _debug(key+' = ' +val);
+ }
+
+ }
+ _debug("---------------------");
+}
+
+
+function getTableRows(tbody) {
+ var rows = [];
+ if(!tbody) return rows;
+
+ var children = tbody.childNodes;
+ if(!children) return rows;
+
+ for(var i = 0; i < children.length; i++) {
+ var child = children[i];
+ if(child.nodeName.match(/^tr$/i))
+ rows.push(child);
+ }
+ return rows;
+}
+
+function getObjectKeys(obj) {
+ keys = []
+ for(var k in obj)
+ keys.push(k)
+ return keys;
+}