
/*
File: utils.js
A light-weight file containing cross-browser DOM scripting utilities.

To include the latest version,
> <script type="text/javascript" src="/core/lw/1/js/utils.js"></script>

*/
// $Id: utils.js 128346 2008-05-21 17:35:21Z cohenaa $

/*
Group: Helpers

Function: $()
Shortcut for document.getElementById.

If you supply multiple ids as parameter, $() returns an array.

Parameters:
id - (String) The id(s) of the element(s) to return.

Returns:
Element/Array

Example:
> var elems = $('foo','bar');
> // elems is an array with an element whose id="foo" and another element whose id="bar"

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/byid.html>.
*/
function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
}

/*
Function: $AN()
Returns an array of nodes which have attribute names that match supplied attrName argument. 

You can further limit what is returned by supplying a parent node (by default this is 'document') and a tag.

$AN() is not a member of the utils object, so do not call it like this, 
> utils.$AN()

Instead call it like this,
> $AN()

Parameters:
attrName - (String) The name of the attribute of the elements you want to return

atttrNode (Optional) -  By default this is 'document'. You can avoid traversing the entire DOM by supplying a parent
node other than document, if one exists. 

tag (optional) = (String) You can limit by tag name the elements that are returned.

Returns: Array

Example:
(start code)
// returns all p elements with a style attribute in the body of the document
var elems = $AN('style', document.body, 'p');
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/an.html>.
*/
function $AN(attrName, node, tag) {
   var oElements = new Array();
   if (node == null) node = document;
   if (tag == null)tag = '*';
   var els = node.getElementsByTagName(tag);
   for (i = 0; i < els.length; i++) {
      if (els[i].getAttribute(attrName) != null) {
         oElements[oElements.length] = els[i];
      }
   }
   return oElements;
}

// Get elements by AttributeValue for Attributename
// http://www.dustindiaz.com/top-ten-javascript/ (but has some errors)
/*
Function: $C()
Returns an array of nodes by class or another specified attribute. 

This is the getElementByClass method that is missing from the built-in DOM methods.

$C() is not a member of the utils object, so you do not need to call it like this
> utils.$C('foo');

Instead call it like this,
> $C('foo');

Parameters:
attrValue - (String) The the name of the class (or attribute) you want to query. This is the only required argument. By default, if you supply just this attribute, the method returns array of nodes by class. i.e. 
You can supply the attrValue argument with a wildcard ('*') to return any attribute value of a given attribute. i.e.
>$C('*', 'id', document, 'p') //Returns any p tag in document with  an id attribute, with any value.
 
attrName (Optional) - (String) You can supply an attribute name to return an array of elements with that attribute name. i.e.
> $C('foo', 'name') //Returns an array of elements with the attribute 'name' of 'foo'.

node (Optional) - (Node) By default this is 'document'. You can supply a parent node in order to define a range for your query. This allows you to avoid traversing the entire DOM. i.e. 
> $C('foo', 'name', $("containerDiv")); 

tag (Optional) - The tag name of the element you want to return. You can further limit what you return by supplying a tag name. You must supply a node if you want to limit by tag name.

Returns:
Array

Example:
(start code)
//get all elements with class="foo"
var elems = $C('foo');
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getbyclass.html>.

*/
function $C(attrValue, attrName, node, tag) {
    //alert([attrValue, attrName, node, tag])
    if ("*" == attrValue) {
        return $AN(attrName, node, tag);
    }
   var oElements = new Array();
   if (!node) node = document;
   if (!tag) tag = '*';
   if (!attrName) attrName = 'class';
    
   var els = node.getElementsByTagName(tag);
   var elsLen = els.length;
   var pattern = new RegExp("(^|\\s)" + attrValue + "(\\s|$)");
    var j = 0;
   for (i = 0; i < elsLen; i++) {
      if (attrName == "class" && pattern.test(els[i].className)) {
            // IE behavior
            oElements[j++] = els[i];
      } else if (pattern.test(els[i].getAttribute(attrName))) {
         oElements[j++] = els[i];
      }
   }
    return oElements;
}

// gather objects contained into node "node" which tagName is "tag" 
// and which has attribute "attrName"


// Shortcut for getElementsByName
/*
Function: $N()
Returns an array of nodes by name.

You can limit DOM traversal by passing a parent node.

Parameters:
name - (String) The value of the name attribute to return.
node (Optional) - (Node) The parent node.

Example:
(start code)
// get all elements in the head of the document with a name="foo"
var anchors = $N('foo', $('head'));
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/n.html>.
*/
function $N(name, node) {
   var oElements = [];
   if (node == null) node = document;
   var els = node.getElementsByName(name);
   for (i = 0; i < els.length; i++) {
       oElements[oElements.length] = els[i];
   }
   return oElements;
} 
/*
Class: utils
*/

