
var selectBoxRelations = Array();

/**
    Called when the user types in the text box

    If the user hit enter, and the select box shows, the selectbox closes,
    and nothing else happens.

    By default, the select box shows as soon as the user starts typing.

*/
function checkKeyOnKeyDownTextBox(field,evt) {
    var selectBoxObj = document.getElementById(field.id+"_selectBox");
      var keyCode =
        document.layers ? evt.which :
        document.all ? event.keyCode :
        document.getElementById ? evt.keyCode : 0;

     switch (keyCode){

          case 13:

                // if the user pressed enter, and the drop down box
                // is opened, just close it, do not submit the page
                if (selectBoxObj.style.display != 'none'){
                    selectBoxObj.style.display = 'none';
                    return false;
                }
                break;
         default:
             if (selectBoxObj.style.display == 'none'){
                  selectBoxObj.style.display = '';
            }


     }


     return true;

}

/**

Called on key up event of the textbox.

If the user presses up/down arrows, transfers the focus to the select box.

*/
function checkArrowsTextBox (field, evt) {

      var selectBoxObj = document.getElementById(field.id+"_selectBox");
      var keyCode =
        document.layers ? evt.which :
        document.all ? event.keyCode :
        document.getElementById ? evt.keyCode : 0;

     field.lastKeyCode = keyCode;

          switch (keyCode){
              case 39:
                    // arrow right
              case 37:
                    // arrow left
              case 35:
                    // home
              case 36:
                    // end
              case 16:
                    // shift
              //case 17:
                    // control
              case 91:
                    // windows
                return false;
                break;
              case 40:
              case 38:
                // arrow down;
                // arrow up;
                selectBoxObj.focus();
                return false;
                break;
              default:
              //alert(keyCode);


          }

      return true;
    }

    /**
        Called when the user presses down on a key on the dropdown.

        If the user presses the left/right keyboard arrows, the textbox gets focus.

    */
   function checkArrowsSelectBox (field, evt) {
      var myId = field.id;
      myparentFieldId = myId.replace("_selectBox","");

      var fieldObj = document.getElementById(myparentFieldId);

      if (fieldObj == null){
          alert("Could not determine original text field");
      }

      var keyCode =
        document.layers ? evt.which :
        document.all ? event.keyCode :
        document.getElementById ? evt.keyCode : 0;

     field.lastKeyCode = keyCode;

          switch (keyCode){
              case 40:
                // arrow down;
                break;
              case 38:
                // arrow up
                break;
              case 37:
              case 39:
              case 8:
                 fieldObj.focus();
                 break;
              case 13:
                field.style.display = "none";
                fieldObj.focus();
                return false;
                break;

              default:

          }


      return true;
    }

