// 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      }  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function initAutoComplete(form,field,submit,pays,region){	_region=region;	_pays=pays;  _documentForm=form;  _inputField=field;  _submitButton=submit;  _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function escapeURI(La){  if(encodeURIComponent) {    return encodeURIComponent(La);  }  if(escape) {    return escape(La)  }}var _xmlHttp = null; //l'objet xmlHttpRequest utilisé pour contacter le serveurvar _adresseRecherche = "options.php"; //l'adresse à interroger pour trouver les suggestionsfunction callSuggestions(valeur){  if(_xmlHttp&&_xmlHttp.readyState!=0){    _xmlHttp.abort()  }  _xmlHttp=getXMLHTTP();  if(_xmlHttp){    //appel à l'url distante    _xmlHttp.open("GET",_adresseRecherche+"?debut="+valeur+"&pays="+_pays+"&region="+_region,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 initStyle(){  var AutoCompleteDivListeStyle="font-size: 13px; font-family: arial,sans-serif; word-wrap:break-word; color:black;";  var AutoCompleteDivStyle="display: block; padding-left: 3; padding-right: 3; height: 16px; overflow: hidden; background-color: white;";  var AutoCompleteDivActStyle="background-color: #3366cc; color: white ! important; ";  insereCSS(".AutoCompleteDivListeStyle",AutoCompleteDivListeStyle);  insereCSS(".AutoCompleteDiv",AutoCompleteDivStyle);  insereCSS(".AutoCompleteDivAct",AutoCompleteDivActStyle);}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() {  initStyle();  _completeDiv=document.createElement("DIV");  _completeDiv.id="completeDiv";  var borderLeftRight=1;  var borderTopBottom=1;  _completeDiv.style.borderRight="black "+borderLeftRight+"px solid";  _completeDiv.style.borderLeft="black "+borderLeftRight+"px solid";  _completeDiv.style.borderTop="black "+borderTopBottom+"px solid";  _completeDiv.style.borderBottom="black "+borderTopBottom+"px solid";  _completeDiv.style.zIndex="1";  _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<liste.length; ++f){    var nouveauDiv=document.createElement("DIV");    nouveauDiv.onmousedown=divOnMouseDown;    nouveauDiv.onmouseover=divOnMouseOver;    nouveauDiv.onmouseout=divOnMouseOut;    setStylePourElement(nouveauDiv,"AutoCompleteDiv");    var nouveauSpan=document.createElement("SPAN");    nouveauSpan.innerHTML=liste[f]; // 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<suggestionLongueur; indice++){      if(getSuggestion(suggestionList.item(indice)).toUpperCase().indexOf(_currentInputFieldValue.toUpperCase())==0) {        trouve=true;        break      }    }  }  // on désélectionne toutes les suggestions  for(var i=0; i<suggestionLongueur; i++) {    setStylePourElement(suggestionList.item(i),"AutoCompleteDiv");  }  // si l'entrée utilisateur (n) est le début d'une suggestion (n-1) on sélectionne cette suggestion avant de continuer  if(trouve){    _highlightedSuggestionIndex=indice;    _highlightedSuggestionDiv=suggestionList.item(_highlightedSuggestionIndex);  }else{    _highlightedSuggestionIndex=-1;    _highlightedSuggestionDiv=null  }  var supprSelection=false;  switch(_eventKeycode){    // cursor left, cursor right, page up, page down, others??    case 8:    case 33:    case 34:    case 35:    case 35:    case 36:    case 37:    case 39:    case 45:    case 46:      // on supprime la suggestion du texte utilisateur      supprSelection=true;      break;    default:      break  }  // si on a une suggestion (n-1) sélectionnée  if(!supprSelection&&_highlightedSuggestionDiv){    setStylePourElement(_highlightedSuggestionDiv,"AutoCompleteDivAct");    var z;    if(trouve) {      z=getSuggestion(_highlightedSuggestionDiv).substr(0);    } else {      z=_currentInputFieldValue;    }    if(z!=_inputField.value){      if(_inputField.value!=_currentInputFieldValue) {        return;      }      // si on peut créer des range dans le document      if(_inputField.createTextRange||_inputField.setSelectionRange) {        _inputField.value=z;      }      // on sélectionne la fin de la suggestion      if(_inputField.createTextRange){        var t=_inputField.createTextRange();        t.moveStart("character",_currentInputFieldValue.length);        t.select()      }else if(_inputField.setSelectionRange){        _inputField.setSelectionRange(_currentInputFieldValue.length,_inputField.value.length)      }    }  }else{    // sinon, plus aucune suggestion de sélectionnée    _highlightedSuggestionIndex=-1;  }}var _cursorUpDownPressed = null;// permet le blur du champ texte après que la touche haut/bas ai été pressé.// le focus est récupéré après traitement (via le timeout).function blurThenGetFocus(){  _cursorUpDownPressed=true;  _inputField.blur();  setTimeout("_inputField.focus();",10);  return}// taille de la selection dans le champ inputfunction rangeSize(n){  var N=-1;  if(n.createTextRange){    var fa=document.selection.createRange().duplicate();    N=fa.text.length  }else if(n.setSelectionRange){    N=n.selectionEnd-n.selectionStart  }  return N}// taille du champ input non selectionnefunction beforeRangeSize(n){  var v=0;  if(n.createTextRange){    var fa=document.selection.createRange().duplicate();    fa.moveEnd("textedit",1);    v=n.value.length-fa.text.length  }else if(n.setSelectionRange){    v=n.selectionStart  }else{    v=-1  }  return v}// Place le curseur à la fin du champfunction cursorAfterValue(n){  if(n.createTextRange){    var t=n.createTextRange();    t.moveStart("character",n.value.length);    t.select()  } else if(n.setSelectionRange) {    n.setSelectionRange(n.value.length,n.value.length)  }}// Retourne la valeur de la possibilite (texte) contenu dans une div de possibilitefunction getSuggestion(uneDiv){  if(!uneDiv) {    return null;  }  return trimCR(uneDiv.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<chaine.length; f++) {    if (zb.indexOf(chaine.charAt(f))==-1) {      nChaine+=chaine.charAt(f);    }  }  return nChaine}// Cache completement les choix de completionfunction hideCompleteDiv(){  _completeDiv.style.visibility="hidden"}// Rends les choix de completion visiblesfunction showCompleteDiv(){  _completeDiv.style.visibility="visible";  setCompleteDivSize()}// Change la suggestion en surbrillancefunction highlightNewValue(C){  if(!_completeDivDivList||_completeDivRows<=0) {    return;  }  showCompleteDiv();  if(C>=_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){      _submitButton.focus();      _lastKeyCode=-1    }  }  _cursorUpDownPressed=false};// declenchee quand on clique sur une div contenant une possibilitevar divOnMouseDown=function(){  _inputField.value=getSuggestion(this);  //_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");};