utils = {
/*
******************************************************************
 * Constants
******************************************************************
/* 

Group: Constants

Constant: KeyCode_TAB
Maps to 9

Working Example:
See: <http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/constants.html>
*/
KeyCode_TAB: 9,
/* 
Constant: KeyCode_DELETE
Maps to 46
*/
KeyCode_DELETE: 46,
/* 
Constant: KeyCode_BACKSPACE
Maps to 8
*/
KeyCode_BACKSPACE: 8,
/* 
Constant: KeyCode_LEFT_ARROW
Maps to 37
*/
KeyCode_LEFT_ARROW: 37,
/* 
Constant: KeyCode_RIGHT_ARROW
Maps to 39
*/
KeyCode_RIGHT_ARROW: 39,
/* 
Constant: KeyCode_HOME
Maps to 36
*/
KeyCode_HOME: 36,
/* 
Constant: KeyCode_END
Maps to 35
*/
KeyCode_END: 35,
/* 
Constant: KeyCode_PAGE_UP
Maps to 33
*/
KeyCode_PAGE_UP: 33,
/* 
Constant: KeyCode_PAGE_DOWN
Maps to 34
*/
KeyCode_PAGE_DOWN: 34,
/* 
Constant: KeyCode_UP_ARROW
Maps to 38
*/
KeyCode_UP_ARROW: 38,
/* 
Constant: KeyCode_DOWN_ARROW
Maps to 40
*/
KeyCode_DOWN_ARROW: 40,
/* 
Constant: KeyCode_ESC
Maps to 27
*/
KeyCode_ESC: 27,
/* 
Constant: KeyCode_ENTER
Maps to 13
*/
KeyCode_ENTER: 13,
/* 
Constant: KeyCode_SPACE
Maps to 32
*/
KeyCode_SPACE: 32,
/* 
Constant: KeyCode_SHIFT_KEY
Maps to 16
*/
KeyCode_SHIFT_KEY: 16,
/* 
Constant: KeyCode_CTRL_KEY
Maps to 17
*/
KeyCode_CTRL_KEY: 17,
/* 
Constant: KeyCode_ALT_KEY
Maps to 18
*/
KeyCode_ALT_KEY: 18,
/* 
Constant: KeyCode_LEFT_MS_WINDOWS_KEY
Maps to 91
*/
KeyCode_LEFT_MS_WINDOWS_KEY: 91, 
/* 
Constant: KeyCode_RIGHT_MS_WINDOWS_KEY
Maps to 92
*/
KeyCode_RIGHT_MS_WINDOWS_KEY: 92,
/* 
Constant: KeyCode_MS_MENU_KEY
Maps to 93
*/
KeyCode_MS_MENU_KEY: 93,
    
/*
******************************************************************
Check object properties
******************************************************************
*/
/*
Group: Type Checking

Method: isArray()
Returns boolean whether argument is an array or not

Arguments: 
a - Argument to be tested whether array or not

Syntax:
>utils.isArray(elems) //returns true, if elems is an array

Example:
See: <http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/isarray.html>.
*/
isArray: function(a) { return this.isObject(a) && a.constructor == Array; },
/*
Method: isObject()
Returns whether item is object or not.

Parameters:
a - Item to be tested

Returns:
Boolean

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/isobject.html>.
*/
isObject: function(a) { return (a && typeof a == 'object'); },

/*
Group: Class Manipulation

Method: addClass()
Adds a class to an HTML element.

Does not replace the class, like setting element.className would do. Instead this adds *or appends* a class.

Parameters:
element - (Element) The element to which you add a class attribute
className - (String) The class you add

Example:
(start code)
var elem = $('someId');
// adds 'foo' class to elem
utils.addClass(elem, 'foo');
(end)
*/
addClass: function(element, className) {
    if (!this.hasClass(element, className)) {
        if (element.className) element.className += " " + className;
        else element.className = className;
    }
},

/*
Method: hasClass()
Returns true if an element has passed class, false if not.

Parameters:
element - (Element) The element to test
className - (String) The className to test for

Example:
(start code)
//returns true if elem has a class attribute set to "foo"
utils.hasClass(elem, 'foo');
(end code)
*/
hasClass: function(element, className) {
    var regexp = new RegExp("(^|\\s)" + className + "(\\s|$)");
    return regexp.test(element.className);
},
/*
Method: removeClass()
Removes a class from an HTML element.

Parameters:
element - (Element) The element to which you remove a class attribute
className - (String) The class you remove

Example:
(start code)
var elem = $('someId');
// removes 'foo' class from elem
utils.removeClass(elem, 'foo');
(end)
*/
removeClass: function(element, className) {
    var regexp = new RegExp("(^|\\s)" + className + "(\\s|$)");
    var b = regexp.test(element.className);
    element.className = element.className.replace(regexp, "$2");
    return b;   // true if class has been removed
},

/*
Group: Cookies Processing

Method: createCookie()
Creates a cookie using day expiration instead of millaseconds. 

This is a convenience method that allows you to bypass the standard
document.cookie = name=value; syntax.

Parameters:
name - (String) The name of the cookie you want to create

value - (String) The value of the cookie you want to create

days - (String) The number of days you want to set cookie to expire

path (Optional) - (String) The path in the domain you want your cookie to be accessible from
  
Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/cookies.html>.
*/
createCookie: function(name, value, days, path) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        var expires = '; expires=' + date.toGMTString();
    } else expires = '';
    
    document.cookie = name + '=' + value + expires + '; path=' + (path ? path : "/");
},

// read cookie
/*
Method: readCookie()
Reads the value of a named cookie.
   
Parameters:
name - (String) The name of the cookie you want to read

Working Example:
See the Working Example for <createCookie()>.

*/
readCookie: function(name) {
    var nameEQ = name + '=';
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1, c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
    }
    return "";
},