/**

    MAGIC, this is the guts of the typeahead functionlality ...

    This function loops through the form items in the page, and for every textfield with
    an attribute of "typeAheadType", it will replace the textbox dynamically with a select box.

    The textbox stays on the page, but it's name, id and onchange event is moved to a new
    selectbox that is added dynamically. It is also tranffered into a dynamically created
    div, so the dropdown will show below the textbox.

    The selectbox is queried, and gets populated with the id based on the value of the textbox,

    The textbox in turn gets populated with the value of the drop down ( the human readable version
    of the id).

    This function can be called multiple times safely, it will always replace
    only newly added items (with a javascript for example).

    So creating a new dropdowns involves the following:

    1. creation of the SQL query for the dropdown in the ajax -> process.php page.
    2. specifying a textbox for the page, either in HTML, or in Javascript, specifying
       the typeAheadType attribute with the case name from the process.php page.
    3. Add any filters (filterBySelects / filterByString)

       filterBySelects - a list of select box Id's delimited by !
                        The list can be regular as well as 'special' textboxes.


       filterByString - a string such as "province = 'AB' AND date > 'xxxx-yy-mm' "
                        this string gets appeneded in the where clause.

    4. call the prepareTypeAheads function, with no parameters, the script will take
        care of the rest, including disabling autocomplete from the browser, manage the
        relationships between dropdowns (filter by parent selects specified in the filter),
        etc ..

*/
function prepareTypeAheads() {
        var forms = document.forms.length;
        var objParent;
        var wrapperDiv = document.createElement("DIV");
        var clonedDiv;
        var selectBox = document.createElement("SELECT");
        var imageProgress = document.createElement("IMG");
        var selectBoxClone;
        var tmpInputBox = document.createElement("INPUT");

        imageProgress.src = "/lib/ajax/images/spinner.gif";
        imageProgress.style.paddingLeft = "5px";
        imageProgress.style.verticalAlign = "middle";
        imageProgress.style.display = "none";
        wrapperDiv.style.display = "inline";

        selectBox.multiple = true;
        selectBox.size = 10;
        // can't tab to the dropdown
        selectBox.tabIndex = -1;
        selectBox.backGroundcolor = '#fff';

        // add an emptry item, this causes the dropdown to show on the process page, otherwise
        // if there are no items, the select does not show.
        addOption(selectBox,'','');

        for (var formCounter = 0; formCounter < forms; formCounter++) {
            var currentForm = document.forms[formCounter];
            var maxsize = currentForm.elements.length;


        	for (var counter=0;counter<maxsize;counter++){
        	        var formFieldObj = document.forms[formCounter].elements[counter];
        	        if (("TEXT" == formFieldObj.type.toUpperCase()) && (formFieldObj.getAttribute("typeAheadType") != null) && (formFieldObj.getAttribute("typeAheadType") != '')){
        	            objParent = formFieldObj.parentNode;


        	            var parentItems = formFieldObj.getAttribute("filterBySelects");

        	            if (parentItems != null && parentItems!=''){
         	               var parentIemsSelects = parentItems.split("!");

        	               for (var parentsCounter = 0; parentsCounter < parentIemsSelects.length; parentsCounter++)
        	               {

        	                   currentParentRelation = parentIemsSelects[parentsCounter].split("=");

        	                   var parentId = currentParentRelation[1];

        	                   if (document.getElementById(parentId) == null) {
        	                       alert("Could not set parent "+parentId+" for "+formFieldObj.id+" aborting process");
        	                       return;
        	                   }

        	                   if (typeof(selectBoxRelations[parentId]) == "undefined"){
        	                       selectBoxRelations[parentId] = Array();
        	                   }

        	                   selectBoxRelations[parentId][selectBoxRelations[parentId].length] = formFieldObj.id;
        	                   //if (selectBoxRelations[parentId])
        	               }
        	            }

        	            objParent.replaceChild(tmpInputBox,formFieldObj);


        	            selectBoxClone = selectBox.cloneNode(true);

        	            selectBoxClone.name = formFieldObj.name;
        	            selectBoxClone.id = formFieldObj.id + "_selectBox";


        	            if (typeof(formFieldObj.onchange) == 'undefined' || typeof(formFieldObj.onchange) == 'object'){
        	                formFieldObj.onchange = function(){};
        	            }

        	            selectBoxClone.originalOnchange = formFieldObj.onchange;

        	            formFieldObj.onchange = function(){};

        	            // on focus of the select box, we need to show it, and give it focus in 100ms, because the onblur event
        	            // of the textbox makes it diespear.
        	            eval("selectBoxClone.onfocus = function(){\
        	                                                   if (document.getElementById('"+selectBoxClone.id+"').style.display=='none'){\
        	                                                       document.getElementById('"+selectBoxClone.id+"').style.display='';\
        	                                                       setTimeout(\"showSelectBoxDelayed('"+selectBoxClone.id+"');\",5);\
        	                                                   }\
        	                                                   }");
        	            eval ("selectBoxClone.onclick = function(){\
        	                                                   var formSelectObj = document.getElementById('"+selectBoxClone.id+"');\
            	                                               if (formSelectObj.selectedIndex > -1){\
            	                                                   return onClickOption('"+formFieldObj.id+"','"+selectBoxClone.id+"',formSelectObj.selectedIndex,true);\
            	                                               }\
        	                                                   }");
        	            eval("selectBoxClone.onblur = function(){\
        	                                                   document.getElementById('"+selectBoxClone.id+"').style.display='none';\
        	                                                   }");

        	            eval("selectBoxClone.onchange = function(event){\
        	                                               var formSelectObj = document.getElementById('"+selectBoxClone.id+"');\
        	                                               clearChildren('"+selectBoxClone.id+"');\
        	                                               if (formSelectObj.selectedIndex > -1){\
        	                                                   return onClickOption('"+formFieldObj.id+"','"+selectBoxClone.id+"',formSelectObj.selectedIndex,false);\
        	                                               }\
        	                                           }");


        	            eval("selectBoxClone.onkeydown = function (event){\
        	                                               var formSelectObj = document.getElementById('"+selectBoxClone.id+"');\
        	                                               return checkArrowsSelectBox(formSelectObj,event);\
        	                                           }");
        	            formFieldObj.name = "";
        	            formFieldObj.setAttribute("autocomplete","off");

//        	            eval("formFieldObj.onfocus =  function(){\
//        	                                               var selectBoxObj = document.getElementById('"+selectBoxClone.id+"');\
//        	                                               if (typeof(selectBoxObj.lastKeyCode) =='undefined' || selectBoxObj.lastKeyCode!=13){\
//        	                                                   selectBoxObj.style.display='block';\
//        	                                               } else {\
//        	                                                   selectBoxObj.lastKeyCode = '';\
//        	                                               }\
//        	                                          }");
        	            eval("formFieldObj.onblur =  function(){\
        	                                               var selectBoxObj = document.getElementById('"+selectBoxClone.id+"');\
        	                                               if (typeof(document.activeElement) == 'undefined') {\
        	                                                       selectBoxObj.style.display='none';\
        	                                               } else {\
        	                                                   setTimeout(\"hideSelectBoxIfNotInFocus('"+selectBoxClone.id+"');\",100);\
        	                                               }\
        	                                           }");

        	            eval("formFieldObj.onkeydown = function (event){\
        	                                                   var selectBoxObj = document.getElementById('"+selectBoxClone.id+"');\
        	                                                   var formInputObj = document.getElementById('"+formFieldObj.id+"');\
        	                                                   \
        	                                                   if (typeof(formInputObj.delayedQueryTimer)!='undefined' && formInputObj.delayedQueryTimer!=null){\
            	                                                   clearTimeout(formInputObj.delayedQueryTimer);\
            	                                                   formInputObj.delayedQueryTimer = null;\
            	                                               }\
        	                                                   return checkKeyOnKeyDownTextBox(formInputObj,event);\
        	                                                   }");

        	            eval("formFieldObj.onkeyup = function (event){\
        	                                               var formInputObj = document.getElementById('"+formFieldObj.id+"');\
        	                                               var formSelectObj = document.getElementById('"+selectBoxClone.id+"');\
                                                            \
                                                           keyResult = checkArrowsTextBox(formInputObj,event);\
        	                                               if (keyResult){\
        	                                                   formInputObj.delayedQueryTimer = setTimeout(\"querydb('"+formFieldObj.id+"',false);\",500);\
        	                                               }\
        	                                               return keyResult;\
        	                                           }");


                        clonedDiv = wrapperDiv.cloneNode(true);

                        imageClone = imageProgress.cloneNode(true);
                        imageClone.id = formFieldObj.id + "_processImage";


                        clonedDiv.appendChild(formFieldObj);
                        clonedDiv.appendChild(imageClone);
                        clonedDiv.appendChild(selectBoxClone);

                        objParent.replaceChild(clonedDiv,tmpInputBox);


                        clonedDiv.style.width = "100%";


//                        formFieldObj.style.position = "absolute";
//                        formFieldObj.style.top = "0px";
//                        formFieldObj.style.left = "0px";
//
                        selectBoxClone.style.position = "absolute";
                        selectBoxClone.style.zIndex = 1000;
                        selectBoxClone.style.display = "none";
                        selectBoxClone.style.top = Position.get(formFieldObj).top + Position.get(formFieldObj).height + "px";
                        selectBoxClone.style.left = Position.get(formFieldObj).left + "px";
                        //selectBoxClone.style.width = Position.get(formFieldObj).width + "px";
                        if (Position.get(formFieldObj).width < 300){
                            selectBoxClone.style.width = (Position.get(formFieldObj).width *3) + "px";
                        } else {
                            selectBoxClone.style.width = (Position.get(formFieldObj).width) + "px";
                        }

                        formFieldObj.setAttribute("originalWidth",Position.get(formFieldObj).width);
                        formFieldObj.setAttribute("typeAheadTypeDbName",formFieldObj.getAttribute("typeAheadType"));
                        formFieldObj.setAttribute("typeAheadType",'');
                        formFieldObj.style.zIndex = 1;

                        selectBoxClone.selectedIndex = 0;
                        if (formFieldObj.value!=''){
                            // populate the value, ignore parent filter relation
                            // could be that the parent is not set yet.
                            // but check first :-) if the parent does exist, and set as
                            // a drop down, do not ignore ...
                            // unless explicitly requested by setting "forceRelation"


                            if (formFieldObj.getAttribute("forceRelation") != null){
                                querydb(formFieldObj.id,false,true);
                            } else {
                                querydb(formFieldObj.id,true,true);
                            }


                        }

        			}


            }



        }

        enableDisableAll();
    }


