// retourne un objet xmlHttpRequest. // méthode compatible entre tous les navigateurs (IE/Firefox/Opera) function getXMLHTTP(){ var xhr=null; if(window.XMLHttpRequest) // Firefox et autres xhr = new XMLHttpRequest(); else if(window.ActiveXObject){ // Internet Explorer try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e1) { xhr = null; } } } else { // XMLHttpRequest non supporté par le navigateur alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest..."); } return xhr; } var _documentForm=null; // le formulaire contenant notre champ texte var _inputField=null; // le champ texte lui-même var _submitButton=null; // le bouton submit de notre formulaire var _adresseRecherche = "" //l'adresse à interroger pour trouver les suggestions function initAutoComplete(form,field,submit,lucase=true,ajax){ _documentForm=form; _inputField=field; _submitButton=submit; _letterCase=lucase; _adresseRecherche=ajax; _inputField.autocomplete="off"; creeAutocompletionDiv(); _currentInputFieldValue=_inputField.value; _oldInputFieldValue=_currentInputFieldValue; cacheResults("",new Array()) document.onkeydown=onKeyDownHandler; _inputField.onkeyup=onKeyUpHandler; _inputField.onblur=onBlurHandler; window.onresize=onResizeHandler; // Premier déclenchement de la fonction dans 200 millisecondes setTimeout("mainLoop()",200) } var _oldInputFieldValue=""; // valeur précédente du champ texte var _currentInputFieldValue=""; // valeur actuelle du champ texte var _resultCache=new Object(); // mécanisme de cache des requetes // tourne en permanence pour suggerer suite à un changement du champ texte function mainLoop(){ if(_oldInputFieldValue!=_currentInputFieldValue){ var valeur=escapeURI(_currentInputFieldValue); var suggestions=_resultCache[_currentInputFieldValue]; if(suggestions){ // la réponse était encore dans le cache metsEnPlace(valeur,suggestions) }else{ callSuggestions(valeur) // appel distant } _inputField.focus() } _oldInputFieldValue=_currentInputFieldValue; setTimeout("mainLoop()",200); // la fonction se redéclenchera dans 200 ms return true } // echappe les caractère spéciaux - tag HTML function escapeURI(La){ return La.replace(/<{1}[^<>]{1,}>{1}/g," "); // if(encodeURIComponent) { // return encodeURIComponent(La); // } // if(escape) { // return escape(La) // } } var _xmlHttp = null; //l'objet xmlHttpRequest utilisé pour contacter le serveur function callSuggestions(valeur){ if(_xmlHttp&&_xmlHttp.readyState!=0){ _xmlHttp.abort() } _xmlHttp=getXMLHTTP(); if(_xmlHttp){ //appel à l'url distante _xmlHttp.open("GET",_adresseRecherche+"?debut="+valeur,true); _xmlHttp.onreadystatechange=function() { if(_xmlHttp.readyState==4&&_xmlHttp.responseXML) { var liste = traiteXmlSuggestions(_xmlHttp.responseXML) cacheResults(valeur,liste) metsEnPlace(valeur,liste) } }; // envoi de la requete _xmlHttp.send(null) } } // Mecanisme de caching des réponses function cacheResults(debut,suggestions){ _resultCache[debut]=suggestions } // Transformation XML en tableau function traiteXmlSuggestions(xmlDoc) { var options = xmlDoc.getElementsByTagName('option'); var optionsListe = new Array(); for (var i=0; i < options.length; ++i) { optionsListe.push(options[i].firstChild.data); } return optionsListe; } //insère une règle avec son nom function insereCSS(nom,regle){ if (document.styleSheets) { var I=document.styleSheets[0]; if(I.addRule){ // méthode IE I.addRule(nom,regle) }else if(I.insertRule){ // méthode DOM I.insertRule(nom+" { "+regle+" }",I.cssRules.length) } } } function setStylePourElement(c,name){ c.className=name; } // calcule le décalage à gauche function calculateOffsetLeft(r){ return calculateOffset(r,"offsetLeft") } // calcule le décalage vertical function calculateOffsetTop(r){ return calculateOffset(r,"offsetTop") } function calculateOffset(r,attr){ var kb=0; while(r){ kb+=r[attr]; r=r.offsetParent } return kb } // calcule la largeur du champ function calculateWidth(){ return _inputField.offsetWidth-2*1 } function setCompleteDivSize(){ if(_completeDiv){ _completeDiv.style.left=calculateOffsetLeft(_inputField)+"px"; _completeDiv.style.top=calculateOffsetTop(_inputField)+_inputField.offsetHeight-1+"px"; _completeDiv.style.width=calculateWidth()+"px" } } function creeAutocompletionDiv() { _completeDiv=document.createElement("DIV"); _completeDiv.id="completeDiv"; var borderLeftRight=1; var borderTopBottom=1; _completeDiv.style.borderRight="#999 "+borderLeftRight+"px solid"; _completeDiv.style.borderLeft="#999 "+borderLeftRight+"px solid"; _completeDiv.style.borderTop="#999 "+borderTopBottom+"px solid"; _completeDiv.style.borderBottom="#999 "+borderTopBottom+"px solid"; _completeDiv.style.zIndex="2000"; _completeDiv.style.paddingRight="0"; _completeDiv.style.paddingLeft="0"; _completeDiv.style.paddingTop="0"; _completeDiv.style.paddingBottom="0"; setCompleteDivSize(); _completeDiv.style.visibility="hidden"; _completeDiv.style.position="absolute"; _completeDiv.style.backgroundColor="white"; document.body.appendChild(_completeDiv); setStylePourElement(_completeDiv,"AutoCompleteDivListeStyle"); } function metsEnPlace(valeur, liste){ while(_completeDiv.childNodes.length>0) { _completeDiv.removeChild(_completeDiv.childNodes[0]); } // mise en place des suggestions for(var f=0; f'+valeur+''+liste[f].substring(liste[f].indexOf(valeur)+valeur.length); // le texte de la suggestion nouveauDiv.appendChild(nouveauSpan); _completeDiv.appendChild(nouveauDiv) } PressAction(); if(_completeDivRows>0) { _completeDiv.height=16*_completeDivRows+4; } else { hideCompleteDiv(); } } var _lastKeyCode=null; // Handler pour le keydown du document var onKeyDownHandler=function(event){ // accès evenement compatible IE/Firefox if(!event&&window.event) { event=window.event; } // on enregistre la touche ayant déclenché l'evenement if(event) { _lastKeyCode=event.keyCode; } } var _eventKeycode = null; // Handler pour le keyup de lu champ texte var onKeyUpHandler=function(event){ // accès evenement compatible IE/Firefox if(!event&&window.event) { event=window.event; } _eventKeycode=event.keyCode; // Dans les cas touches touche haute(38) ou touche basse (40) if(_eventKeycode==40||_eventKeycode==38) { // on autorise le blur du champ (traitement dans onblur) blurThenGetFocus(); } // taille de la selection var N=rangeSize(_inputField); // taille du texte avant la selection (selection = suggestion d'autocomplétion) var v=beforeRangeSize(_inputField); // contenu du champ texte var V=_inputField.value; if(_eventKeycode!=0){ if(N>0&&v!=-1) { // on recupere uniquement le champ texte tapé par l'utilisateur V=V.substring(0,v); } // 13 = touche entrée if(_eventKeycode==13||_eventKeycode==3){ var d=_inputField; // on mets en place l'ensemble du champ texte en repoussant la selection if(_inputField.createTextRange){ var t=_inputField.createTextRange(); t.moveStart("character",_inputField.value.length); _inputField.select() } else if (d.setSelectionRange){ _inputField.setSelectionRange(_inputField.value.length,_inputField.value.length) } } else { // si on a pas pu agrandir le champ non selectionné, on le mets en place violemment. if(_inputField.value!=V) { _inputField.value=V } } } // si la touche n'est ni haut, ni bas, on stocke la valeur utilisateur du champ if(_eventKeycode!=40&&_eventKeycode!=38) { // le champ courant n est pas change si key Up ou key Down _currentInputFieldValue=V; } if(handleCursorUpDownEnter(_eventKeycode)&&_eventKeycode!=0) { // si on a préssé une touche autre que haut/bas/enter PressAction(); } } // Change la suggestion selectionné. // cette méthode traite les touches haut, bas et enter function handleCursorUpDownEnter(eventCode){ if(eventCode==40){ highlightNewValue(_highlightedSuggestionIndex+1); return false }else if(eventCode==38){ highlightNewValue(_highlightedSuggestionIndex-1); return false }else if(eventCode==13||eventCode==3){ return false } return true } var _completeDivRows = 0; var _completeDivDivList = null; var _highlightedSuggestionIndex = -1; var _highlightedSuggestionDiv = null; // gère une touche pressée autre que haut/bas/enter function PressAction(){ _highlightedSuggestionIndex=-1; var suggestionList=_completeDiv.getElementsByTagName("div"); var suggestionLongueur=suggestionList.length; // on stocke les valeurs précédentes // nombre de possibilités de complétion _completeDivRows=suggestionLongueur; // possiblités de complétion _completeDivDivList=suggestionList; // si le champ est vide, on cache les propositions de complétion if(_currentInputFieldValue==""||suggestionLongueur==0){ hideCompleteDiv() }else{ showCompleteDiv() } var trouve=false; // si on a du texte sur lequel travailler if(_currentInputFieldValue.length>0){ var indice; // T vaut true si on a dans la liste de suggestions un mot commencant comme l'entrée utilisateur for(indice=0; indice','').replace('',''); return trimCR(texte.getElementsByTagName('span')[0].firstChild.data) } // supprime les caractères retour chariot et line feed d'une chaine de caractères function trimCR(chaine){ for(var f=0,nChaine="",zb="\n\r"; f=_completeDivRows){ C=_completeDivRows-1 } if(_highlightedSuggestionIndex!=-1&&C!=_highlightedSuggestionIndex){ setStylePourElement(_highlightedSuggestionDiv,"AutoCompleteDiv"); _highlightedSuggestionIndex=-1 } if(C<0){ _highlightedSuggestionIndex=-1; _inputField.focus(); return } _highlightedSuggestionIndex=C; _highlightedSuggestionDiv=_completeDivDivList.item(C); setStylePourElement(_highlightedSuggestionDiv,"AutoCompleteDivAct"); _inputField.value=getSuggestion(_highlightedSuggestionDiv); } // Handler de resize de la fenetre var onResizeHandler=function(event){ // recalcule la taille des suggestions setCompleteDivSize(); } // Handler de blur sur le champ texte var onBlurHandler=function(event){ if(!_cursorUpDownPressed){ // si le blur n'est pas causé par la touche haut/bas hideCompleteDiv(); // Si la dernière touche préssé est tab, on passe au bouton de validation if(_lastKeyCode==9){ if (_submitButton != null) _submitButton.focus(); _lastKeyCode=-1 } } _cursorUpDownPressed=false }; // declenchee quand on clique sur une div contenant une possibilite var divOnMouseDown=function(){ _inputField.value=getSuggestion(this); _inputField.dispatchEvent(new Event('change')); if (_submitButton != null) _documentForm.submit() }; // declenchee quand on passe sur une div de possibilite. La div précédente est passee en style normal var divOnMouseOver=function(){ if(_highlightedSuggestionDiv) { setStylePourElement(_highlightedSuggestionDiv,"AutoCompleteDiv"); } setStylePourElement(this,"AutoCompleteDivAct") }; // declenchee quand la sourie quitte une div de possiblite. La div repasse a l'etat normal var divOnMouseOut = function(){ setStylePourElement(this,"AutoCompleteDiv"); };