// GoogleSuggest.js
/*
1. Takes the value in the input field element and passes it to the server using AJAX

2. Processes the XML returned from the server places in a DIV element using insertHTML

INSTALLATION
Place a reference to this file in the head of the HTML:
<head runat="server">
    <title>OMEGAnet</title>
    <link rel="Stylesheet" type="text/css" href=/Utils/Styles.css />
    <script type="text/javascript" src="/Utils/AJAX.js" ></script>
    <script type="text/javascript" src="/Utils/GoogleSuggest.js" ></script>    
</head>

2. In the HTML body, place the following Javascript after the InputElement:
Search:& <asp:TextBox runat="server" id="INPUT_ELEMENT_ID" type="text"  autocomplete="off" />
<script language="javascript" type="text/javascript">
objGoogleSuggest.Setup("/Utils/GetDDLItemsFromLDAP.aspx","Text","INPUT_ELEMENT_ID");
</script>

3. Finally, set the autocomplete to off on the input element:
<input type=text id="INPUT_ELEMENT_ID" autocomplete="off">

4. [.NET ONLY] To compute the INPUT_ELEMENT_ID on a .NET page, use (typically in PopulateForeignControls() )

    Control Ctrl = myDBAccess.GetControlWithID(Controls, "INPUT_ELEMENT_ID");
    if (Ctrl.UniqueID != null)
    {
        DDLID = Ctrl.ClientID;
        //DDLID = Ctrl.UniqueID.Replace("$","_");
    } 
    
    AND in the Javascript, use <%= DDLID %> in place of "INPUT_ELEMENT_ID" in the objGoogleSuggest:
    
    <script language="javascript" type="text/javascript">
objGoogleSuggest.Setup("/Utils/GetDDLForTemplateItemsAsXML.aspx","Text","<%= DDLID %>");
</script>

*/
var _XMLUrl, _InputVarForXMLUrl;
var _InputElementID;
var _SuggestionsListContainerDiv = null;
var _HighlightColor = "#FF6D00";//"#3165CE"; // Google's blue
var _TextColorOnHighLight = "white";
var _BackgroundColor = "white";
var _TextColorNormal = "black";


var objGoogleSuggest = {

    Setup: function (XMLUrl,InputVarForXMLUrl,InputElementID) {
        _XMLUrl = XMLUrl;
        _InputVarForXMLUrl = InputVarForXMLUrl
        _InputElementID = InputElementID;

        // Add the onKeyUp attribute to the Input Element to get suggestions
        objGoogleSuggest.addEvent(document.getElementById(_InputElementID),"keyup", objGoogleSuggest.GetSuggestions); 

    }, // end of Setup
    
    GetSuggestions: function (e) {
            //alert("element ID = " + event.srcElement.id); // or event.target.id 
            // identify input element in a cross-browser fashion
            if (window.event) {
                _InputElementID = window.event.srcElement.id;
            }  else if (e) {
                _InputElementID = e.target.id; // non-IE, ie Firefox
            }  else return;
            /*
            try {
                _InputElementID = event.target.id; // non-IE, i.e. Firefox
            } catch (ex) {
                _InputElementID = event.srcElement.id;
            }
            */
            // Using AJAX get suggested matches
            var XmlDoc = _XMLUrl + "?" + _InputVarForXMLUrl + "=" + document.getElementById(_InputElementID).value;
            //alert(XmlDoc);
            objAJAX.loadXMLDoc(XmlDoc + "&" + new Date().getTime(), "objGoogleSuggest.BuildDropDownOptionsFromXML(XMLFromServer)");  
        return;
    }, // end of Suggest function

    BuildDropDownOptionsFromXML: function (DropDownOptionsXML) {
        if (_SuggestionsListContainerDiv) {
            _SuggestionsListContainerDiv.innerHTML = "";
            objGoogleSuggest.HideSuggestionsDiv();
        }
        /*  
        This function takes an XML document in which the drop down options are 
        are listed within XML tags, and creates the drop down options.
        <DropDownOptions>
            <DropDownOption>
                <Text>Option1 Text</Text>
                <Value>Option1 Value</Value>
            </DropDownOption>
            <DropDownOption>
                <Text>Option2 Text</Text>
                <Value>Option2 Value</Value>
            </DropDownOption>
        </DropDownOptions>
        NOTE: Because of the way this function is written, the actual names of 
        tags are not important. The structure, where the individual options tags are listed 
        or nested under a top level container tag, is important.

        1. First step is to get the  <DropDownOption> nodes within the
        <DropDownOptions> tag.
        This is achieved simply by defining an "DropDownOptions" array and setting
        it as follows:
        var DropDownOptions = objXMLReq.responseXML.getElementsByTagName("DropDownOption");
        Note the "SecondList" argument - not "DropDownOptions" since we are interested
        in the "DropDownOption' nodes in the XML tree.

        Next, to access the tags, within a "DropDownOption" tag, use:
        var text = DropDownOptions[i].firstChild.nodeValue;
        Hence, we use the .firstChild.nodeValue to get the value.
        */
                    var DropDownOptionsContainer = DropDownOptionsXML;
                    /////////////////////////////////////////////
                    /*
                    ADD NEW ELEMENT FOR SUGGESTIONS LIST
                    
                    Summary of steps:
                    1. Create new element 
                         - 1.1 Assign styles
                         - 1.2 Set size
                    2. Append to document.body using the .appendChild method
                    */ 
                    //
                    // 1. Create new element and assign styles :
                    _SuggestionsListContainerDiv = document.createElement("DIV");
                    _SuggestionsListContainerDiv.id = "SuggestionsListContainerDiv";
                    // 1.1 Assign styles
                    _SuggestionsListContainerDiv.style.borderRight="black 1px solid";
                    _SuggestionsListContainerDiv.style.borderLeft="black 1px solid";
                    _SuggestionsListContainerDiv.style.borderTop="black 1px solid";
                    _SuggestionsListContainerDiv.style.borderBottom="black 1px solid";
                    _SuggestionsListContainerDiv.style.zIndex="1";
                    _SuggestionsListContainerDiv.style.paddingRight="0";
                    _SuggestionsListContainerDiv.style.paddingLeft="0";
                    _SuggestionsListContainerDiv.style.paddingTop="0";
                    _SuggestionsListContainerDiv.style.paddingBottom="0";
                    _SuggestionsListContainerDiv.style.overflow = "hidden";
                    _SuggestionsListContainerDiv.style.visibility="visible";
                    _SuggestionsListContainerDiv.style.position="absolute";
                    _SuggestionsListContainerDiv.style.backgroundColor="white";
                    // 1.2 Set Size
                    // Obtain width in cross-browser fashion  
                    // Left and top are obtained by recursively working 
                    // up the parent elements Left and Top properties. 
					_SuggestionsListContainerDiv.style.left =  objGoogleSuggest.calculateOffsetLeft(document.getElementById(_InputElementID))+"px"; 
					_SuggestionsListContainerDiv.style.top = objGoogleSuggest.calculateOffsetTop(document.getElementById(_InputElementID))+document.getElementById(_InputElementID).offsetHeight-1+"px"; 
					_SuggestionsListContainerDiv.style.width =  objGoogleSuggest.calculateWidth(document.getElementById(_InputElementID))+"px";   
                    // 2.0 Append to document body  
                    document.body.appendChild(_SuggestionsListContainerDiv);           
                    /////////////////////////////////////////////  
                    // Now place all items in the drop down list in the SuggestDiv:
                    // Get the DropDownList DIV element and assign to variable 
                    //var ddl = document.getElementById("SuggestionsListContainerDiv");
                    ddl = _SuggestionsListContainerDiv; 
                    // Remove existing option elements
                    //ddl.innerHTML = "";
                    //document.getElementById("SuggestionsListContainerDiv").innerHTML = "";
                    if (DropDownOptionsContainer) {
                        
                        /*
                        DropDownOptionsContainer.childNodes[0] gives the container XML tag: <DropDownOptions>
                        DropDownOptionsContainer.childNodes[0].childNodes[i] gives the i-th option
                        tag
                        */
                        //alert("# of nodes = " + DropDownOptionsContainer.childNodes[0].childNodes.length);
                        DropDownOptions = DropDownOptionsContainer.childNodes[0]; 
                        // or getElementsByTagName("DropDownOption");
                        var ListItem;
                        for (var i=0;i<DropDownOptions.childNodes.length;i++) {
                            //opt = document.createElement("SPAN");
                         
                            // Note: to get access to the text within a tag, you 
                            // need to access it as .firstChild
                            // DropDownOptions.childNodes[i] = i-th <DropDownOption> tag
                            
                            ListItem = "<div id='_GoogleSuggestItem" + i + "' onmouseover='objGoogleSuggest.SuggestMouseOver(this.id)' onmouseout='objGoogleSuggest.SuggestMouseOut(this.id)' onMouseDown='objGoogleSuggest.HideSuggestionsDiv()' >";
                            ListItem += DropDownOptions.childNodes[i].childNodes[0].firstChild.nodeValue;
                            ListItem += "</div>";
                            ddl.innerHTML += ListItem; 
                            
                            //opt.innerHTML = DropDownOptions.childNodes[i].childNodes[0].firstChild.nodeValue;
                            //opt.innerHTML += DropDownOptions.childNodes[i].childNodes[1].firstChild.nodeValue;
                        //ddl.appendChild(opt);
                        }
                        
            var listLength = ddl.childNodes.length ;                   
                        if (listLength == 1) {
                            document.getElementById(_InputElementID).value = ddl.childNodes[0].firstChild.nodeValue;
                            objGoogleSuggest.HideSuggestionsDiv();
                        }
                        
                    }
    }, // end of BuildDropDownOptionsFromXML 
    
    SuggestMouseOver: function(id) {
        document.getElementById(id).style.backgroundColor = _HighlightColor;
        document.getElementById(id).style.color = _TextColorOnHighLight;
        document.getElementById(_InputElementID).value = document.getElementById(id).innerHTML;
    }, // end of SuggestMouseOver
    
    SuggestMouseOut: function(id) {
        document.getElementById(id).style.backgroundColor = _BackgroundColor;
        document.getElementById(id).style.color = _TextColorNormal;
    }, // end of SuggestMouseOut      

    HideSuggestionsDiv: function() {
        _SuggestionsListContainerDiv.style.visibility = "hidden";
    },
  
  calculateWidth: function (elem){
    if(navigator&&navigator.userAgent.toLowerCase().indexOf("msie")==-1){
        return elem.offsetWidth-2;
    }else{
        return elem.offsetWidth;
    }
  }, // end of calculateWidth

    calculateOffsetTop: function (elem){
		return objGoogleSuggest.GetAttrValueRecursively(elem,"offsetTop")
    } , // end of calulateOffsetTop
    
    calculateOffsetLeft: function (elem){
		return objGoogleSuggest.GetAttrValueRecursively(elem,"offsetLeft")
    } , // end of calulateOffsetLeft
    
    GetAttrValueRecursively: function (elem,attr){
        var AttrVal=0;
        while(elem){
            AttrVal += elem[attr]; 
            elem = elem.offsetParent;
        }
        return AttrVal;
    }, // end of GetAttrValueRecursively  
    
    addEvent: function(elm, evType, fn, useCapture) {
    // elm: Element that triggers event, eg. window
    // evType: Event type such as click, etc.
    // fn: function that gets called when event is triggered
    
    // addEvent and removeEvent
    // cross-browser event handling for IE5+,  NS6 and Mozilla
    if (elm.addEventListener){
      elm.addEventListener(evType, fn, useCapture);
      return true;
    } else if (elm.attachEvent){
      var r = elm.attachEvent("on"+evType, fn);
      return r;
    } else {
      alert("Handler could not be removed");
    }
  } // end of addEvent function 

} // end of GoogleSuggest
