/*                                                                  
* Copyright © 1999-2009 TeaLeaf Technology, Inc.  
* All rights reserved.
*
* THIS SOFTWARE IS PROVIDED BY TEALEAF ``AS IS'' 
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED.  
* IN NO EVENT SHALL TEALEAF BE LIABLE FOR ANY DIRECT, INDIRECT, 
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
* @fileoverview 
* This is the main UI Client Event Capture JavaScript file that is  
* used by other JavaScript to register their onload routines.
*
* @requires 
* TeaLeaf.js
* TeaLeafEvent.js
* TeaLeafClientCfg.js
*
* @version 2009.02.12.1
*                                                                   
*/
if(TeaLeaf.Client && TeaLeaf.Client.Configuration){
 
 TeaLeaf.Client.tlTimeoutID = -1;
 
 /**
    * Enable all event handlers specified in the configuration.
    * @param obj parameter that determines to enable handlers to the window or document object or both.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */                                                        
    TeaLeaf.Client.tlEnableAllEventHandlers = function(obj) {         
        if(obj){
            if(obj == window){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, true, "all");
            }
            else if(obj == document){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, true, "all");
            }
        } 
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, true, "all");
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, true, "all");        
        }        
    }
 /**
    * Enable a specific event handler defined in the configuration.
    * @param obj parameter that determines to enable handlers to the window or document object.
    * @param domEventName name of the event to enable.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */                                                            
    TeaLeaf.Client.tlEnableEventHandler = function(obj, domEventName) { 
        if(obj == window){  
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, true, domEventName); 
        }
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, true, domEventName); 
        }        
    }
 /**
    * Disable all event handlers specified in the configuration.
    * @param obj parameter that determines to disable handlers to the window or document object or both.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */                                                        
    TeaLeaf.Client.tlDisableAllEventHandlers = function(obj) { 
        if(obj){
            if(obj == window){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, false, "all");
            }
            else if(obj == document){
                TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, false, "all");
            }
        } 
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, false, "all");
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, false, "all");        
        }        
    }
 /**
    * Disable a specific event handler defined in the configuration.
    * @param obj parameter that determines to disable handlers to the window or document object.
    * @param domEventName name of the event to enable.
    * @requires
    * TeaLeafClientCfg.js 
    * @addon
    */                                                                
    TeaLeaf.Client.tlDisableEventHandlers = function(obj, domEventName) { 
        if(obj == window){                
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlWindowHandlers, false, domEventName); 
        }
        else{
            TeaLeaf.Client.tlClientJSONCfgUtil(TeaLeaf.Client.Configuration.tlDocumentHandlers, false, domEventName); 
        }        
    }    
 /**
    * Utility that helps enabling or disabling of event handlers.
    * @param tlJSONConfig configuration array.
    * @param tlEnable enable (true or false flag).
    * @param domEventName event name to enable or disable.
    * @addon
    */                                                                    
    TeaLeaf.Client.tlClientJSONCfgUtil = function(tlJSONConfig, tlEnable, domEventName) {         
        for(var i = 0; i<tlJSONConfig.length; i++){
            if(domEventName == "all"){
                tlJSONConfig[i].load = tlEnable;
            }
            else if (domEventName == tlJSONConfig[i].domevent){
                tlJSONConfig[i].load = tlEnable;
            }
        }  
    }  
 TeaLeaf.Client.tlHasUserMovement = false;
 /**
    * Detect user movement.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                        
 TeaLeaf.Client.tlUserMovement = function() {
  TeaLeaf.Client.tlHasUserMovement = true;
  TeaLeaf.Event.tlRemoveHandler(document, "mousemove", TeaLeaf.Client.tlUserMovement, false);
 }
 /**
    * Add a unique Id to a DOM element.
    * @param itemSource DOM element that needs an id.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                             
    TeaLeaf.Client.tlAddIdToControl = function(itemSource) {       
     if ((itemSource.id && itemSource.id != "") || (itemSource.name && itemSource.name != "")) {
      return;
     }
     var idTag = itemSource.tagName;
     var thereYet = TeaLeaf.Client.Configuration.tlIdCounter[idTag];
     if (thereYet == undefined)
      TeaLeaf.Client.Configuration.tlIdCounter[idTag] = 0;
        var idElement = "_TL_" + idTag + "_"
            + TeaLeaf.Client.Configuration.tlIdCounter[idTag];
        var item  = document.getElementById(idElement);
        var baseId = idElement;
        
        if(item){
            //loop through to check if there are items with such ids
            while(document.getElementById("_TL_" + idTag + "_"
                + TeaLeaf.Client.Configuration.tlIdCounter[idTag]++));
        }
        
        itemSource.id = baseId;
        TeaLeaf.Client.Configuration.tlIdCounter[idTag]++;
 }  
 /**
    * Loops through a JSON array to find the elemement if exists.
    * @param name or id of element.
    * @param JSON.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                             
 TeaLeaf.Client.tlFindinJSON = function(tlElement, tlJSON) {        
        var tlNameorId = TeaLeaf.Client.tlGetName(tlElement);
        if(tlNameorId){
            for(var i=0; i<tlJSON.length; i++){ 
                if(tlNameorId == tlJSON[i].tlfieldname){  
                    return tlJSON[i];
                }
            }
        }
    }
 /**
    * Check if element is silent.
    * @param name or id of element.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                             
 TeaLeaf.Client.tlIsReplace = function(name) {
  // Nothing there
  if( !name ) {
   return false;
  }
  // If this an object
  if( typeof name == "object" ) {   
   if( name.TeaLeafReplace) {  
     return true;
   }      
  }
  else{
      var tlReplace = document.getElementById(name);  
      if(tlReplace.TeaLeafReplace == true){
           return true;      
      }      
      if(!tlReplace){
          tlReplace = document.getElementsByName(name);     
          for(var i=0; i<tlSilent.length; i++){
              if(tlReplace[i].TeaLeafReplace == true){
                   return true;
              }
          }
      }
  }
  
  if( name.type == "password" ) {
   return TeaLeaf.Client.Configuration.tlpassword == 2;
  }
  return false;
 }
 /**
    * Replace element with dummy value, needed in some cases
    * when there is client validation.
    * @param elem
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                              
 TeaLeaf.Client.tlReplaceValue = function(elem) {
  var name = TeaLeaf.Client.tlGetName(elem);
  TeaLeaf.Client.tlMakeFieldBlockMap();
  var map_item = TeaLeaf.Client.Configuration.tlFieldBlockMap[name.toLowerCase()];
  if(map_item == null) return "";
  if(map_item["eventvaluereplace"].length > 0) return map_item["eventvaluereplace"];
  else return "";
    }
    
 /**
    * Check if element is excluded from capture.
    * @param name or id of element.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                              
 TeaLeaf.Client.tlIsExcluded = function(name) {
  // Nothing there
  if( !name ) {
   return false;
  }
  // If this an object
  if( typeof name == "object" ) {   
   if( name.TeaLeafExclude ) {
    return true;
   }      
  }
  else{
      var tlExclude = document.getElementById(name);         
      if(tlExclude){
          if(tlExclude.TeaLeafExclude){   
              return true;      
          }         
      }
      else{
          tlExclude = document.getElementsByName(name);     
          if(tlExclude){
              for(var i=0; i<tlExclude.length; i++){
                  if(tlExclude[i].TeaLeafExclude){
                      return true;
                  }
              }
          }      
      }
      return false;
  }
  
  if( name.type == "password" ) {
   return TeaLeaf.Client.Configuration.tlpassword == 2;
  }
  return false;
 }
 /**
    * Get the name from a DOM node.
    * @param theNode DOM element.
    * @addon
    */                                                                             
 TeaLeaf.Client.tlGetName = function(theNode) {
  if( theNode == null ) {
   return null;
  }
  var  id = theNode.id;
  if( id && id != "" ) {
   return id;
  }
  var  name = theNode.name;
  if( name && name != "" ) {
   return name;
  }
  return null;
 }
 /**
    * Get event source DOM element.
    * @param theEvent DOM event.
    * @addon
    */                                                                             
    TeaLeaf.Client.tlGetEventSource = function(theEvent) {
        var itemSource = null;       
        if(theEvent){ 
         if( theEvent.srcElement ) { // MSFT
             itemSource = theEvent.srcElement;
         }
         else { // Mozilla
             itemSource = theEvent.target;
          if( itemSource == null ) {
              itemSource = theEvent.explicitOriginalTarget;   
           if( itemSource == null ) {
               itemSource = theEvent.originalTarget;
           }
          }
         }
         if(itemSource && (itemSource.name == null || itemSource.name == "")) {
             // If an Anchor or link, I can look info up in the list
          if( itemSource.parentNode && itemSource.parentNode.tagName ) {
              if( itemSource.parentNode.tagName == "A" ||
               itemSource.parentNode.tagName == "LINK" ) {
                itemSource = itemSource.parentNode;
               }
              }
             }
         }
     return itemSource;
    } 
 /**
    * If we don't have an name, get the index from either the anchors
    * or the links collection.
    * @param theNode DOM element.
    * @param full XML format.
    * @addon
    */                                                                             
 TeaLeaf.Client.tlGetAnchor = function(theNode, full) {
  if( theNode == null ) {
   return null;
  }
  if( theNode.name && theNode.name != "" ) {
   return null;
  }
  var  idx;
  for(idx = 0; idx < document.anchors.length; idx++) {
   if( document.anchors[idx] == theNode ) {
    if( full ) {
     return "<AnchorElement>" + idx + "</AnchorElement>\r\n";
    }
    else {
     return "Anchor-" + idx;
    }
   }
  }
  for(idx = 0; idx < document.links.length; idx++) {
   if( document.links[idx] == theNode ) {
    if( full ) {
     return "<LinkElement>" + idx + "</LinkElement>\r\n";
    }
    else {
     return "Link-" + idx;
    }
   }
  } 
  return null;
 }
 /**
  * Check if element is of type input
  */
 TeaLeaf.Client.checkIsInput = function(elem) {
     if(typeof(elem) == "string") elem = document.getElementById(elem);
 
            switch(elem.tagName) 
     {
  case "INPUT":
  case "SELECT":
  case "TEXTAREA":
      return true;
     }
     return false;
 }

 /**
    * If we don't have an name, get the index from either the anchors
    * or the links collection.
    * @param str XML string.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                              
 TeaLeaf.Event.tlFormatXMLName = function(str) {
  // Nothing handed in
  if( ! str || str.length <= 0 )
   return null;
  var rtn = "";
  if( ! TeaLeaf.Event.tlNameStartChar(str.charCodeAt(0)) ) {
   rtn = "_";
  }
  var max = str.length;
  var ind;
  for(ind = 0; ind < max; ind++) {
   if( TeaLeaf.Event.tlNameChar(str.charCodeAt(ind)) ) {
    rtn = rtn + str.charAt(ind);
   }
   else {
    rtn = rtn + "_";
   }
  }
  return rtn;
 }
 /**
 * Utility function to help format the XML.
    * @param chr character.
    * @addon
    */                                                                              
    TeaLeaf.Event.tlNameStartChar = function(chr) {
  // ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] |
  // [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] |
  // [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] |
  // [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD]
  // Note:  ":" was removed because it is only valid when a namespace
  // is defined
  return (chr >= 0x41 && chr <= 0x5A) || chr == 0x5F ||
   (chr >= 0x61   && chr <= 0x7A)   || (chr >= 0xC0   && chr <= 0xD6)   ||
   (chr >= 0xD8   && chr <= 0xF6)   || (chr >= 0xF8   && chr <= 0x2FF)  ||
   (chr >= 0x370  && chr <= 0x37D)  || (chr >= 0x37F  && chr <= 0x1FFF) ||
   (chr >= 0x200C && chr <= 0x200D) || (chr >= 0x2070 && chr <= 0x218F) ||
   (chr >= 0x2C00 && chr <= 0x2FEF) || (chr >= 0x3001 && chr <= 0xD7FF) ||
   (chr >= 0xF900 && chr <= 0xFDCF) || (chr >= 0xFDF0 && chr <= 0xFFFD);
 }
 /**
 * Utility function to help format the XML.
    * @param chr character.
    * @addon
    */                                                                              
    TeaLeaf.Event.tlNameChar = function(chr) {
  // NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
  return TeaLeaf.Event.tlNameStartChar(chr) || chr == 0x2D || chr == 0x2E ||
   (chr >= 0x30 && chr <= 0x39) || chr == 0xB7  ||
   (chr >= 0x0300 && chr <= 0x036F) || (chr >= 0x203F && chr <= 0x2040);
 }
 TeaLeaf.Client.tlQueuedKeys = "";
 /**
    * Queues the keys
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                              
 TeaLeaf.Client.tlQueueKey = function(theEvent) {
        TeaLeaf.Client.tlSendResize();
        TeaLeaf.Client.tlSendScroll();
  if( ! theEvent ) {
   theEvent = window.event;
  }
  if( theEvent.keyCode < 0x20 ) {
   return;
  }
  // Residual keys to send in?  Save the source for next time around
  var itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
  if( ! itemSource ) {
   return;
  }
  // Do we need to set the onFocus time?
  if( ! itemSource.TeaLeafFocusTime ) {
   itemSource.TeaLeafFocusTime = new Date();
  }
  if( TeaLeaf.Client.tlQueuedKeySource ) {
   if( TeaLeaf.Client.tlQueuedKeySource != itemSource ) {
    if( TeaLeaf.Client.tlQueuedKeys && TeaLeaf.Client.tlQueuedKeys.length > 0 )
                    TeaLeaf.Client.tlSendKeys();
    TeaLeaf.Client.tlQueuedKeySource = itemSource;
   }
  }
  else {
   TeaLeaf.Client.tlQueuedKeySource = itemSource;
  }
  // Get the name/anchor where the key happened.  If both are null,
  // don't worry about logging
  var name  = TeaLeaf.Client.tlGetName(itemSource);
  var lev = null;
  if( ! name ) {
   lev = TeaLeaf.Client.tlGetAnchor(itemSource, false);
   if( ! lev ) {
    TeaLeaf.Client.tlQueuedKeySource = null;
    return;
   }
  }
  else {
   if( TeaLeaf.Client.tlIsReplace(itemSource) ) {
    TeaLeaf.Client.tlQueuedKeysCount++;
    return;
   }
   if( TeaLeaf.Client.tlIsExcluded(itemSource) ) {
       TeaLeaf.Client.tlQueuedKeys=null;
    TeaLeaf.Client.tlQueuedKeysCount++;
    return;
   }
  }
  // Put in the seperator if we need it
  if( TeaLeaf.Client.tlQueuedKeys ) {
   if( TeaLeaf.Client.tlQueuedKeys.length > 0 ) {
    TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + ";";
   }
  }
  // build the string
  if( theEvent.ctrlKey ) {
   if( TeaLeaf.Client.tlQueuedKeys ) {
    TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + "ctrl-";
   }
   else {
    TeaLeaf.Client.tlQueuedKeys = "ctrl-";
   }
  }
  if( theEvent.altKey ) {
   if( TeaLeaf.Client.tlQueuedKeys ) {
    TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + "alt-";
   }
   else {
    TeaLeaf.Client.tlQueuedKeys = "alt-";
   }
  }
  if( theEvent.shiftKey ) {
   if( TeaLeaf.Client.tlQueuedKeys ) {
    TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + "shift-";
   }
   else {
    TeaLeaf.Client.tlQueuedKeys = "shift-";
   }
  }
  TeaLeaf.Client.tlQueuedKeys = TeaLeaf.Client.tlQueuedKeys + theEvent.keyCode;
 }
 /**
    * Send the keys.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                              
 TeaLeaf.Client.tlSendKeys = function() { 
  if( ! TeaLeaf.Client.tlQueuedKeySource ||
   ( ! TeaLeaf.Client.tlQueuedKeys && ! TeaLeaf.Client.tlQueuedKeysCount ) ) {
    return;
  }
  // Save the values to temp variables and null out the
  // queue variables
  var qSource = TeaLeaf.Client.tlQueuedKeySource;
  var qKeys   = TeaLeaf.Client.tlQueuedKeys;
  var qCount  = TeaLeaf.Client.tlQueuedKeysCount;
  TeaLeaf.Client.tlQueuedKeySource = null;
  TeaLeaf.Client.tlQueuedKeys      = "";
  TeaLeaf.Client.tlQueuedKeysCount = 0; 
    
        var tlreplace = false; 
  if( TeaLeaf.Client.tlIsReplace(qSource) ) {  
   tlreplace = true;
   return;
  }
  var excluded = false;
 
  if( TeaLeaf.Client.tlIsExcluded(qSource) ) {
   excluded = true;
   qKeys = null;
  }
  // Get the name/anchor where the key happened.  If both are null,
  // don't worry about logging
  var name  = TeaLeaf.Client.tlGetName(qSource);
  var lev = null;
  if( name == null ) {
   lev = TeaLeaf.Client.tlGetAnchor(qSource, false);
   if( lev == null ) {
    return;
   }
  }
  else {
   if( TeaLeaf.Client.tlIsExcluded(name) ) {
    return null;
   }
  }
  // The Reporting Event
  var tlevt = new TeaLeaf.Event("GUI", "KeyUp");
        var tlAddNameValueArray = ["Name", qSource.name,
                          "Id", qSource.id,
                          "Lev", lev,
                          "ElementType", qSource.type,
                          "TagName", qSource.tagName,
                          "KeyCount", qCount];
        tlevt.tlAddData(tlAddNameValueArray);
  if(excluded) {
      var tlAddNameValueArrayExcluded = ["Excluded", "true"];
            tlevt.tlAddData(tlAddNameValueArrayExcluded);
  }
  else if(tlreplace){
   
   var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(qSource);   
   var tlAddNameValueArrayReplaceName = ["ValueIn", name,
                                      name,   tlRepValue,
                                      "KeyCode", qKeys];                                          
   tlevt.tlAddData(tlAddNameValueArrayReplaceName);
  }
  else {
   var tlManualName = TeaLeaf.Event.tlFormatXMLName(name);   
   var tlAddNameValueArrayManualName = ["ValueIn", tlManualName,
                                     tlManualName,   qSource.value,
                                     "KeyCode", qKeys];                                          
   tlevt.tlAddData(tlAddNameValueArrayManualName);
  }
  // Now send the data in
  tlevt.tlSend();
 }
 /**
    * Send resize event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                              
 TeaLeaf.Client.tlSendResize = function() { 
  if( ! TeaLeaf.Client.ResizeClientX && ! TeaLeaf.Client.ResizeClientY ) {
   return;
  }
  var tlevt = new TeaLeaf.Event("GUI", "Resize");
        var tlAddNameValueArray = ["ClientX", TeaLeaf.Client.ResizeClientX,
                          "ClientY", TeaLeaf.Client.ResizeClientY,
                          "ScreenX", TeaLeaf.Client.ResizeScreenX,
                          "ScreenY", TeaLeaf.Client.ResizeScreenY];
        tlevt.tlAddData(tlAddNameValueArray);
  TeaLeaf.Client.ResizeClientX = null;
  TeaLeaf.Client.ResizeClientY = null;
  TeaLeaf.Client.ResizeScreenX = null;
  TeaLeaf.Client.ResizeScreenY = null;
  // Now send the data in
  tlevt.tlSend();
 }
 
 /**
    * Queue scroll event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */             
    TeaLeaf.Client.tlQueueScroll = function(tlEvent) {
     TeaLeaf.Client.tlSendKeys();
     TeaLeaf.Client.tlSendResize();
     if( ! tlEvent ) {
      tlEvent = window.event;
     }
     
     if( tlEvent.clientX ) {
      // IE
      TeaLeaf.Client.ScrollClientX = tlEvent.clientX;
      TeaLeaf.Client.ScrollClientY = tlEvent.clientY;
      TeaLeaf.Client.ScrollScreenX = tlEvent.screenX;
      TeaLeaf.Client.ScrollScreenY = tlEvent.screenY;
     }
     else {
      // Other
      TeaLeaf.Client.ScrollHeight = tlEvent.target.scrollHeight;
      TeaLeaf.Client.ScrollWidth  = tlEvent.target.scrollWidth;
      TeaLeaf.Client.ScrollTop    = tlEvent.target.scrollTop;
      TeaLeaf.Client.ScrollLeft   = tlEvent.target.scrollLeft;
     }
    }
 /**
    * Send scroll event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                              
 TeaLeaf.Client.tlSendScroll = function() { 
  if( ! TeaLeaf.Client.ScrollClientX && ! TeaLeaf.Client.ScrollHeight ) {
   return;
  }
  var tlevt = new TeaLeaf.Event("GUI", "Scroll");
        var tlAddNameValueArray = ["ClientX",      TeaLeaf.Client.ScrollClientX,
                                   "ClientY",      TeaLeaf.Client.ScrollClientY,
                                   "ScreenX",      TeaLeaf.Client.ScrollScreenX,
                                   "ScreenY",      TeaLeaf.Client.ScrollScreenY,
                                   "ScrollHeight", TeaLeaf.Client.ScrollHeight,
                                   "ScrollWidth",  TeaLeaf.Client.ScrollWidth,
                                   "ScrollTop",    TeaLeaf.Client.ScrollTop,
                                   "ScrollLeft",   TeaLeaf.Client.ScrollLeft]; 
  tlevt.tlAddData(tlAddNameValueArray); 
  TeaLeaf.Client.ScrollClientX = null;
  TeaLeaf.Client.ScrollClientY = null;
  TeaLeaf.Client.ScrollScreenX = null;
  TeaLeaf.Client.ScrollScreenY = null;
  TeaLeaf.Client.ScrollHeight  = null;
  TeaLeaf.Client.ScrollWidth   = null;
  TeaLeaf.Client.ScrollTop     = null;
  TeaLeaf.Client.ScrollLeft    = null;
  // Now send the data in
  tlevt.tlSend();
 }
    /**
    * Find the nearest ancestor for a DOM node of the given type
    * @param node The original node
    * @param tag The tag to match on
    * @addon
    */  
 TeaLeaf.Client.tlFindAncestorByTag = function(node, tag)
    {
        var cur_node = node.parentNode;
        while(cur_node && cur_node != window.document)
        {
            if(cur_node.nodeType != 1) continue;
            if(cur_node.tagName == tag) break;
            else cur_node = cur_node.parentNode;
        }
        
        return cur_node;
    }
    /**
    * Generate an XPath for the node, consumable by TeaLeaf.Client.tlGetNodeFromXPath
    * @param node The starting node
    * @param tag The tag to match on
    * @addon
    */
    TeaLeaf.Client.tlGetXPathFromNode = function(node)
    {
        if(node == null) return null;
        var xpath = [];
        var cur_node = node;
        var nodes_arr = null;
        var parent_node = null;
  // Hack fix to handle tags that are not normally visual elements
  for(var i in TeaLeaf.Client.Configuration.tlSpecialChildNodeTags)
  {
  if(cur_node.tagName.toString()==i)
   cur_node = cur_node.parentNode;
  }
        
       while(cur_node != window.document && (cur_node.id == null || cur_node.id == ""))
       {
            nodes_arr = null;
            parent_node = null;
            switch(cur_node.tagName)
            {
                case "TD":
                    if(parent_node = TeaLeaf.Client.tlFindAncestorByTag(cur_node, "TR"))
                        nodes_arr = parent_node.cells;
                    break;
                case "TR":
                    if(parent_node = TeaLeaf.Client.tlFindAncestorByTag(cur_node, "TABLE"))
                        nodes_arr = parent_node.rows;
                    break;
         case "OPTION":
              if(parent_node = TeaLeaf.Client.tlFindAncestorByTag(cur_node, "SELECT"))
                  nodes_arr = parent_node.options;
      break;
                default:
                    parent_node = cur_node.parentNode;
              if(!parent_node) parent_node = window.document;
              nodes_arr = parent_node.childNodes;
              break;
            }
            
            if(nodes_arr == null) return null;
            var j=0;
            for(var i=0; i<nodes_arr.length; i++)
            {
             if(nodes_arr[i].nodeType == 1 && nodes_arr[i].tagName == cur_node.tagName)
                {
                    if(nodes_arr[i] == cur_node)
                    {
                        xpath[xpath.length] = [cur_node.tagName.toUpperCase(), j];
                        break;
                    }
                    
                    j++;
                }
            }
            
     cur_node = parent_node;
        }
        
        if(cur_node.id != null && cur_node.id != "") xpath[xpath.length] = [cur_node.id];
        
        var parts = [];
        for(var i=xpath.length-1; i>=0; i--)
        {
            if(xpath[i].length > 1)
                parts[parts.length] = "['"+xpath[i][0]+"',"+xpath[i][1]+"]";
            else
                parts[parts.length] = "['"+xpath[i][0].toString().replace(/'/g, "\\'")+"']";
        }
        
        return "["+parts.join(",")+"]";
    }
    /**
    * Find a node specified by an XPath generated by TeaLeaf.Client.tlGetXPathFromNode
    * @param path The XPath
    * @addon
    */      
    TeaLeaf.Client.tlGetNodeFromXPath = function(path, decode)
    {
        if(path == null) return null;
 if(decode) path = TeaLeaf.Event.tlXMLDecode(path);
        var xpath = eval(path);
        if(xpath == null) return null;
        var cur_node = window.document;
        
        for(var i=0; i<xpath.length; i++)
        {
         found = false;
            if(xpath[i].length == 1)
            {
                cur_node = document.getElementById(xpath[i]);
                if(cur_node == null) return null; 
            }
            else
            {
                k = 0;
             switch(cur_node.tagName)
             {
              case "TABLE": children = cur_node.rows; break;
              case "TR": children = cur_node.cells; break;
              case "SELECT": children = cur_node.options; break;
              default: children = cur_node.childNodes; break;
             }
                for(var j=0; j<children.length; j++)
                {
                 if(children[j].nodeType != 1) continue;
                    if(children[j].tagName.toUpperCase() == xpath[i][0])
                    {
                        if(k == xpath[i][1])
                        {
                            cur_node = children[j];
                      found = true;
                            break;
                        }
                        
                        k++;
                    }
                }
             if(!found) return null;
            }
        }
       
        return cur_node;
    }
    // Added to have a globally accessible version (not under TeaLeaf namespace)
    window.TeaLeaf_Client_tlGetNodeFromXPath = TeaLeaf.Client.tlGetNodeFromXPath;
 /**
    * Add an event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                              
 TeaLeaf.Client.tlAddEvent = function(theEvent) {
  // Check for a null
  if( ! theEvent ) theEvent = window.event;
  // Try to mark the event so that it is not reprocessed. It will
  // depend on the browsers event model, whether the same event is
  // bubbled or a duplicate instance of it is.
  if(theEvent.tealeafMarked === true) return;
  //theEvent.tealeafMarked = true;
  // Get the target - If we have no way to identify then discard
  var itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
  if( ! itemSource ) return;
  // Send in any queued keys and resizes  
         TeaLeaf.Client.tlSendKeys();
         TeaLeaf.Client.tlSendResize();
         TeaLeaf.Client.tlSendScroll();  
  // Do we need to set the onFocus time?
  if( ! itemSource.TeaLeafFocusTime ) {
   switch(theEvent.type)
   {
    case "keyup":
    case "change":
    case "click":
    case "dblclick":
    case "mousedown":
     itemSource.TeaLeafFocusTime = new Date();
     break;
   }
  }
  
  // Ignore flash for blur
  if( theEvent.type == "blur" && itemSource.type == "application/x-shockwave-flash" ) {
   return;
  }  
  if(theEvent.type == "click" && TeaLeaf.Client.checkIsInput(itemSource)){
      TeaLeaf.Event.Configuration.tlidoflastvisitedcontrol = TeaLeaf.Client.tlGetName(itemSource);       
  }
  if(theEvent.type == "click" && (itemSource.tagName =="a" || itemSource.tagName =="A") && TeaLeaf.tlIsIE()){
      TeaLeaf.Client.Configuration.tlIEhref = false
   if(itemSource.href == "#" || itemSource.href == "javascript:void(0);" || itemSource.href == "javascript:void(0)" || itemSource.href == "javascript:;"){
                TeaLeaf.Client.Configuration.tlIEhref = true;
            }
        }
  
  // The Reporting Event
  var tlevt = new TeaLeaf.Event("GUI", theEvent.type);
  // Start the node tag
  
  var tlAddNameValueArray = ["Name", itemSource.name,
                          "Id", itemSource.id,
                    "ElementType", itemSource.type,
                          "TagName", itemSource.tagName,
                          "AltKey", theEvent.altKey?"True":null,
                          "CtrlKey", theEvent.ctrlKey?"True":null,
                          "ShiftKey", theEvent.shiftKey?"True":null,
                          "NodeName", theEvent.nodeName,
                          "NodeValue", theEvent.nodeValue,
              "XPath", TeaLeaf.Client.tlGetXPathFromNode(itemSource)];
        tlevt.tlAddData(tlAddNameValueArray);

  var tlName = TeaLeaf.Client.tlGetName(itemSource);
  if( theEvent.type == "blur" && itemSource.TeaLeafFocusTime ) {
   var now = new Date();
   var tlAddNameValueArrayTimeIn = ["TimeInControl", TeaLeaf.Event.tlDateDiff(now, itemSource.TeaLeafFocusTime)];
            tlevt.tlAddData(tlAddNameValueArrayTimeIn);
   itemSource.TeaLeafFocusTime = null;
  }
        if(itemSource.TeaLeafExclude) {
      var tlAddNameValueArrayExcluded = ["Excluded", "true"];
      tlevt.tlAddData(tlAddNameValueArrayExcluded);
  }   
        else{
            var tlManualName = TeaLeaf.Event.tlFormatXMLName(tlName);
            var tlRepValue = itemSource.TeaLeafReplace ? TeaLeaf.Client.tlReplaceValue(itemSource) : itemSource.value;
            var tlAddNameValueArrayManualName = ["ValueIn", tlManualName, 
                                                 tlManualName, tlRepValue];                            
           tlevt.tlAddData(tlAddNameValueArrayManualName);  
       }
  tlevt.tlSend();
 } 
 /**
    * Send all the form field values with the form submit.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlHandleFormSubmit = function(theEvent) {
  // Log that we did a submit - this will be send in the unload
  TeaLeaf.Client.Configuration.tlactiontype = "Submit"; 
  // Send in any queued keys and resizes
        TeaLeaf.Client.tlSendKeys();
        TeaLeaf.Client.tlSendResize();
        TeaLeaf.Client.tlSendScroll();
  // Check for a null
  if( ! theEvent ) {
   theEvent = window.event;
  }
  // Get the target - If we have no way to identify then discard
  var itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
  if( ! itemSource ) {
   return;
  }
  // If item Source.name is not definded, let's make one up
  var i;
  if( ! itemSource.name ) {
   var forms = document.forms;
   for(i = 0; i < forms.length; i++) {
    if( forms[i] == itemSource ) {
     itemSource.name = "Ordinal-" + i;
     break;
    }
   }
  }
  // We have no name - forget it.
  if( ! itemSource.name ) {
   return;
  }
  // Is this one of our silent controls
        if( TeaLeaf.Client.tlIsReplace(itemSource) ) {
            var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(itemSource);   
            var name = TeaLeaf.Client.tlGetName(itemSource);
            var tlAddNameValueArrayReplaceName = ["ValueIn", name, name,   tlRepValue]; 
            tlevt.tlAddData(tlAddNameValueArrayReplaceName);      
        }
  // The Reporting Event
  var tlevt = new TeaLeaf.Event("GUI", theEvent.type);
  // Start the node tag
        var tlAddNameValueArray = ["Name", itemSource.name,
                          "Id", itemSource.id,
                          "ElementType", itemSource.type,
                          "TagName", itemSource.tagName,
                          "AltKey", theEvent.altKey?"True":null,
                          "CtrlKey", theEvent.ctrlKey?"True":null,
                          "ShiftKey", theEvent.shiftKey?"True":null,
                          "NodeName", theEvent.nodeName,
                          "NodeValue", theEvent.nodeValue,
                          "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];
        tlevt.tlAddData(tlAddNameValueArray);
  var children = itemSource.getElementsByTagName("INPUT");
  var tlAddNameValueArrayInputFieldCount = ["InputFieldCount", children.length];
        tlevt.tlAddData(tlAddNameValueArrayInputFieldCount);
  tlevt.tlPushXML("InputFields"); 
  // Do through the children
  for(i = 0; i < children.length; i++) {
   var child = children[i];
   // No name, skip
   if( ! child.name ) {
    continue;
   }
   // Put the field tag in
   tlevt.tlPushXML("Field"+i);
            var tlAddNameValueArrayNode = ["Name", child.name,
                               "Id", child.id,
                               "ElementType", child.type,
                               "TagName", child.tagName];
            tlevt.tlAddData(tlAddNameValueArrayNode);
    
   if( TeaLeaf.Client.tlIsExcluded(name) ) {
       var tlAddNameValueArrayExcluded = ["Excluded", "true"];
       tlevt.tlAddData(tlAddNameValueArrayExcluded);
   }
   // Is this one of our silent controls
   else if( TeaLeaf.Client.tlIsReplace(child.name) ) {
                var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(child);   
                var name = TeaLeaf.Client.tlGetName(child);
                var tlAddNameValueArrayReplaceName = ["ValueIn", name,name,   tlRepValue]; 
                tlevt.tlAddData(tlAddNameValueArrayReplaceName);      
   }
   else {
    var tlManualName = TeaLeaf.Event.tlFormatXMLName(child.name);
       var tlAddNameValueArrayManualName = ["ValueIn", tlManualName, tlManualName, child.value];
                tlevt.tlAddData(tlAddNameValueArrayManualName);
   }
   tlevt.tlPopXML();
  }
  tlevt.tlPopXML();
  tlevt.tlSend();
  TeaLeaf.Event.Configuration.tlvisitorder = "";
 }
 /**
    * Handle the resize event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlQueueResize = function(tlEvent) {
  TeaLeaf.Client.tlSendKeys();
  TeaLeaf.Client.tlSendScroll();
  if( ! tlEvent ) {
   tlEvent = window.event;
  }
  if( tlEvent.clientX) {
   TeaLeaf.ResizeClientX = tlEvent.clientX;
   TeaLeaf.ResizeClientY = tlEvent.clientY;
   TeaLeaf.ResizeScreenX = tlEvent.screenX;
   TeaLeaf.ResizeScreenY = tlEvent.screenY;
  }
  else {
   TeaLeaf.ResizeClientX = tlEvent.target.width;
   TeaLeaf.ResizeClientY = tlEvent.target.height;
  }
 }
 /**
    * Handle the form reset event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlHandleFormReset = function(theEvent) {
  // Send in any queued keys and resizes
  TeaLeaf.Client.tlSendKeys();
  TeaLeaf.Client.tlSendResize();
  TeaLeaf.Client.tlSendScroll();
  // Check for a null
  if( ! theEvent ) {
   theEvent = window.event;
  }
  // Get the target - If we have no way to identify then discard
  var itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
  if( ! itemSource ) {
   return;
  }
  // If item Source.name is not definded, let's make one up
  var i;
  if( ! itemSource.name ) {
   var forms = document.forms;
   for(i = 0; i < forms.length; i++) {
    if( forms[i] == itemSource ) {
     itemSource.name = "Ordinal-" + i;
     break;
    }
   }
  }
  // We have no name - forget it.
  if( name == null ) {
   return;
  }
  // Is this one of our silent controls
  if( TeaLeaf.Client.tlIsReplace(itemSource) ) {
      var tlRepValue = TeaLeaf.Client.tlGetReplaceValue(itemSource);   
            var tlname = TeaLeaf.Client.tlGetName(itemSource);
            var tlAddNameValueArrayReplaceName = ["ValueIn", tlname,
                                                tlname,   tlRepValue]; 
            tlevt.tlAddData(tlAddNameValueArrayReplaceName);
  }
  // The Reporting Event
  var tlevt = new TeaLeaf.Event("GUI", theEvent.type);
  // Start the node tag
        var tlAddNameValueArray = ["Name", itemSource.name,
                          "Id", itemSource.id,
                          "ElementType", itemSource.type,
                          "TagName", itemSource.tagName,
                          "AltKey", theEvent.altKey?"True":null,
                          "CtrlKey", theEvent.ctrlKey?"True":null,
                          "ShiftKey", theEvent.shiftKey?"True":null,
                          "NodeName", theEvent.nodeName,
                          "NodeValue", theEvent.nodeValue,
                          "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];
        tlevt.tlAddData(tlAddNameValueArray);
  tlevt.tlSend();
  TeaLeaf.tlVisitOrder = "";
 } 
 /**
    * Handle the before unload event and flush the queue of events client events captured.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlBeforeUnload = function() {
     // Only let this fire once
     if(TeaLeaf.Client.tlBeforeUnloadFired) return;
     TeaLeaf.Client.tlBeforeUnloadFired = true;
        if(TeaLeaf.Client.Configuration.tlIEhref){
           TeaLeaf.Client.Configuration.tlIEhref = false;
           return;
        }
     // If configured to do so, store the current event queue xml in a cookie
     // so if it fails to send up it can be sent with the next page's events
     if(typeof TeaLeaf.Cookie != "undefined" && TeaLeaf.Client.Configuration.tlStoreQueueInCookie){
      var d = new Date();
      d.setTime(d.getTime()+300000);
      var cookie_val = TeaLeaf.Event.tlQueuedXML.replace(/(\r|\n)/g, "").replace(/;/g, "%3B");
      TeaLeaf.Cookie.tlSetCookieValue("tlQueuedXML", cookie_val, d, "/");
     }
        if(TeaLeaf.Client.Configuration.tlbeforeunloadflag == true){ 
            TeaLeaf.Event.Configuration.tllastdwelltime = new Date();
            TeaLeaf.Client.Configuration.tlunloadflag = false;   
   
      // Send in the notice
      var tlevt = new TeaLeaf.Event("PERFORMANCE", "BeforeUnload"); 
      TeaLeaf.Event.SetType = tlevt.EventType;
      if(TeaLeaf.Event.SetSubType == ""){
                TeaLeaf.Event.SetSubType = tlevt.EventSubType;
            }
            else{
                TeaLeaf.Event.SetSubType += "; " + tlevt.EventSubType;
            }                    
            TeaLeaf.Event.Configuration.tlbeforeunloadflag = true;
            var tlAddNameValueArray = ["MouseMove", TeaLeaf.Client.tlHasUserMovement?"TRUE":"FALSE",
                                          "Action", TeaLeaf.Client.Configuration.tlactiontype, 
                                          "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];          
            tlevt.tlAddData(tlAddNameValueArray);
            TeaLeaf.Event.Configuration.tlasync = false;          
      tlevt.tlSend();
 
      TeaLeaf.Event.tlFlushQueue(true);
      TeaLeaf.Event.Configuration.tlvisitorder = "";
      TeaLeaf.Client.tlDetachFromAllControls();
  }
 }
 /**
    * Handle the unload event and flush the queue of events client events captured.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                 
 TeaLeaf.Client.tlUnload = function(){
        if( TeaLeaf.Client.Configuration.tlunloadflag ){         
            TeaLeaf.Event.Configuration.tllastdwelltime = new Date();
            TeaLeaf.Client.Configuration.tlbeforeunloadflag = false;
      // Send in the notice
      var tlevt = new TeaLeaf.Event("PERFORMANCE", "Unload");
      TeaLeaf.Event.SetType = tlevt.EventType;
      
      if(TeaLeaf.Event.SetSubType == ""){
                TeaLeaf.Event.SetSubType = tlevt.EventSubType;
            }
            else{
                TeaLeaf.Event.SetSubType += "; " + tlevt.EventSubType;
            }
            var tlAddNameValueArray = ["MouseMove", TeaLeaf.Client.tlHasUserMovement?"TRUE":"FALSE",
                                 "Action", TeaLeaf.Client.Configuration.tlactiontype, 
                                 "VisitOrder", TeaLeaf.Event.Configuration.tlvisitorder];
            tlevt.tlAddData(tlAddNameValueArray);
            TeaLeaf.Event.Configuration.tlasync = false;
      tlevt.tlSend();
      TeaLeaf.Event.tlFlushQueue(true);
      TeaLeaf.Event.Configuration.tlvisitorder = "";
      TeaLeaf.Client.tlDetachFromAllControls();
        }
 }
 /**
    * Attach listeners to all controls including controls in frames.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlAttachToAllControls = function() {
        //TeaLeaf.Client.tlMarkBlocked();
  TeaLeaf.Client.Configuration.tlcontrolsattached = true;
  // Attach to the main window
  TeaLeaf.Client.tlAttachToControls(window);
  // Attach to the frame controls
        try{
   var ind;
   for(ind = 0; ind < window.frames.length; ind++) {
    if(window == window.frames[ind]) continue;
    TeaLeaf.Client.tlAttachToControls(window.frames[ind]);
   }
  }
  catch(e){}
 }
 
 /**
    * Attach listeners for specified events to specified controls.
    * 
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlSingleAttach = function() { 
     var tldomsingleelements = TeaLeaf.Client.Configuration.tlSingleAttach;
 
        for(var i=0; i<tldomsingleelements.length; i++){      
            if(tldomsingleelements[i].domelementID
                    && tldomsingleelements[i].domelementID !=""){                
                var tlelement = document.getElementById(tldomsingleelements[i].domelementID);
                if(tlelement){
                    var func = eval(tldomsingleelements[i].tlhandler);
                    TeaLeaf.Event.tlAddHandler(tlelement, tldomsingleelements[i].domevent, func, false);   
                }            
            }
        }
 }
 /**
    * Attach listeners to controls based on the configuration. It also attaches 
    * 'beforeunload' and 'unload' handlers.
    * @param win window object.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlAttachToControls = function(win) {
            try{
                TeaLeaf.Event.tlAddHandler(win, "beforeunload", eval(TeaLeaf.Client.tlBeforeUnload), false);
                TeaLeaf.Event.tlAddHandler(win, "unload", eval(TeaLeaf.Client.tlUnload), false);
                // Attach to all listeners for all the window and document
                //controls.
                var handlers = TeaLeaf.Client.Configuration.tlWindowHandlers;
                for(var i=0; i<handlers.length; i++) {
                    if(handlers[i].load == true){
                        var func = eval(handlers[i].tlhandler);
                        TeaLeaf.Event.tlAddHandler(win, handlers[i].domevent, func, false);
                    }
                }
                handlers = TeaLeaf.Client.Configuration.tlDocumentHandlers;
                for(var i=0; i<handlers.length; i++) {
                    if(handlers[i].load == true){
                        var func = eval(handlers[i].tlhandler);
                        TeaLeaf.Event.tlAddHandler(win.document, handlers[i].domevent, func, false);
                    }
                }
                // Look for the individual controls
  TeaLeaf.Client.tlProcessNode(win.document.body);
                //TeaLeaf.Client.tlCheckIndControls(win);
            }
            catch (e) { }
 }
 /**
    * Check if a handler is attached to a control, otherwhise,
    * if the control is INPUT or SELECT attach focus, blur and change 
    * @param control control to check.
    * @requires 
    * TeaLeafEvent.js
    * @addon
    */                                                                                 
 TeaLeaf.Client.tlCheckAttach = function(control) { 
  // Already got this control
  if( control.TeaLeaf || control.TeaLeafExclude) return;
  control.TeaLeaf = true;
  if(TeaLeaf.Client.Configuration.tlassignTLID)
   TeaLeaf.Client.tlAddIdToControl(control);
    TeaLeaf.Client.tlMakeFieldBlockMap();
  // Double check for the listed tagnames. If it matches, attach
  // for focus, blur and change, since the document object won't see these
  switch(control.tagName)
  {
   case "INPUT":
   case "SELECT":
   case "TEXTAREA":
    if( TeaLeaf.Client.Configuration.tlsendfocus ) {
                       TeaLeaf.Event.tlAddHandler(control, 'focus',  TeaLeaf.Client.tlSetFocusTime, false);
    }    
    if( TeaLeaf.Client.Configuration.tlsendblur ) {
                          TeaLeaf.Event.tlAddHandler(control, 'blur',   TeaLeaf.Client.tlHandleBlur, false);
    }
    TeaLeaf.Event.tlAddHandler(control, 'change', TeaLeaf.Client.tlAddEvent, false);
    // check if we need to block this node
    item_name = TeaLeaf.Client.tlGetName(control);
    if(item_name == null) break;
    lower_item_name = item_name.toLowerCase();
    map_item = TeaLeaf.Client.Configuration.tlFieldBlockMap[lower_item_name];
    if(map_item == null) break;
    if(map_item["tlfieldname"] == item_name ||
            (map_item["caseinsensitive"] && map_item["tlfieldname"] == lower_item_name))
    {
     control.TeaLeafExclude = map_item["eventnovalue"];
     control.TeaLeafReplace = map_item["eventvaluereplace"].length > 0;
    }
    break;
  }
  if(TeaLeaf.Client.Configuration.tlUniversalAttach) 
  {
       var handlers = TeaLeaf.Client.Configuration.tlDocumentHandlers;
      for(var i=0; i<handlers.length; i++)
        {
           if(handlers[i]["load"])
        TeaLeaf.Event.tlAddHandler(control, handlers[i]["domevent"], eval(handlers[i]["tlhandler"]), false);
      }
  }
 }
 /**
    * Attach to INPUT and SELECT. 
    * @param win window object.
    * @addon
    */                                                                                  
 TeaLeaf.Client.tlCheckIndControls = function(win) {
            try{
                if(win.document){  
                    var items = win.document.getElementsByTagName("INPUT");        
                    for(var i = 0; i < items.length; i++) {   
                        TeaLeaf.Client.tlCheckAttach(items[i]);
                    } 
                    items = win.document.getElementsByTagName("SELECT");
                    for(var i = 0; i < items.length; i++) {
                        TeaLeaf.Client.tlCheckAttach(items[i]);
                    }
                    items = win.document.getElementsByTagName("BODY"); 
                    if(items.length>0){  
                        items = items[0].getElementsByTagName("*");         
                        for(var i = 0; i < items.length; i++) {
                            TeaLeaf.Client.tlCheckAttach(items[i]);
                        }
                    }
                }
            }
            catch(e) { }
        }
      
    /**
    * Attach to the given DOM node and all descendants 
    * @param obj DOM object
    * @param ignore_descendants (Optional) boolean to ignore child nodes
    * @addon
    */  
    TeaLeaf.Client.tlProcessNode = function(obj, ignore_descendants) {
 if(typeof(obj) == "string") obj = document.getElementById(obj);
 if(obj == null) return;
        try{
  switch(obj.tagName)
  {
   case "INPUT":
   case "SELECT":
   case "TEXTAREA":
    TeaLeaf.Client.tlCheckAttach(obj);
    break;
   default:
           if(TeaLeaf.Client.Configuration.tlUniversalAttach && TeaLeaf.Client.tlTagNameAllowed(obj.tagName))
     TeaLeaf.Client.tlCheckAttach(obj);
    break;
  }
  if(!ignore_descendants)
  {
   var explicit_tags = ["INPUT","SELECT","TEXTAREA"];
   for(var i=0; i<explicit_tags.length; i++)
   {
    items = obj.getElementsByTagName(explicit_tags[i]);
                      for(var j=0; j<items.length; j++)
                          TeaLeaf.Client.tlCheckAttach(items[j]);
   }
   if(TeaLeaf.Client.Configuration.tlUniversalAttach)
   {
    if(TeaLeaf.Client.Configuration.tlExcludeTags)
    {
               items = obj.getElementsByTagName("*");
                for(var i = 0; i < items.length; i++) {
                 if(TeaLeaf.Client.tlTagNameAllowed(items[i].tagName))
                       TeaLeaf.Client.tlCheckAttach(items[i]);
                }
    }
    else
    {
     for(var i in TeaLeaf.Client.Configuration.tlNodeTags)
     {
      items = obj.getElementsByTagName(i);
      for(var j=0; j<items.length; j++)
       TeaLeaf.Client.tlCheckAttach(items[j]);
     }
    }
   }
  }
        }
 catch(e) {}
    }
 /**
    * Handle focus event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                                   
 TeaLeaf.Client.tlSetFocusTime = function(theEvent) {
  // Check for a null
  if( ! theEvent ) {
   theEvent = window.event;
  }
  // We need the item source.  Ignore flash
  var itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
  if( ! itemSource || itemSource.type == "application/x-shockwave-flash" ) {
   return;
  }
  // Get the target - If we have no way to identify then discard
  var itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
  if( ! itemSource ) {
   return;
  }
  if( ! itemSource.TeaLeafFocusTime ) {
   itemSource.TeaLeafFocusTime = new Date();
  }
  // If we are sending the focus event, then send it!
  if(TeaLeaf.Client.Configuration.tlsendfocus ) {
   TeaLeaf.Client.tlAddEvent(theEvent);
  }
 } 
 /**
    * Handle blur event.
    * @param theEvent DOM event.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                                   
 TeaLeaf.Client.tlHandleBlur = function(theEvent) {
  // Check for a null
  if( ! theEvent ) {
   theEvent = window.event;
  }
  // We need the item source.  Ignore flash
  var itemSource = TeaLeaf.Client.tlGetEventSource(theEvent);
  if( ! itemSource || itemSource.type == "application/x-shockwave-flash" ) {
   return;
  }
  TeaLeaf.Client.tlEndVisit(itemSource);
  if(TeaLeaf.Client.checkIsInput(itemSource))
   TeaLeaf.Event.Configuration.tlidoflastvisitedcontrol = TeaLeaf.Client.tlGetName(itemSource);
  // Send the event?
  if( TeaLeaf.Client.Configuration.tlsendblur ) {
   TeaLeaf.Client.tlAddEvent(theEvent);
  }
 }
 /**
    * Last element visited.
    * @param itemSource DOM element.
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                                   
 TeaLeaf.Client.tlEndVisit = function(itemSource) {
  if( itemSource.TeaLeafFocusTime ) {
   var name = TeaLeaf.Client.tlGetName(itemSource);
   if( ! name ) {
    name = TeaLeaf.Client.tlGetAnchor(itemSource, false);
    if( name ) {
     name = "LEVEL" + name;
    }
    else {
     name = "unnamed";
    }
   }
   var diff = TeaLeaf.Event.tlDateDiff(itemSource.TeaLeafFocusTime, new Date());
   var entry = name + ':' + diff;
   if( TeaLeaf.Event.Configuration.tlvisitorder != "")
    TeaLeaf.Event.Configuration.tlvisitorder = TeaLeaf.Event.Configuration.tlvisitorder + ";" + entry;
   else
    TeaLeaf.Event.Configuration.tlvisitorder = entry;
  }
 }
 /**
    * Detach from all controls including frames.
    *
    * @requires 
    * TeaLeafClientCfg.js
    * @addon
    */                                                                                   
 TeaLeaf.Client.tlDetachFromAllControls = function() {
  // Mark as not attached
  TeaLeaf.Client.Configuration.tlcontrolsattached = false;
  // Attach to this window
  TeaLeaf.Client.tlDetachFromControls(window);
  // Do the frames
  try{
   var ind;
   for(ind = 0; ind < window.frames.length; ind++) {
    var w = window.frames[ind];
    TeaLeaf.Client.tlDetachFromControls(w);
   }
  }
  catch(e){}
 }
 /**
    * Detach listeners to controls based on the configuration. 
    * @param win window object.
    * @requires 
    * TeaLeafClientCfg.js
    * TeaLeafEvent.js
    * @addon
    */                                                                                
 TeaLeaf.Client.tlDetachFromControls = function(win) {
 try{
     var handlers = TeaLeaf.Client.Configuration.tlWindowHandlers;
     for(var i=0; i<handlers.length; i++) {
         var func = eval(handlers[i].tlhandler);
         TeaLeaf.Event.tlRemoveHandler(win, handlers[i].domevent, func, false);
     }
     handlers = TeaLeaf.Client.Configuration.tlDocumentHandlers;
     for(var i=0; i<handlers.length; i++) {
         var func = eval(handlers[i].tlhandler);
         TeaLeaf.Event.tlRemoveHandler(win.document, handlers[i].domevent, func, false);
     }
     // Detach from Individual Items
     var items = win.document.getElementsByTagName("INPUT");
     var i;
     for(i = 0; i < items.length; i++) {
         TeaLeaf.Event.tlRemoveHandler(items[i], 'change', TeaLeaf.Client.tlAddEvent, false);
         TeaLeaf.Event.tlRemoveHandler(items[i], 'focus',  TeaLeaf.Client.tlSetFocusTime, false);
            TeaLeaf.Event.tlRemoveHandler(items[i], 'blur',   TeaLeaf.Client.tlHandleBlur, false);
         items[i].TeaLeaf = false;
     }
     items = win.document.getElementsByTagName("SELECT");
     for(i = 0; i < items.length; i++) {
         TeaLeaf.Event.tlRemoveHandler(items[i], 'change', TeaLeaf.Client.tlAddEvent, false);
         TeaLeaf.Event.tlRemoveHandler(items[i], 'focus',  TeaLeaf.Client.tlSetFocusTime, false);
            TeaLeaf.Event.tlRemoveHandler(items[i], 'blur',   TeaLeaf.Client.tlHandleBlur, false);
         items[i].TeaLeaf = false;
     }
 } 
 catch(e) { }
  }
  /**
  * Attach a listener to a specific control. 
  * @param domelement DOM element.
  * @param eventtype TeaLeaf Event type.
  * @param eventHandler Event handler.
  * @requires 
  * TeaLeafEvent.js
  * @addon
  */                                                                                  
  TeaLeaf.Client.tlAttachToControl = function(domelement, eventtype, eventHandler) {
    if(eventHandler){
        TeaLeaf.Event.tlAddHandler(domelement, eventtype, eventHandler, false);
    }
    else{
        TeaLeaf.Event.tlAddHandler(domelement, eventtype, eval(TeaLeaf.Client.tlAddEvent), false);
    }
  }
  /**
  * Detach a listener to a specific control. 
  * @param domelement DOM element.
  * @param eventtype TeaLeaf Event type.
  * @param eventHandler Event handler.
  * @requires 
  * TeaLeafEvent.js
  * @addon
  */                                                                                  
  TeaLeaf.Client.tlDetachFromControl = function(domelement, eventtype, eventHandler) {
    if(eventHandler){
        TeaLeaf.Event.tlRemoveHandler(domelement, eventtype, eventHandler, false);
    }
    else{
        TeaLeaf.Event.tlRemoveHandler(domelement, eventtype, eval(TeaLeaf.Client.tlAddEvent), false);
    }
  }
  /**
  * Mark the blocked fields based on the configuration. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */       
  TeaLeaf.Client.tlMarkBlocked = function(items) { 
 // Got through all the input fields and see which ones
 // should be blocked.
   TeaLeaf.Client.tlMakeFieldBlockMap();
   if(items == null) items = document.getElementsByTagName("INPUT");
   for(var i=0; i<items.length; i++)
   {
  item_name = TeaLeaf.Client.tlGetName(items[i]);
  if(item_name == null) continue;
  lower_item_name = item_name.toLowerCase();
  map_item = TeaLeaf.Client.Configuration[lower_item_name];
  if(map_item == null) continue;
  if(map_item["tlfieldname"] == item_name ||
     (map_item["caseinsensitive"] && map_item["tlfieldname"] == lower_item_name))
  {
   items[i].TeaLeafExclude = map_item["eventnovalue"];
   items[i].TeaLeafReplace = map_item["eventvaluereplace"].length > 0;
  }
  }
  }  
  /**
  * Scan the DOM based on a timer set in the configuration and attach
  * to controls that might have been rendered due to a DOM update. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */                                                                                  
   TeaLeaf.Client.tlScanForAdditions = function() {
     if(!TeaLeaf.Client.Configuration.tlScheduledScan) return;
  // Attach to the main window
  //TeaLeaf.Client.tlCheckIndControls(window);
  TeaLeaf.Client.tlProcessNode(document.body);
  // attach to the frames
  try{
   for(var i=0; i<window.frames.length; i++) {
    var w = window.frames[i];
    TeaLeaf.Client.tlProcessNode(w.document.body);
    //TeaLeaf.Client.tlCheckIndControls(w);
   }   
  }
  catch(e){} 
  
  window.clearTimeout(TeaLeaf.Client.tlTimeoutID); 
  TeaLeaf.Client.tlTimeoutID = window.setTimeout(TeaLeaf.Client.tlScanForAdditions, TeaLeaf.Client.Configuration.tlscanupdate);  
 }
 TeaLeaf.Client.tlTagNameAllowed = function(tag) {
     if(tag == null) 
         return false;
     var tagVal = TeaLeaf.Client.Configuration.tlNodeTags[tag];     
     if(tagVal == null) 
         tagVal = false; 
     if(TeaLeaf.Client.Configuration.tlExcludeTags) 
         return !tagVal;
     else 
         return tagVal;
 }
 TeaLeaf.Client.tlMakeFieldBlockMap = function() {
     if(TeaLeaf.Client.Configuration.tlFieldBlockMap != null) return;
  TeaLeaf.Client.Configuration.tlFieldBlockMap = {};
  var fields = TeaLeaf.Client.Configuration.tlFieldBlock;
  for(var i=0; i<fields.length; i++){
      name = fields[i]["tlfieldname"];
   if(name == null) continue;
   else name = name.toLowerCase();
   if(fields[i]["caseinsensitive"]) fields[i]["tlfieldname"] = name;
   TeaLeaf.Client.Configuration.tlFieldBlockMap[name] = fields[i];
  }
 }
  /**
  * Start registering DOM listeners based on the config options. 
  * NOTE: This function is ment to be used in SDK mode. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */                                                                                  
   TeaLeaf.Client.tlStartListeners = function() {
     // Get the lists we want to get
  TeaLeaf.Client.tlAttachToAllControls(); 
  TeaLeaf.Client.tlSingleAttach();
   }
  /**
  * Unregister DOM listeners based on the config options. 
  * NOTE: This function is ment to be used in SDK mode. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */                                                                                  
   TeaLeaf.Client.tlEndListeners = function() {
     TeaLeaf.Event.tlFlushQueue(true);
        TeaLeaf.Client.tlDetachFromAllControls();
   }
  /**
  * Sends the value of the specified element. 
  * NOTE: This function is ment to be used explicitly. 
  *
  * @requires 
  * TeaLeafClientCfg.js
  * @addon
  */                                                                                 
  TeaLeaf.Client.tlSendValueChange = function(tlElement, tleventtosend) {
      var tlevt = new TeaLeaf.Event("GUI", tleventtosend);
      //    Start the node tag
      var tlAddNameValueArray = ["Name", tlElement.name, 
                                "Id", tlElement.id, 
                                "ElementType", tlElement.type];
      tlevt.tlAddData(tlAddNameValueArray);
      var tlName = TeaLeaf.Client.tlGetName(tlElement);
      var tlManualName = TeaLeaf.Event.tlFormatXMLName(tlName);
      var tlRepValue = tlElement.TeaLeafReplace ? TeaLeaf.Client.tlReplaceValue(tlElement) : tlElement.value;
      var tlAddNameValueArrayManualName = ["ValueIn", tlManualName, 
                                            tlManualName, tlRepValue ];                            
      tlevt.tlAddData(tlAddNameValueArrayManualName);        
      tlevt.tlSend();
  }
 
  /**
  * Setup function that attaches to all the controls on the page. 
  * @addon
  */                                                        
  TeaLeaf.Client.tlSetup = function() {
    // If a previous event queue was stored in the cookie, apply it to the current queue
  if(typeof TeaLeaf.Cookie != "undefined")
  {
   var queuedXML = TeaLeaf.Cookie.tlGetCookieValue("tlQueuedXML");
   if(queuedXML != null && queuedXML != "")
    TeaLeaf.Event.tlQueuedXML += queuedXML.replace(/%3B/g, ";");
  }
  // Get the lists we want to get
  TeaLeaf.Client.tlAttachToAllControls(); 
  TeaLeaf.Client.tlSingleAttach();
  
  // Hook on to the window open
  window.OrigOpen = window.open;
  window.open = function(url,name,features,replace) {
   var numberArgs = arguments.length;
   var status = "blocked";
   var subWin = window.OrigOpen(url, name, features, replace);
   try {
    if(!subWin.closed)
     status = "visible";
   }
   catch(exc) {
    if( TeaLeaf.Event.Configuration.tlshowexceptions ) {
     alert(exc.name + ": " + exc.message + "\r\n\r\nPos 8");
    }
   };
   var tlevt = new TeaLeaf.Event("GUI", "WindowOpen"); 
   var tlAddNameValueArray = ["Status", status, 
                           "Url", escape(url),
                           "Name", name, 
                           "Features", features, 
                           "Replace", replace];
   tlevt.tlAddData(tlAddNameValueArray);
   tlevt.tlSend(); 
   return subWin;
  }; 
  
  // At this point, lets scan periodically for added controls
  window.clearTimeout(TeaLeaf.Client.tlTimeoutID);
  
  if(TeaLeaf.Client.Configuration.tlscanupdate >0 ){
            TeaLeaf.Client.tlTimeoutID = window.setTimeout(TeaLeaf.Client.tlScanForAdditions, TeaLeaf.Client.Configuration.tlscanupdate);
        }
    }  
 /**
    * Initialize the call to tlSetup UI Client Event
    * Capture is not used as an SDK.
    * @requires
    * TeaLeafEvent.js
    * @addon
    */                                                        
 TeaLeaf.Client.CallInit = function() { 
        TeaLeaf.Event.tlRemoveHandler(window, "beforeunload", eval(TeaLeaf.Client.tlBeforeUnload), false);
        TeaLeaf.Event.tlRemoveHandler(window, "unload", eval(TeaLeaf.Client.tlUnload), false);
     TeaLeaf.addOnLoad(TeaLeaf.Client.tlSetup);
 }
    if(TeaLeaf.Client.Configuration.tlinit == false){
        TeaLeaf.Client.Configuration.tlinit = true;
     TeaLeaf.Client.CallInit();  
 }
}