function AutoCompleteDB() { // set the initial values. this.bEnd = false; this.nCount = 0; this.aStr = new Object; } AutoCompleteDB.prototype.add = function(str) { // increment the count value. this.nCount++; // if at the end of the string, flag this node as an end point. if ( str == "" ) this.bEnd = true; else { // otherwise, pull the first letter off the string var letter = str.substring(0,1); var rest = str.substring(1,str.length); // and either create a child node for it or reuse an old one. if ( !this.aStr[letter] ) this.aStr[letter] = new AutoCompleteDB(); this.aStr[letter].add(rest); } } AutoCompleteDB.prototype.getCount = function(str, bExact) { // if end of search string, return number if ( str == "" ) if ( this.bEnd && bExact && (this.nCount == 1) ) return 0; else return this.nCount; // otherwise, pull the first letter off the string var letter = str.substring(0,1); var rest = str.substring(1,str.length); // and look for case-insensitive matches var nCount = 0; var lLetter = letter.toLowerCase(); if ( this.aStr[lLetter] ) nCount += this.aStr[lLetter].getCount(rest, bExact && (letter == lLetter)); var uLetter = letter.toUpperCase(); if ( this.aStr[uLetter] ) nCount += this.aStr[uLetter].getCount(rest, bExact && (letter == uLetter)); return nCount; } AutoCompleteDB.prototype.getStrings = function(str1, str2, outStr) { if ( str1 == "" ) { // add matching strings to the array if ( this.bEnd ) outStr.push(str2); // get strings for each child node for ( var i in this.aStr ) this.aStr[i].getStrings(str1, str2 + i, outStr); } else { // pull the first letter off the string var letter = str1.substring(0,1); var rest = str1.substring(1,str1.length); // and get the case-insensitive matches. var lLetter = letter.toLowerCase(); if ( this.aStr[lLetter] ) this.aStr[lLetter].getStrings(rest, str2 + lLetter, outStr); var uLetter = letter.toUpperCase(); if ( this.aStr[uLetter] ) this.aStr[uLetter].getStrings(rest, str2 + uLetter, outStr); } } function AutoComplete(aStr, oText, oDiv, nMaxSize) { // initialize member variables this.oText = oText; this.oDiv = oDiv; this.nMaxSize = nMaxSize; // preprocess the texts for fast access this.db = new AutoCompleteDB(); var i, n = aStr.length; for ( i = 0; i < n; i++ ) { this.db.add(aStr[i]); } // attach handlers to the text-box oText.AutoComplete = this; oText.onkeyup = AutoComplete.prototype.onTextChange; oText.onblur = AutoComplete.prototype.onTextBlur; } AutoComplete.prototype.onTextBlur = function() { this.AutoComplete.onblur(); } AutoComplete.prototype.onblur = function() { this.oDiv.style.visibility = "hidden"; } AutoComplete.prototype.onTextChange = function() { this.AutoComplete.onchange(); } AutoComplete.prototype.onDivMouseDown = function() { this.AutoComplete.oText.value = this.innerHTML; } AutoComplete.prototype.onDivMouseOver = function() { this.className = "AutoCompleteHighlight"; } AutoComplete.prototype.onDivMouseOut = function() { this.className = "AutoCompleteBackground"; } AutoComplete.prototype.onchange = function() { var txt = this.oText.value; // count the number of strings that match the text-box value var nCount = this.db.getCount(txt, true); // if a suitable number then show the popup-div if ( (this.nMaxSize == -1 ) || ((nCount < this.nMaxSize) && (nCount > 0)) ) { // clear the popup-div. while ( this.oDiv.hasChildNodes() ) this.oDiv.removeChild(this.oDiv.firstChild); // get all the matching strings from the AutoCompleteDB var aStr = new Array(); this.db.getStrings(txt, "", aStr); // add each string to the popup-div var i, n = aStr.length; for ( i = 0; i < n; i++ ) { var oDiv = document.createElement('div'); this.oDiv.appendChild(oDiv); oDiv.innerHTML = aStr[i]; oDiv.onmousedown = AutoComplete.prototype.onDivMouseDown; oDiv.onmouseover = AutoComplete.prototype.onDivMouseOver; oDiv.onmouseout = AutoComplete.prototype.onDivMouseOut; oDiv.AutoComplete = this; } this.oDiv.style.visibility = "visible"; } else // hide the popup-div { this.oDiv.innerHTML = ""; this.oDiv.style.visibility = "hidden"; } } function createAutoComplete() { var aNames = ["aaragon","aguadulce","albacete","albecete","alcaucin","alhaurin de la torre ","alhaurin el grande","alicante","almeria","almerimar ","alpujarra","andalucia","andalusia","arroyo de la miel ","artola alta ","bahia dorada ","balearic islands","bel air ","benahavis","benalmadena","benalmadena costa ","benalmadena pueblo","buenavista","cadiz","calahonda ","calasparra ","calypso","canary islands","cantabria","carib playa ","casares ","catalonia","catelonia","cerros del aguila ","coin","cordoba","costa almeria","costa azahar","costa blanca","costa blanca north","costa blanca south","costa brava","costa calida","costa de almeria","costa de calida","costa de la luz","costa del almeria ","costa del azahar","costa del silencio","costa del sol","costa dol sol","costa tropical","denia","el coto ","el faro ","el paraiso ","el rosario","empuria brava","estepona ","fuengirola","fuerteventura","galicia","girona","gran canaria","granada","guaro","ibiza","inland andalucia","jaen","la cala ","la cala de mijas","la cala golf","la chapas ","la gomera","la rioja","lanzarote","las chapas ","las delicias ","las farolas ","las lagunas ","los alcazares","los flamingos","los pacos ","majorca","malaga","mallorca","manilva","marbella","marbella centre ","menorca","mijas","mijas costa","mijas golf ","miraflores ","monte alto ","monte biarritz ","murcia","puerto banus","puerto marina ","rancho domingo ","riviera","riviera del sol ","riviera del sol beachfront","sevilla","sotogrande","sucina ","tenerife","terremolinos ","tolox","torreblanca ","torremuelle","torrenueva ","torrequebrada","valencia","valenciana","veracruz","voltacado ",""]; new AutoComplete( aNames, document.getElementById('theText'), document.getElementById('theDiv'), 25 ); }