Initial dev repository
[kcls-web.git] / opac / common / js / utils.js
diff --git a/opac/common/js/utils.js b/opac/common/js/utils.js
new file mode 100644 (file)
index 0000000..aeae80d
--- /dev/null
@@ -0,0 +1,705 @@
+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;
+}