// erase cookie
/*
Method: eraseCookie()
Erases an existing cookie.

Parameters:
name - (String) The name of the cookie to erase

Working Example:
See working example for <createCookie()>.
*/
eraseCookie: function(name) {
   document.cookie = name + "=null; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=nih.gov; path=/";
   document.cookie = name + "; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=nih.gov; path=/";
},

/*
Group: Debugging

Method: printObj()
Prints contents of object for debugging purposes.

Parameters:
oObj - (Object) The object to inspect.
iLevel - (Integer) The number of indentation spaces.

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/printobj.html>.
*/
printObj: function (oObj, iLevel) {
     var s = "";
     var sIdent = "";
     if (!iLevel) iLevel = 0;
     for (var i = 0; i < iLevel; i++) {
         sIdent += "__";
     }
     for (var i in oObj) {
         var ss = [];
         if ("string" == typeof oObj[i]) {
             ss = oObj[i].split("<");
         }
         s += sIdent + " " + i + " : [" + (typeof oObj[i]) + "] : " + ss.join("&lt;") + "<br/>";
 //        if (oObj[i] && "object" == typeof oObj[i] && iLevel < 2) {
 //            s+= "<br/>-----" + typeof oObj[i] + " --- " + iLevel + "</br>";
 //            s += this.printObj(oObj[i], iLevel + 1); 
 //        }
     }
     return s;
},

/*
Group: Deprecated

Method: drawText()
Deprecated
*/
drawText: function (sText, sId, add) {
    if (!sId) sId = "debug";
    var obj = document.getElementById(sId);
    if (obj) {
        if (add)
            obj.innerHTML = "<br/>" + sText;
        else
            obj.innerHTML += sText;
    }
},

/*
Method: insertInHtml()
Deprecated
*/
insertInHtml: function(text, obj) {
   if (document.all) {
      obj.innerHTML += text;
   } else {
      var range = document.createRange();
      range.setStartAfter(obj);
      var docFrag = range.createContextualFragment(text);
      obj.appendChild(docFrag);
   }
   
},

/*
Method: replaceInHtml()
Deprecated
*/
replaceInHtml: function(text, obj) {
   if (document.all) {
      obj.innerHTML = text;
   } else {
      while (obj.hasChildNodes()) obj.removeChild(obj.firstChild);
      var range = document.createRange();
      range.setStartAfter(obj);
      var docFrag = range.createContextualFragment(text);
      obj.appendChild(docFrag);
   }
},

/*
Group: Events

*/
// a counter used to create unique IDs
addEvent_guid: 1,

/*
Method: addEvent()
Adds a handler function to an object. 

From http://dean.edwards.name/weblog/2005/10/add-event/. Use this instead of either W3C standard addEventListener(), or IE's attachEvent().

Parameters:
element - (Object) The element (or object) you want to attach a handler to.
type - (String) The type of event, minus the 'on' prefix.
handler - (Function) The handler to attach.

Examples:
(start code)
//Run a function after the window (DOM) loads
utils.addEvent(window, 'load', someFunction);

// attach a function to hover event of link
var link = $('someLink');
utils.addEvent(link, 'hover', someFunction);

// attach a function to click event of button, passing a parameter to handler function
utils.addEvent($('btn'), 'click', function(){
    someFunction(someParameter);
});
(end)
*/
addEvent: function (element, type, handler) {
                   
//     console.info("addEvent", element, type)
   // assign each event handler a unique ID
                   
   if (!handler.$$guid) handler.$$guid = this.addEvent_guid++;
//    console.log(handler.$$guid)
   // create a hash table of event types for the element
   if (!element.events) element.events = {};
   // create a hash table of event handlers for each element/event pair
   var handlers = element.events[type];
   if (!handlers) {
      handlers = element.events[type] = {};
      // store the existing event handler (if there is one)
      if (element["on" + type]) {
         handlers[0] = element["on" + type];
      }
   }
   // store the event handler in the hash table
   handlers[handler.$$guid] = handler;
   // assign a global event handler to do all the work
   element["on" + type] = handleEvent;
    
    
    
    function handleEvent(event) {
      var returnValue = true;
      // grab the event object (IE uses a global event object)
      event = event || fixEvent(window.event);
      // get a reference to the hash table of event handlers
      var handlers = this.events[event.type];
      // execute each event handler
      for (var i in handlers) {
         this.$$handleEvent = handlers[i];
         if (this.$$handleEvent(event) === false) {
            returnValue = false;
         }
      }
      return returnValue;
    };
    
    function fixEvent(event) {
      // add W3C standard event methods
      event.preventDefault = fixEvent.preventDefault;
      event.stopPropagation = fixEvent.stopPropagation;
      return event;
    };
    fixEvent.preventDefault = function() {
      this.returnValue = false;
    };
    fixEvent.stopPropagation = function() {
      this.cancelBubble = true;
    };
    
    return handler.$$guid;
},
// begin http://ejohn.org/apps/jselect/event.html
//addEvent: function(obj, type, fn, b) {
//    if (obj.attachEvent) {
//        var name = "" + type + fn; 
//        name = name.substring(0, name.indexOf("\n"));   // IE
//        obj["e" + name] = fn;
//        obj[name] = function(){ obj["e" + name](window.event);}
//        obj.attachEvent("on" + type, obj[name]);
//    } else {
//        obj.addEventListener(type, fn, b);
//        return true;
//    }
//},
//
//
//removeEvent: function(obj, type, fn, b) {
//    if (obj.detachEvent) {
//        var name = "" + type + fn; 
//        name = name.substring(0, name.indexOf("\n"));   //IE
//        if ("function" == typeof obj[name]) {
//            obj.detachEvent("on" + type, obj[name]);
//            obj[name] = null;
//            obj["e" + name] = null;
//        }
//    } else {
//      obj.removeEventListener(type, fn, b);
//      return true;
//    }
//},
// 
//noBubbleEvent: function(e) {
//   if (e && e.stopPropagation) e.stopPropagation();
//   else window.event.cancelBubble = true;
//},
//
// end http://ejohn.org/apps/jselect/event.html

