03 décembre 2013

Outil JavaScript : adapter l'encodage d'un Ajax récursif

La balise '<meta' ou à défaut, la propriété 'document.characterSet', permettent d'accéder à l'encodage d'une page web. Cependant, l'encodage réel du fichier source peut s'avèrer différent - d'où de possibles problèmes d'affichage - ou des soucis en cas d'Ajax "récursif".

Pour un fichier '.html' francophone dont l'on connait le parcours et qui est modifiable, il est possible de deviner s'il y a discordance, et s'il s'agit alors :

  • d'un fichier "latin", "occidental" (ISO-8859-1, ISO-8859-15, windows-1252) avec une '<meta' déclarée en 'utf-8',
  • ou bien du contraire, une '<meta' déclarée en "latin" dans un fichier "utf-8".

Le script ci-dessous, avec une heuristique simple, établit cette information avec un fort degré de probabilité.
Il fonctionne avec ce code ajouté en début de page :

<html>
<!-- é test -->

Détection de l'encodage du fichier

try{
  var charset = document.querySelector("meta[http-equiv='Content-Type']").getAttribute("content").split("=")[1]; //meta HTML4-XHTML1
}
catch(e){
    try{
      charset = document.querySelector("meta[charset]").getAttribute("charset"); //meta HTML5
    }
    catch(e){
      charset = document.characterSet; //absence de meta
    }
}
var commentaire = document.querySelector("html").childNodes[0]; //presence du commentaire de controle <!-- é test --> apres <html>
if (commentaire.nodeType == 8 && commentaire.textContent.indexOf("test") > 0){
 //fichier probablement "latin" avec une meta utf-8 :
 if(charset.toLowerCase().indexOf("utf-8") > -1 && commentaire.textContent.split(/\uFFFD/).length == 2){ 
  charset = "iso-8859-1";
 }
 //fichier probablement utf-8 avec une meta differente :
 else if(commentaire.textContent.split(/\u00E9/).length == 1 && charset.toLowerCase().indexOf("utf-8") < 0){ 
  charset = "utf-8";
 }
}

Pour de l'Ajax récursif ?

C'est une requête de la page vers elle-même. La réponse en est le code source d'origine de la page, avant son analyse par le navigateur. Mais ça peut être faussé si encodages déclaré et réel ne concordent pas.

L'encodage détecté peut donc servir à paramétrer la requête Ajax via la méthode 'overrideMimeType()' pour favoriser l'intégrité du code retourné.
Par défaut, une réponse Ajax est encodée en "utf-8".

Remarque : Internet Explorer n'est pas pris en compte ici, mais ce doit être possible. Autre remarque préliminaire, l'économie du projet n'incluait par jQuery, d'où ce code à l'ancienne  :

var ajax = new XMLHttpRequest();
ajax.overrideMimeType("text/plain; charset=" + charset);
ajax.onreadystatechange = function(){if (ajax.readyState == 4){if (ajax.status == 200||ajax.status == 0){/*...*/}}}
ajax.open("GET","#",true);
ajax.send();

Post-scriptum du 27/12

La méthode Ajax 'getResponseHeader()' fournit parmi les-entêtes retournées, une information d'encodage via le paramètre "Content-Type" :

ajax.onreadystatechange = function(){
 if (ajax.readyState == 4){
  if (ajax.status == 200||ajax.status == 0){
   //vérifier l'existence de ajax.getResponseHeader puis obtenir ajax.getResponseHeader("Content-Type") 
}}}

Mais cette information HTTP, en provenance du serveur, reste probablement relative à un encodage déclaré, et redondante avec la valeur de 'document.characterSet' - à tester selon cas et configurations…

Moyen direct d'obtenir cette information, la méthode HTTP "HEAD" comme paramètre de la méthode Ajax 'open()', au lieu de "GET" :

ajax.open("HEAD","#",true);

Aucun commentaire: