//
//	$Source$
//	$Date: 2004-06-29 23:18:39 -0700 (Tue, 29 Jun 2004) $
//	$Revision: 824 $
//
//	Copyright 2003-2004 Repomanager 
//	Mike Carlton <carlton@repomanager.com>
//

// Extracted from
// http://www.oreillynet.com/pub/a/javascript/2003/09/03/dannygoodman.html
// including patch for tab and keypad
/***************
   "search"
  select Element Type-Ahead for IE/Windows by Danny Goodman (www.dannyg.com)
  A bonus recipe for readers of O'Reilly's
    "JavaScript & DHTML Cookbook"
  This recipe first published at O'Reilly Network (www.oreillynet.com)
  For full implementation notes, read the article.
****************/
   
// global storage object for type-ahead info, including reset() method
var typeAheadInfo = {last:0, 
                     accumString:"", 
                     delay:500,
                     timeout:null, 
                     reset:function() {this.last=0; this.accumString=""}
                    };
// function invoked by select element's onkeydown event handler
function typeAhead() {
   // limit processing to IE event model supporter; don't trap Ctrl+keys
   if (window.event && !window.event.ctrlKey) {
      // timer for current event
      var now = new Date();
      // process for an empty accumString or an event within [delay] ms of last
      if (typeAheadInfo.accumString == "" || now - typeAheadInfo.last < typeAheadInfo.delay) {
         // make shortcut event object reference
         var evt = window.event;
         // get reference to the select element
         var selectElem = evt.srcElement;
         // get typed character ASCII value
         var charCode = evt.keyCode;
		 if (charCode == 9) { return true; }		// patched
		 // correct for NumPad digits
		 if (charCode >= 96 && charCode <=105) {	// patched
			charCode = charCode - 48;
		 }
         // get the actual character, converted to uppercase
         var newChar =  String.fromCharCode(charCode).toUpperCase();
         // append new character to accumString storage
         typeAheadInfo.accumString += newChar;
         // grab all select element option objects as an array
         var selectOptions = selectElem.options;
         // prepare local variables for use inside loop
         var txt, nearest;
         // look through all options for a match starting with accumString
         for (var i = 0; i < selectOptions.length; i++) {
            // convert each item's text to uppercase to facilitate comparison
            // (use value property if you want match to be for hidden option value)
            txt = selectOptions[i].text.toUpperCase();
            // record nearest lowest index, if applicable
            nearest = (typeAheadInfo.accumString > txt.substr(0, typeAheadInfo.accumString.length)) ? i : nearest;
            // process if accumString is at start of option text
            if (txt.indexOf(typeAheadInfo.accumString) == 0) {
               // stop any previous timeout timer
               clearTimeout(typeAheadInfo.timeout);
               // store current event's time in object 
               typeAheadInfo.last = now;
               // reset typeAhead properties in [delay] ms unless cleared beforehand
               typeAheadInfo.timeout = setTimeout("typeAheadInfo.reset()", typeAheadInfo.delay);
               // visibly select the matching item
               selectElem.selectedIndex = i;
               // prevent default event actions and propagation
               evt.cancelBubble = true;
               evt.returnValue = false;
               // exit function
               return false;   
            }            
         }
         // if a next lowest match exists, select it
         if (nearest != null) {
            selectElem.selectedIndex = nearest;
         }
      } else {
         // not a desired event, so clear timeout
         clearTimeout(typeAheadInfo.timeout);
      }
      // reset global object
      typeAheadInfo.reset();
   }
   return true;
}