/*
Method: preventDefault()
Prevents default action from occuring on an element.

Parameters:
e - (Object) The event object.

Example:
Prevent a link from being followed.
(start code)
utils.addEvent(link, click, function(e){
   alert('This link was clicked, but not followed');
   utils.preventDefault(e);
});
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/preventdefault.html>.
*/
preventDefault: function(e) {
     if (e.preventDefault) e.preventDefault();
     else window.event.returnValue = false;
},

/*
Method: getRelatedTarget()
Gets element mouse came from for mouseover or element mouse went to for mouseout.

Arguments:
e - (Object)- Implied argument passed from event

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/relatedtarget.html>.
*/
getRelatedTarget: function(e) {
    if (!e) var e = window.event;
   if (e.relatedTarget)    return e.relatedTarget;
   else if (e.toElement)   return e.toElement;
    else if (e.fromElement) return e.fromElement;
},

/*
Method: getTargetObject()
Returns the object that received an event

Parameters:
eEvent - (Object) The event

Returns:
Object

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/gettargetobj.html>.
*/ 
getTargetObj: function(eEvent) {
    var oTarget;
    var e = eEvent || window.event;
    if (e == null) return null;
    if (e.srcElement == null) oTarget = e.target;
    else oTarget = e.srcElement;
    while (oTarget && oTarget.nodeType != 1) oTarget = oTarget.parentNode;
    return oTarget;
},

/*
Method: removeEvent()
Removes event handler from object. 

Parameters:
element - (Object) The object to remove the event from.
type - (String) The event type minus the 'on' prefix.
handler - (Function) The function to remove.

Example:
(start code)
// remove event handler from some element
utils.removeEvent(someElement, 'click', someFunction);
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/removeevent>.
*/
removeEvent: function (element, type, handler) {
   // delete the event handler from the hash table
   if (element.events && element.events[type]) {
      delete element.events[type][handler.$$guid];
        return handler.$$guid;
   }
    return null;
},
// end http://dean.edwards.name/weblog/2005/10/add-event/ 





/*
// begin (2007/03/09) http://www.dustindiaz.com/rock-solid-addevent/
// + some modifications were made by sponomar@ncbi
addEvent: function(obj, type, fn) {
//     console.info(obj, type, fn);
   if (obj.addEventListener) {
      obj.addEventListener(type, fn, false);
      this.x_EventCache.add(obj, type, fn);
   } else if (obj.attachEvent) {
      obj["e" + type + fn] = fn;
      obj[type+fn] = function() { obj["e" + type + fn](window.event); }
      obj.attachEvent( "on" + type, obj[type + fn] );
      this.x_EventCache.add(obj, type, fn);
   } else {
        var old = obj["on" + type];
        if (typeof(old) == "function") {
            obj["on"+type] = function() { old(); fn(); }
        } else {
            obj["on"+type] = fn;
        }
   }
},

removeEvent: function( obj, type, fn ) {
     this.x_EventCache.remove(obj, type, fn);
},

x_EventCache: function(){
   var listEvents = [];
   return {
      listEvents : listEvents,
      add: function(node, sEventName, fHandler){
         listEvents[listEvents.length] = arguments;
      },
        remove: function(node, sEventName, fHandler) {
            var item;
            for(var i = listEvents.length - 1; i >= 0; i--) {
                if(node == listEvents[i][0] && sEventName == listEvents[i][1] && fHandler == listEvents[i][2]) {
                    item = listEvents[i];
                    if(item[0].removeEventListener) {
                        item[0].removeEventListener(item[1], item[2], item[3]);
                        if (window.opera) continue;
                    } 
                    if(item[1].substring(0, 2) != "on") {
                        item[1] = "on" + item[1];
                    }
                    if(item[0].detachEvent) {
                        item[0].detachEvent(item[1], item[0][sEventName + fHandler]);
                    } 
                    item[0][item[1]] = null;
                }
            }
        },
      flush: function(){
         var item;
         for(var i = listEvents.length - 1; i >= 0; i--){
            item = listEvents[i];
            if(item[0].removeEventListener){
               item[0].removeEventListener(item[1], item[2], item[3]);
            } 
                if(item[1].substring(0, 2) != "on"){
               item[1] = "on" + item[1];
            } 
                if(item[0].detachEvent){
               item[0].detachEvent(item[1], item[2]);
            };
            item[0][item[1]] = null;
         };
      }
   };
}(),
*/
// end http://www.dustindiaz.com/rock-solid-addevent/