/*
    Executed only when IE, returns focus to the dropdown when the user
    moves between the textbox, and the select box (otherwise the selectbox will
    disappear the moment the focus moved from the textbox.

    Also hides the selectbox if the user did not mean to move to the select box from
    the text box.
*/
 function hideSelectBoxIfNotInFocus(selectBoxId)
 {

      var selectObj = document.getElementById(selectBoxId);

      if (typeof(document.activeElement) == "undefined") {
           // not defined in FF, but FF will show the dropdown properly if it gets focus
          selectObj.style.display="none";
      } else if (selectObj != document.activeElement ){
            selectObj.style.display="none";
      }
 }

 /**

 Being called by a delay to show the selectbox after a textbox loses focus.

 */
 function showSelectBoxDelayed(selectBoxId)
 {

     document.getElementById(selectBoxId).style.display = "";
     document.getElementById(selectBoxId).focus();
 }

/**
    Query the database for the select box.

    fieldID is the text field id

    ignoreParent is used in a special case, where there is a value when the page
    loads, in which case, we need to ignore the parent relationship, and try to populate anyway
    since the parent might not be loaded yet ...

*/
function querydb(fieldId,ignoreParent,exact){

        var fieldObj = document.getElementById(fieldId);
        var selectObj = document.getElementById(fieldId + "_selectBox");
        var queryType = fieldObj.getAttribute("typeAheadTypeDbName");
        var filterByString = fieldObj.getAttribute("filterByString");
        var filterBySelects = fieldObj.getAttribute("filterBySelects");

        if (filterByString == null){
            filterByString = '';
        }

         selectObj.options.length = 0;
         selectObj.indexSelected = 0;
         selectObj.originalOnchange();
         enableDisableChildren(selectObj.id);


         if ((filterBySelects != null && filterBySelects!='') && !ignoreParent){
            filterBySelects = filterBySelects.split("!");

            for(var counter=0; counter < filterBySelects.length ; counter++)
            {
                filterBySelectsInfo = filterBySelects[counter].split("=");

                dbField = filterBySelectsInfo[0];
                fieldObjectId = filterBySelectsInfo[1];

                // the parent is actually a select box ....
                parentFieldObj = document.getElementById(fieldObjectId+"_selectBox");
                if (parentFieldObj == null){
                    parentFieldObj = document.getElementById(fieldObjectId);
                    // we might be dealing with a regular select box

                }

                if (parentFieldObj == null){
                    alert("Could not determine parent select "+fieldObjectId);
                    return;
                }

                if (parentFieldObj.selectedIndex < 0){
                    // disable me if my parent does not have anything selected
                    fieldObj.disabled = true;
                    fieldObj.value="";
                    selectObj.style.display="none";
                    return;

                }

                if (filterByString == ''){
                    filterByString = dbField+"=\""+parentFieldObj.options[parentFieldObj.selectedIndex].value+"\"";
                } else {
                     filterByString += "AND "+dbField+"=\""+parentFieldObj.options[parentFieldObj.selectedIndex].value+"\"";
                }



            }
        }

        selectObj = document.getElementById(fieldObj.id+"_selectBox");



        if (fieldObj.value != "") {
            var imgObj = document.getElementById(fieldObj.id + "_processImage");
            fieldObj.style.width = (fieldObj.getAttribute("originalWidth") - 21) + "px";
            imgObj.style.display = "inline";

            if (exact != null && exact){
                exact = 1;
            } else {
                exact = 0;
            }


            if (fieldObj.ajaxRequest != null && typeof(fieldObj.ajaxRequest) == "object"){
                fieldObj.ajaxRequest.abort();
            }

            fieldObj.ajaxRequest = ajax_request("GET","request=executeTypeAheadQuery&exactquery="+exact+"&queryname="+ajax_URLEncode(queryType)+"&searchParam="+ajax_URLEncode(fieldObj.value)+"&filterByString="+ajax_URLEncode(filterByString),queryResultFunction,fieldObj.id);

        }
    }

    /**
        Processes the results of the ajax request, populates the dropdown with
        the items found. Also calls the onclick and onchange events based on the
        found set (for example, if there is only one result in the found set, will
        make the single item in focus, and call the onclick / onchange event of the
        dropdown).
    */
    function queryResultFunction(txtResult,fieldId){

        var imgObj = document.getElementById(fieldId + "_processImage");
        var fieldObj = document.getElementById(fieldId);
        var selectObj = document.getElementById(fieldId+"_selectBox");


        if (fieldObj == null) {
            alert("Could not find original field");
            return;
        }

        if (selectObj == null) {
            alert("Could not find select field");
            return;
        }

        try{
            var foundItems = eval(txtResult);
        } catch (e) {
            alert(txtResult);
        }

        var items = foundItems.length;
        var itemResults = 0;

        for (counter=0;counter<items;counter++)
        {
            objOption = addOption(selectObj,foundItems[counter].name,foundItems[counter].value);
            itemResults = foundItems[counter].results;
            if (itemResults){

            // done by onclick on the dropdown, IE does not support on click of the item
                eval ("objOption.onclick = function(){\
                            return onClickOption('"+fieldObj.id+"','"+selectObj.id+"',"+objOption.index+",true);\
                        }");

                if (items == 1){
                        //document.getElementById('status').value='Found 1 item';
                        selectObj.setAttribute('resultsFound',itemResults);
                    // we have only one item, but its result is atleast 1 (0 is an error / not found)
                        onClickOption(fieldObj.id,selectObj.id,objOption.index,false);
                } else if (fieldObj.value.toLowerCase() == objOption.text.toLowerCase() ||
                        fieldObj.value.toLowerCase() == objOption.id.toLowerCase()) {
                         selectObj.setAttribute('resultsFound',itemResults);
                        onClickOption(fieldObj.id,selectObj.id,objOption.index,false);
                }
            } else {
                selectObj.originalOnchange();
            }

        }

     if (!itemResults) {
         // otherwise the dropdown does not get submitted to the next page.
         selectObj.indexSelected = 0;
     }

     selectObj.setAttribute('resultsFound',itemResults);

     enableDisableChildren(selectObj.id);

     fieldObj.style.width = fieldObj.getAttribute("originalWidth") + "px";
     imgObj.style.display = "none";

     fieldObj.ajaxRequest = null;
 }


 /**
    get called when the user clicks on an option, or even when the code determines
    that an item suppose to be clicked.

    Helps with managing any 'child' select when one item is filtered by another.
 */
 function onClickOption(fieldObjId,selectObjId,objOptionIndex,hideSelect)
 {
     var fieldObj = document.getElementById(fieldObjId);
     var selectObj = document.getElementById(selectObjId);
     var objOption = selectObj.options[objOptionIndex];

     //document.getElementById("status").value="called on click option";

      if (document.getElementById(fieldObj.id).value != objOption.text){
           clearChildren(selectObj.id);
      }


      //document.getElementById("status").value="checking results found";
      if (selectObj.getAttribute('resultsFound') == 0){
          return false;
      }

      //document.getElementById("status").value="after checking results found";

      if (document.getElementById(fieldObj.id).lastKeyCode != 8 || hideSelect){
            document.getElementById(fieldObj.id).value = objOption.text;
      }

      document.getElementById(selectObj.id).selectedIndex = objOption.index;

      if (hideSelect){
          document.getElementById(selectObj.id).style.display="none";
      }
      enableDisableChildren(selectObj.id);

      //document.getElementById("status").value="Calling on change on the options";


      selectObj.originalOnchange();



      return true;
 }

 /**
    Loops through the children of a select box, enabling / disabling the selects
    based on wether the parent has a proper value selected.

    If not, it will disable the child until such time as the parent has a proper
    value.

    Helper function for enableDisable all....

 */
 function enableDisableChildren(selectObjId)
 {
     var textObjectId = selectObjId.replace("_selectBox","");

     var selectObj = document.getElementById(selectObjId);

     if (selectObj == null){
         // we might be dealing with a regular select box
         var selectObj = document.getElementById(textObjectId);
     }


     if (typeof(selectBoxRelations[textObjectId]) == "undefined"){
         return;
     }

     for (var counter=0; counter < selectBoxRelations[textObjectId].length; counter++)
     {
         var childTextObj = document.getElementById(selectBoxRelations[textObjectId][counter]);

         if (childTextObj == null) {
             alert("Could not find object "+selectBoxRelations[textObjectId][counter]+" cannot enable child for "+textObjectId);
         }

         var childTextObjSelect = document.getElementById(selectBoxRelations[textObjectId][counter]+"_selectBox");

         if (childTextObjSelect == null){
             // we might be dealing with a regular select box
             var childTextObjSelect = document.getElementById(selectBoxRelations[textObjectId][counter]);
         }

         if (selectObj.selectedIndex == -1 || typeof(selectObj.selectedIndex) == "undefined" || selectObj.value == ''){
             childTextObj.disabled = true;
             childTextObjSelect.selectedIndex = -1;
             childTextObj.value = "";
             childTextObjSelect.options.length = 0;

         } else {
             childTextObj.disabled = false;
             childTextObjSelect.selectedIndex = -1;
             childTextObj.value = "";
             childTextObjSelect.options.length = 0;
         }

         // recoursivley, enable of disable any children associated with the child
         enableDisableChildren(childTextObjSelect.id);

     }

 }

 function enableDisableAll()
 {

     for (keyItem in selectBoxRelations)
     {
        if(typeof(selectBoxRelations[keyItem]) == "object"){
            enableDisableChildren(keyItem+"_selectBox");
        }
     }
 }

 function clearChildren(selectObjId)
 {
    var textObjectId = selectObjId.replace("_selectBox","");
     var selectObj = document.getElementById(selectObjId);


     if (typeof(selectBoxRelations[textObjectId]) == "undefined"){
         return;
     }

     for (var counter=0; counter < selectBoxRelations[textObjectId].length; counter++)
     {
         var childTextObj = document.getElementById(selectBoxRelations[textObjectId][counter]);

         if (childTextObj == null) {
             alert("Could not find object "+selectBoxRelations[textObjectId][counter]+" cannot clear child for "+textObjectId);
         }

         var childTextObjSelect = document.getElementById(selectBoxRelations[textObjectId][counter]+"_selectBox");


         childTextObjSelect.selectedIndex = -1;
         childTextObj.value = "";
         childTextObjSelect.options.length = 0;

         // recoursivley, enable of disable any children associated with the child
         clearChildren(childTextObjSelect.id);

     }
 }

 function moveSelectedItemsInMultipleSelect(from,to){
    var fromObject = document.getElementById(from);
    var toObject = document.getElementById(to);

    if (fromObject == null){
        alert("could not find "+from+" - it has to be an id of a select box");
        return;
    }

    if (toObject == null){
        alert("could not find "+to+" - it has to be an id of a select box");
        return;
    }


    var itemsToMove = Array();
    var counter=0;
    for (selectionItem = 0; selectionItem < fromObject.options.length; selectionItem++){

        if (fromObject.options[selectionItem]!=null && fromObject.options[selectionItem].selected){
            itemsToMove[counter] = new Object();
            itemsToMove[counter].value = fromObject.options[selectionItem].value;
            itemsToMove[counter].text = fromObject.options[selectionItem].text;
            counter++;
        }
    }

    for (counter = 0; counter < itemsToMove.length; counter++){
            addOption(toObject,itemsToMove[counter].text,itemsToMove[counter].value);
            deleteOption(fromObject,itemsToMove[counter].value);
        }
}

