Discussion MediaWiki:Gadget-X-SAMPAseul.js

Dernier commentaire : il y a 15 ans par Darkdadaah dans le sujet conversion X-SAMPA boguée

conversion X-SAMPA boguée modifier

(Contenu déplacé depuis la Wikidémie : Wiktionnaire:Wikidémie/décembre 2008#conversion X-SAMPA boguée)

La conversion vers X-SAMPA est boguée, et ne convertit effectivement qu'une prononciation sur deux.

Pour voir le bogue il faut bien entendu regarder les pages où figurent plusieurs appels au modèle {{pron}} (par exemple les pages annexes de conjugaison).

Le code actuel fait ceci:

// Parcours de toutes les prononciations d'une page et conversion de chacune
function pronpage() {
  var  pron = document.getElementsByClassName("API") ;
  var max = pron.length ;
  var n = 0 ;  // Précaution
  
  // Tourner jusqu'à ce que toutes les classes API aient été traitées
  while(pron.length>0 && n<max) {
     pron[0].innerHTML = APIversXSAMPA(pron[0].innerHTML) ;
     pron[0].title = "prononciation X-SAMPA" ;
     pron[0].className = pron[0].className.replace(/\bAPI\b/, "X-SAMPA") ;
     n++ ;
  }
}
addOnloadHook(pronpage) ;

La bogue s'explique ainsi : lorsque la ligne qui change le nom de la classe "API" en classe "X-SAMPA" s'exécute, elle a pour effet de modifier aussi la collection du navigateur référencée par la variable "pron": un élément peut disparaître du tableau, celui en tête, mais rien ne garantit que cela se produit si la collection obtenue dans le tableau est une copie des références au lieu d'une référence à une collection interne du navigateur, ni que le tri actuel de la collection sera conservé (des élements du tableau peuvent être permutés plutôt que de les glisser tous, car les collections d'éléments n'ont pas de tri garanti).

L'effet obtenu sera donc dépendant du navigateur ; par exemple cela ne marche pas avec les navigateurs basés sur WebKit comme Safari ou Google Chrome ou Chromium ou KDE Browser, où la collection d'éléments obtenue n'est pas une copie de références vers chaque élément trouvé, mais une référence directe à la liste des éléments du navigateur (qui maintient lui-même les listes d'éléments par classe, car cela va effectivement plus vite de faire ainsi). Il semble même que ce code ne peut pas marcher sur aucun navigateur strictement conforme à la norme (puisque la modification de la collection référencée est normalement nécessaire, même en cours d'exécution du JavaScript).

Le code actuel ne semble marcher QUE sur Internet Explorer (qui ne sait pas faire de référence directe aux collections internes du navigateur, pour des raisons techniques liée à l'utilisation d'une interface ActiveX trop lente entre son moteur JavaScript, son moteur de rendu HTML et son interface DOM: il paliie au problème en effectuant une copie profonde des collections et via un système complexe de "hooks" internes dans son moteur Javascript, patché plus ou moins bien pour gérer le DOM).

Aussi je propose plutôt le code suivant qui fonctionne sur tous les navigateurs, et redemande au navigateur la nouvelle collection d'éléments après chaque modification effectuée, et qui commence aussi par la fin de liste (plus rapide dans les longues pages car dans des parties pas encore affichées : cela limite le nombre de "reflows" pour la mise à jour à l'écran; cela évite aussi que le navigateur procède par permutation d'éléments puisqu'il lui suffit juste de décrémenter la longueur de collection sans décaler non plus les autres positions), et évite aussi les bogues de certains navigateurs (qui ne suppriment pas non plus les références ou qui les remplacent par des nulls qui ne seront supprimés que lors du "reflow" suivant, après l'exécution de la totalité du JavaScript) :

function pronpage() {
  var  pron = document.getElementsByClassName("API"); // obtient soit une référence soit une copie d'une collection interne du navigateur
  var n = pron.length; // sécurité contre boucles infinies (sur les navigateurs qui ne changent pas la longueur des collections) !
  // Tourner jusqu'à ce que toutes les classes API aient été traitées
  while (--n >= 0) { // sécurité contre boucles infinies !
    if (pron[n]) { // sécurité contre les position nulles sur certains navigateurs qui ne changent ni la longueur totale ni les positions dans la collection !
      pron[n].innerHTML = APIversXSAMPA(pron[n].innerHTML) ;
      pron[n].title = "prononciation X-SAMPA" ;
      pron[n].className = pron[n].className.replace(/\bAPI\b/, "X-SAMPA") ; // modifie aussi la collection d'éléments interne du navigateur !
      pron = document.getElementsByClassName("API") ; // redemande la collection modifiée !
    }
  }
}
addOnloadHook(pronpage) ;

D'une façon générale, toute collection d'éléments obtenue par document.getElementsByXxxxx() ne reste valide que tant que la collection n’est pas modifiée par le code Javascript qui l'utilise (ce qui est le cas ici quand on change le nom de classe d'un élément faisant partie d'une collection d'éléments ayant ce nom de classe). Si on continue à l'utiliser magré tout, le résultat est imprévisible et on risque même de référencer des éléments inexistants (et provoquer des exceptions à cause de références nulles). verdy_p 4 décembre 2008 à 07:08 (UTC)Répondre

Merci, j'avais eu ce problème (c'est pour ça que j'avais fait la boucle while), et je pensais l'avoir résolu, mais je n'ai pas testé sur d'autres navigateurs et systèmes d'exploitation (testé sous firefox 3 sous Ubuntu).
J'ai corrigé comme tu l'as indiqué, peux-tu me dire si le problème est résolu chez toi ? (page d'exemple : Annexe:Conjugaison française:métamorphoser) - Dakdada (discuter) 4 décembre 2008 à 08:25 (UTC)Répondre
Revenir à la page « Gadget-X-SAMPAseul.js ».