/*
Group: Geometry

Method: getPageDim()
Returns an object representing height and width of total page, not just viewable page. This is usually the entire
body element.

Parameters:
None

Example:
(start code)
//get height of entire page
var h = utils.getPageDim().h;
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getpagedim.html>.
*/

getPageDim: function() {
    // http://www.quirksmode.org/viewport/compatibility.html
    var dim = {w:0, h:0};
    var test1 = parseInt(document.body.scrollHeight);
    var test2 = parseInt(document.body.offsetHeight)
    if (test1 > test2) { // all but Explorer Mac
      dim.w = parseInt(document.body.scrollWidth);
      dim.h = test1;
    } else {// Explorer Mac;
         //would also work in Explorer 6 Strict, Mozilla and Safari
      dim.w = parseInt(document.body.offsetWidth);
      dim.h = test2;
    }
    return dim;
},

/*
Method: getScrolls()
Returns an object representing horizontal and vertical scroll in pixels of the window.

Parameters:
None

Example: 
(start code)
//get vertical scroll
vertScroll = utils.getScrolls().y;
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getscrolls.html>
*/
getScrolls: function() {
     // http://www.quirksmode.org/viewport/compatibility.html
     var dim = {x:0, y:0};
     if (self.pageYOffset) { // all except Explorer
         dim.x = self.pageXOffset;
         dim.y = self.pageYOffset;
     } else if (document.documentElement /* && document.documentElement.scrollTop */) {
         // Explorer 6 Strict
         dim.x = document.documentElement.scrollLeft;
         dim.y = document.documentElement.scrollTop;
     } else if (document.body) { // all other Explorers
         dim.x = document.body.scrollLeft;
         dim.y = document.body.scrollTop;
     }
     dim.x = parseInt(dim.x);
     dim.y = parseInt(dim.y);
     return dim;
},

/*
Method: getWindowDim() 
Returns an object representing inside dimensions of window.

Getting window dimensions is very browser depenendent. This method should work across different browsers.

Parameters:
None

Example:
(start code)
//get the height of the window
var h = utils.getWindowDim().h;
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getwindowdim.html>.
*/
getWindowDim: function() {
    // http://www.quirksmode.org/viewport/compatibility.html
    var dim = {w:0, h:0};
    if (self.innerHeight) { // all except Explorer
      dim.w = self.innerWidth;
      dim.h = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      // Explorer 6 Strict Mode
      dim.w = document.documentElement.clientWidth;
      dim.h = document.documentElement.clientHeight;
    } else if (document.body) {// other Explorers
      dim.w = document.body.clientWidth;
      dim.h = document.body.clientHeight;
    }
    dim.w = parseInt(dim.w);
    dim.h = parseInt(dim.h);
    return dim;
},

/*
Method: getXY()
Returns an object representing the x, y coordinates and height and width of passed element.

Parameters: 
obj - (Element) The object whose coordinates you want to get

Example:
(start code)
var elem = $('someId');
var pos = utils.getXY(elem);
window.scrollTo(pos.x, pos.y);
(end code)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getxy.html>
*/
getXY: function (obj){
     /*
     +------------- w ----
     | (x,y)
     |
     h
     |
     */
     
     var b = {x:0, y:0, w:obj.offsetWidth, h:obj.offsetHeight};
     
     if (obj.offsetParent) {
         while(obj) {
             b.x += obj.offsetLeft;
             b.y += obj.offsetTop;
             obj = obj.offsetParent;
         }
     } else if (obj.x) {
         b.x = obj.x;
         b.y = obj.y;
     }
     return b;
},
/*
Group: Node Manipulation

Method: insertAfter()
Inserts a node into the document tree after a specified node. This is useful because there is no built-in JavaScript insertAfter method.

Parameters:
parent - (Element) The parent node of the node you are inserting

node - (Element) The node you are inserting

referenceNode - (Element) The node after which you are inserting the node

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/insertafter.html>.
*/
insertAfter: function(parent, node, referenceNode) {
   parent.insertBefore(node, referenceNode.nextSibling);
},

/*
Method: moveAfter()
Moves a node after another one

Parameters:
item1 - (Node) The node to move
item2 - (Node) The reference node

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/moveafter.html>.
*/
moveAfter: function(item1, item2) {
    var parent = item1.parentNode;
    parent.removeChild(item1);
    parent.insertBefore(item1, item2 ? item2.nextSibling : null);
},

/*
Method: moveBefore()
Moves a node before another one

Parameters:
item1 - (Node) The node to move
item2 - (Node) The reference node

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/movebefore.html>.
*/
moveBefore: function(item1, item2) {
    var parent = item1.parentNode;
    parent.removeChild(item1);
    parent.insertBefore(item1, item2);
},

/*
Method: removeChildren()
Removes the children nodes of passed node

Parameters:
oObj - The node whose children you want to remove

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/removechildren.html>.
*/  
removeChildren: function(oObj) {
     if (!oObj || typeof oObj != "object") return;
     while(oObj.hasChildNodes()) oObj.removeChild(oObj.firstChild);
},


removeAllChildren: function(oObj) {
     if (!oObj || typeof oObj != "object") return;
     while(oObj && oObj.hasChildNodes()) {
         this.removeAllChildren(oObj.firstChild);
         oObj.removeChild(oObj.firstChild);
     }
},

/*
Group: Node Querying

Method: getFirstChild()
Returns the first-child element of a node. 

This is different than the built-in JavaScript firstChild property, in that it gets the firstChild that is an *element*. This is useful because a firstChild could also be a  text node or white-space.

Parameters:
obj - (Element) The element for which you want to get the firstChild element.

Returns:
Element

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getfirstchild.html>.
*/  
getFirstChild: function(obj) {
     if (obj) {
         var result = obj.firstChild;
         while (result && result.nodeType != 1) result = result.nextSibling;
         if (result) return result;
     }
     return null;
},

/*
Method: getNextSibling()
Gets the next element sibling of passed element.

Parameters:
obj - (Element) The element for which you want to get the next element sibling
tagName (optional) - (String) Supply a tagName to filter results

Returns:
Element

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getnextsibling.html>.
*/   
getNextSibling: function(obj, tagName) {
    if (obj) {
        var result = obj.nextSibling;    
        if (tagName) {
            var tn = tagName.toUpperCase();
            while (result && result.tagName != tn) result = result.nextSibling;
        } else {
            while (result && result.nodeType != 1) result = result.nextSibling;
        }
        return result;
    }
    return null;
},

/*
Method: getParent()

Description:
Returns the parent element of a node. 

This is different than the built-in JavaScript parentNode method, in that it gets the parent that is an *element*. This is useful because a parent can also be a  text node (including white-space).

Parameters:
obj - The object for which you want to get the parent.

Returns:
Element

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getparent.html>.
*/
getParent: function(obj) {
     if (obj) {
         var result = obj.parentNode;
         while (result && result.nodeType != 1) result = result.nextSibling;
         if (result) return result;
     }
     return null;
},


/*
Method: getPreviousSibling()
Gets the previous element sibling of passed element.

Parameters:
obj - (Element) The element for which you want to get the previous element sibling
tagName (optional) - (String) Supply a tagName to filter results

Returns:
Element

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getprevioussibling.html>.
*/
getPreviousSibling: function(obj, tagName) {    
     if (obj) {
         var result = obj.previousSibling;    
         if (tagName) {
             var tn = tagName.toUpperCase();
             while (result && result.tagName != tn) result = result.previousSibling;
         } else {
             while (result && result.nodeType != 1) result = result.previousSibling;
         }
         return result;
     }
     return null;
},
/*
Method: nextItem()
Gets the next node of a particular node name

Parameters:
item - (Element) The start element
nodeName - (String) The nodeName of the next item you want to get (ie #comment, #text etc.)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/nextitem.html>.
 */ 
nextItem: function(item, nodeName) {
    if (item == null) return null;
    var next = item.nextSibling;
    while (next != null) {
        if (next.nodeName == nodeName) return next;
        next = next.nextSibling;
    }
    return null;
},
/*
Method: previousItem()
Gets the previous node of a particular node name

Parameters:
item - (Element) The item to start from
nodeName - (String) The nodeName of the next item you want to get (ie #comment, #text etc.)

Working Example:
See <nextItem>'s Working Example: <http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/nextitem.html>.
*/
previousItem: function(item, nodeName) {
    var previous = item.previousSibling;
    while (previous != null) {
        if (previous.nodeName == nodeName) return previous;
        previous = previous.previousSibling;
    }
    return null
},

/*
Group: Style Querying

Method: getBorders()
Returns object representing thickness of passed element's borders.

The returned object also has an isInner property which represents whether the currentStyle property exists. If the currentStyle  property exists, we know we are using the IE client. This is useful because in quirks mode, IE includes margins, padding, and borders in its calculation of the total width of an element. Thus in IE, elements with a declared width will often be rendered more narrow than in other browsers.

oObj - (Element) The element whose borders to get.

Example:
(start code)
var el = $('someElement');
var leftBorder = utils.getBorders(el).l;
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getborders.html>.
*/

getBorders: function(oObj) {
     var res = {t:0, b:0, l:0, r:0, isInner:false};
     res.t = this.getStyle(oObj, "borderTopWidth");
     if (typeof(res.t) == "string" && res.t != "") {        //IE, Firefox
         res.b = this.getStyle(oObj, "borderBottomWidth");
         res.l = this.getStyle(oObj, "borderLeftWidth");
         res.r = this.getStyle(oObj, "borderRightWidth");
     } else {
         res.t = this.getStyle(oObj, "border-top-width");   //Firefox, Opera
         res.b = this.getStyle(oObj, "border-bottom-width");
         res.l = this.getStyle(oObj, "border-left-width");
         res.r = this.getStyle(oObj, "border-right-width");
     }
     
     if (oObj.currentStyle) {
         res.isInner = true;
     }
     return res;
},