function addOption(selectObject,optionText,optionValue) {
    var optionObject = new Option(unescape(optionText),optionValue);
    var optionRank = selectObject.options.length;
    selectObject.options[optionRank]=optionObject;

    return optionObject;
}

function deleteOption(selectObject,optionValue) {
    if (selectObject.options.length!=0) {
         for (selectionItem = 0; selectionItem < selectObject.options.length; selectionItem++){
            if (selectObject.options[selectionItem].value == optionValue){
                selectObject.options[selectionItem]=null;
                return;
            }
        }
    }
}


/*===================================================================
 Author: Matt Kruse

 View documentation, examples, and source code at:
     http://www.JavascriptToolbox.com/

 NOTICE: You may use this code for any purpose, commercial or
 private, without any further permission from the author. You may
 remove this notice from your final code if you wish, however it is
 appreciated by the author if at least the web site address is kept.

 This code may NOT be distributed for download from script sites,
 open source CDs or sites, or any other distribution method. If you
 wish you share this code with others, please direct them to the
 web site above.

 Pleae do not link directly to the .js files on the server above. Copy
 the files to your own server for use with your site or webapp.
 ===================================================================*/
var Position = (function() {
  // Resolve a string identifier to an object
  // ========================================
  function resolveObject(s) {
    if (document.getElementById && document.getElementById(s)!=null) {
      return document.getElementById(s);
    }
    else if (document.all && document.all[s]!=null) {
      return document.all[s];
    }
    else if (document.anchors && document.anchors.length && document.anchors.length>0 && document.anchors[0].x) {
      for (var i=0; i<document.anchors.length; i++) {
        if (document.anchors[i].name==s) {
          return document.anchors[i]
        }
      }
    }
  }

  var pos = {};
  // Set the position of an object
  // =============================
  pos.set = function(o,left,top) {
    if (typeof(o)=="string") {
      o = resolveObject(o);
    }
    if (o==null || !o.style) {
      return false;
    }
    o.style.position = "absolute";

    // If the second parameter is an object, it is assumed to be the result of getPosition()
    if (typeof(left)=="object") {
      var pos = left;
      left = pos.left;
      top = pos.top;
    }

    o.style.left = left + "px";
    o.style.top = top + "px";
    return true;
  };

  // Retrieve the position and size of an object
  // ===========================================
  pos.get = function(o) {
    var fixBrowserQuirks = true;
      // If a string is passed in instead of an object ref, resolve it
    if (typeof(o)=="string") {
      o = resolveObject(o);
    }

    if (o==null) {
      return null;
    }

    var left = 0;
    var top = 0;
    var width = 0;
    var height = 0;
    var parentNode = null;
    var offsetParent = null;


    offsetParent = o.offsetParent;
    var originalObject = o;
    var el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references
    while (el.parentNode!=null) {
      el = el.parentNode;
      if (el.offsetParent==null) {
      }
      else {
        var considerScroll = true;
        /*
        In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already
        take its scroll position into account. If elements further up the chain are scrollable, their
        scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value
        which must be ignored.
        */
        if (fixBrowserQuirks && window.opera) {
          if (el==originalObject.parentNode || el.nodeName=="TR") {
            considerScroll = false;
          }
        }
        if (considerScroll) {
          if (el.scrollTop && el.scrollTop>0) {
            top -= el.scrollTop;
          }
          if (el.scrollLeft && el.scrollLeft>0) {
            left -= el.scrollLeft;
          }
        }
      }
      // If this node is also the offsetParent, add on the offsets and reset to the new offsetParent
      if (el == offsetParent) {
        left += o.offsetLeft;
        if (el.clientLeft && el.nodeName!="TABLE") {
          left += el.clientLeft;
        }
        top += o.offsetTop;
        if (el.clientTop && el.nodeName!="TABLE") {
          top += el.clientTop;
        }
        o = el;
        if (o.offsetParent==null) {
          if (o.offsetLeft) {
            left += o.offsetLeft;
          }
          if (o.offsetTop) {
            top += o.offsetTop;
          }
        }
        offsetParent = o.offsetParent;
      }
    }


    if (originalObject.offsetWidth) {
      width = originalObject.offsetWidth;
    }
    if (originalObject.offsetHeight) {
      height = originalObject.offsetHeight;
    }

    return {'left':left, 'top':top, 'width':width, 'height':height
        };
  };

  // Retrieve the position of an object's center point
  // =================================================
  pos.getCenter = function(o) {
    var c = this.get(o);
    if (c==null) { return null; }
    c.left = c.left + (c.width/2);
    c.top = c.top + (c.height/2);
    return c;
  };

  return pos;
})();