// Get thickness of object's paddings
/*
Method: getPaddings()
Returns an object with the top, right, bottom, left (t,r,b,l) thickness of an element's padding in pixels. 

Object also has an isInner property, which represents whether the element is being rendered in Microsoft Internet Explorer (IE6) or not. The isIe property is useful because in quirks mode, IE includes margins, padding, and borders in its calculation of the total width of an element.  Thus in IE, elements with a declared width will often be rendered more narrow than in other browsers.

Arguments:
oObj - (Element) The element whose paddings to return

Example:
(start code)
//get top padding of element
var el = $('aPara');
var topPadding = utils.getPaddings(el).t;
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getpaddings.html>
*/
getPaddings: function(oObj) {
     var res = {t:0, b:0, l:0, r:0, isInner:false};
     res.t = this.getStyle(oObj, "paddingTop");
     if (typeof(res.t) == "string" && res.t != "") {    //IE, Firefox
         res.b = this.getStyle(oObj, "paddingBottom");
         res.l = this.getStyle(oObj, "paddingLeft");
         res.r = this.getStyle(oObj, "paddingRight");
     } else {
         res.t = this.getStyle(oObj, "padding-top");    //Firefox, Opera
         res.b = this.getStyle(oObj, "padding-bottom");
         res.l = this.getStyle(oObj, "padding-left");
         res.r = this.getStyle(oObj, "padding-right");
     }
     
     if (oObj.currentStyle) {
         res.isInner = true;
     }
     return res;
},



// get current style of object
/*
Method: getStyle()
Returns the style of passed property.

Tries to get accurate style of element taking into account cascade from in-page and external stylesheet, not just inline or javascript-set styles.

Parameters:
oObj - (Element) The element whose style to return
styleProp - (String) The CSS property to return   

Example:
(start code)
var para = $('myPara');
var color = utils.getStyle(para, 'color');
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getstyle.html>.
*/
getStyle: function (oObj, styleProp) {
    var res;
    if (oObj.currentStyle) {    //IE
      res = oObj.currentStyle[styleProp];
    }
    if (typeof(res) != "string") {
        if (oObj.style) { //Firefox, Opera
            res =  oObj.style[styleProp];
        }
        if (typeof(res) != "string") {
            if (document.defaultView) { // Safary
                res = document.defaultView.getComputedStyle(oObj, null).getPropertyValue(styleProp);
            }
            if (typeof(res) != "string") {
                return null;
            }
        }
    }
    return res;
},

/*
Group: Text Processing

Method: getSelection()
Gets text selected by keyboard or mouse.

Parameters:
None

Example:
(start code)
// given that user has some text selected in window
var selected = utils.getSelection();
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/getselection.html>.
*/
getSelection: function() {
     var text = "";
     if (window.getSelection) {  
         text += window.getSelection();
     } else if (document.getSelection) {  
         text += document.getSelection();
     } else if (document.selection){        //IE
         text += document.selection.createRange().text;
     }
     return text;
},

/*
Method: selectRange()
Selects text on page.

Parameters:
oObj - (Element) The parent element of the text to select
iStart - (Integer) The index position to start selection
iLength - (Integer) The length of selection 

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/selectrange.html>.
*/
selectRange: function (oObj, iStart, iLength) {
    if (!(oObj && oObj.value)) return;
    
    if (oObj.createTextRange) {
        //use text ranges for Internet Explorer
        var oRange = oObj.createTextRange(); 
        oRange.moveStart("character", iStart); 
        oRange.moveEnd("character", iLength - oObj.value.length);      
        oRange.select();
    } else if (oObj.setSelectionRange) {
        //use setSelectionRange() for Mozilla
        oObj.setSelectionRange(iStart, iLength);
    }     
    //set focus back to the textbox
    oObj.focus();      
},

/*
******************************************************************
For debug purposes @@@@@@@ obsolete @@@@@@@
******************************************************************
*/



/*
Class: jsLoader
Loads JavaScripts from other JavaScript files. 

This is useful because you can load related scripts only when needed. If scriptA needs a component from script b, you can load script b from script a.  

jsLoader is an object acting as a class. You will need to set one of its properties (sBase) and call its method (load). 

Working Example:
Four files are used in this example. 
- index.html
- morning.js
- noon.js 
- eve.js

morning.js has a function that alerts the greeting, "Good Morning." Let's assume that if you say "Good Morning," you may want to also say other greetings for different parts of the day. You can then load noon.js and eve.js from morning.js. To do this, 

- In index.html link to utils.js and to morning.js.
- In index.html set utils.jsLoader.sBase to the path where your javascript files are
- In morning.js, call,
> utils.jsLoader.load(["noon.js","eve.js"])

See, <http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/jsloader/>.
*/

jsLoader:  {
    oLoaded: [],
    /*
    Property: sBase
    (String) Represents path to JavaScript file to load. Defaults to current directory from where jsLoader.load() is called.
    */
    sBase:"",
    /*
    Method: load()
    Does the actual work of loading scripts from other scripts

    Parameters:
    aScripts - (Array) JavaScript files to load.
    */
    load: function (aScripts) {
        var oS = document.getElementsByTagName("script");
        for (var j = 0; j < oS.length; j++) {
            if (oS[j].src == "") continue;
            this.oLoaded.push(oS[j].src);
        }

        
        var sHost = document.location.protocol + "/" + "/" + document.location.host;
        var sPath = document.location.pathname;
        sPath = sPath.substring(0, sPath.lastIndexOf("/")) + "/";

        var oHead = document.getElementsByTagName("head")[0];
        for (var i = 0; i < aScripts.length; i++) {
            var sNewSrc = this.sBase + aScripts[i];
            if (sNewSrc.indexOf(":/" + "/") == -1) {
                if (sNewSrc.indexOf("/") == 0) {
                    sNewSrc = sHost + sNewSrc;
                } else {
                    sNewSrc = sHost + sPath + sNewSrc;
                }
            }

            var oS = document.getElementsByTagName("script");
            var b = true;
            for (var j = 0; j < this.oLoaded.length; j++) {
                if (sNewSrc == this.oLoaded[j]) {
//                    alert(sNewSrc + " : loaded yet");
                    b = false;
                }
            }

            if (b) {
                document.write("<script src='" + sNewSrc + "' type='text/javascript'></script>");
//                alert(sNewSrc)
                this.oLoaded.push(sNewSrc);
            }
        }
    }
}
}; //end ncbi.base.utils object
/*
******************************************************************
 Extensions
******************************************************************
*/

/*
Class: String
Extensions to core JavaScript String Class

Method: trimSpaces()
Trims leading and/or trailing spaces from a string

Parameters:
trimMode (Optional) - (Int) How to trim spaces. 0, trim leading and trailing; 1, trim leading only; 2, trim trailing only. Defaults to 0.

Example:
(start code)
//trim all spaces from string
var str = "  hello world    ";
str.trimSpaces();
(end)

Working Example:
<http://intrawebdev.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/trimspaces>.
*/
String.prototype.trimSpaces = function(trimMode) {
    // 0 = trim begin and end
    // 1 = trim begin only
    // 2 = trim after only

    var targetString = this;
    var iPos = 0;
    if (!trimMode) trimMode = 0;
    
    if (trimMode==0 || trimMode==1) {
        if (targetString.charAt(iPos)==" ") {
            while(targetString.charAt(iPos)==" ") iPos++;
            targetString = targetString.substr(iPos);
        }
    }

    iPos = targetString.length-1;
    if (trimMode==0 || trimMode==2) {
        if (targetString.charAt(iPos) == " ") {
            while(targetString.charAt(iPos) == " ") iPos--;
            targetString = targetString.substr(0, iPos + 1);
        }
    }
    return targetString;
}


/*
//
// Update Array class to JS 1.5 if not yet there.
// TODO: Add push pop shift unshift
//
if (!Array.prototype.push) 
    Array.prototype.push = function(o) {
        this[this.length] = o;
    }

if (!Array.prototype.pop)
    Array.prototype.pop = function () {
        if (this.length > 0) {
            delete this[this.length - 1];
            this.length--;
        }
    }


// array-like enumeration
if (!Array.forEach) // mozilla already supports this
    Array.forEach = function(object, block, context) {
        for (var i = 0; i < object.length; i++) {
            block.call(context, object[i], i, object);
        }
    };

if (!Array.prototype.indexOf)
    Array.prototype.indexOf = function(item, startIndex) {
        var len = this.length;
        if (startIndex == null)
            startIndex = 0;
        else if (startIndex < 0) {
            startIndex += len;
            if (startIndex < 0)
                startIndex = 0;
        }
        for (var i = startIndex; i < len; i++) {
            var val = this[i] || this.charAt && this.charAt(i);
            if (val == item)
                return i;
        }
        return -1;
    };

if (!Array.prototype.lastIndexOf)
    Array.prototype.lastIndexOf = function(item, startIndex) {
        var len = this.length;
        if (startIndex == null || startIndex >= len)
            startIndex = len - 1;
        else if (startIndex < 0)
            startIndex += len;
        for (var i = startIndex; i >= 0; i--) {
            var val = this[i] || this.charAt && this.charAt(i);
            if (val == item)
                return i;
        }
        return -1;
    };

if (!Array.prototype.map)
    Array.prototype.map = function(func, thisVal) {
        var len = this.length;
        var ret = new Array(len);
        for (var i = 0; i < len; i++)
            ret[i] = func.call(thisVal, this[i] || this.charAt && this.charAt(i), i, this);
        return ret;
    };

if (!Array.prototype.filter)
    Array.prototype.filter = function(func, thisVal) {
        var len = this.length;
        var ret = new Array();
        for (var i = 0; i < len; i++) {
            var val = this[i] || this.charAt && this.charAt(i);
            if(func.call(thisVal, val, i, this))
                ret[ret.length] = val;
        }
        return ret;
    };

if (!Array.prototype.every)
    Array.prototype.every = function(func, thisVal) {
     var len = this.length;
     for (var i = 0; i < len; i++)
        if (!func.call(thisVal, this[i] || this.charAt && this.charAt(i), i, this))
            return false;
     return true;
    };

if (!Array.prototype.some)
    Array.prototype.some = function(func, thisVal) {
        var len = this.length;
        for (var i = 0; i < len; i++)
            if (func.call(thisVal, this[i] || this.charAt && this.charAt(i), i, this))
                return true;
        return false;
    };
    
    
  Array.prototype.size = function() {
  var i = 0;
  for (var j in this) {
    if (this.propertyIsEnumerable(j)) {
      i++;
    }
  }
  return i;
}
*/
