HTMLSelectElement : différences d’interprétation Javascript entre Chrome et Firefox

Une ligne ne renvoie pas pareil sur Chrome et sur Firefox. Chez moi, je ne la vois que sur des HTMLSelectElement.

En fait j’ai l’impression que les HTMLSelectElement n’ont pas le même type de constructeur entre Firefox et Chrome. sur Chrome, le test typeof(obj.constructor) == 'function' renverra true pour un HTMLSelectElement. Sur Firefox, il renverra false.

Sauf que pour le coup, c’est le résultat de Firefox que je veux obtenir sous Chrome. Donc je veux que dans le cas d’un HTMLSelectElement, Chrome me renvoie false.

Exemple : Prenez un select dans votre page, et faites un truc genre :

<select name="shipping_country_id" id="shipping_country_id" onfocus="isCollection(this);" >
<option title="France métropolitaine" value="FR" selected="selected">France métropolitaine</option>
<option title="Royaume uni" value="RK">Royaume uni</option>
</select>

En fait, c’est le inCollection(this) qui va créer un HTMLSelectElement (ce que ferait également un document.getElementById('shipping_country_id'), mais pas un $('#shipping_country_id')).

La ligne :

isCollection = function(obj) {
var bool = (obj && (obj.constructor == Object || typeof(obj.constructor) == 'function') && typeof(obj.add) == 'function' && typeof(obj.remove) == 'function' && typeof(obj.length) == 'number');
Util.Debug(bool);
if(bool){
Util.Debug("obj : "+obj);
Util.Debug("obj.constructor : "+obj.constructor);
Util.Debug("obj.innerHTML : "+obj.innerHTML); //permets de retrouver l'element dans la page car le toString du obj ne renvoie souvent pas grand chose
Util.Debug("typeof(obj.add) : "+typeof(obj.add));
Util.Debug("typeof(obj.remove) : "+ typeof(obj.remove));
Util.Debug("typeof(obj.length) : "+typeof(obj.length));
}
  return bool;
}

Avec une fonction Util.Debug ressemblant à ça :

Util.Debug = function(message){
  if (typeof(console) != "undefined") { // firebug, safari
    if (!console.debug) { // console Safari
      window.console.log(message);
    } else { // Firebug
      window.console.debug(message);
    }
  }
}

La correction

Rajouter le test obj.constructor != HTMLSelectElement pour la variable bool, qui devient du coup :

var bool = (obj && (obj.constructor == Object || (typeof(obj.constructor) == 'function' && obj.constructor != HTMLSelectElement))) && typeof(obj.add) == 'function' && typeof(obj.remove) == 'function' && typeof(obj.length) == 'number');

Alors on peut aussi dire que l’instruction suivante fonctionne très bien :

var bool = (obj && obj.constructor == Object) && typeof(obj.add) == 'function' && typeof(obj.remove) == 'function' && typeof(obj.length) == 'number');

Sauf que dans ce cas, les objets itérables envoyés par Jquery ne sont pas considérés comme des collections. D’où la necéssité de rajouter d’abord le typeof(obj.constructor) == 'function' afin qu’ils soient pris en compte, puis de corriger l’effet de bord sur les objets HTMLSelectElement avec obj.constructor != HTMLSelectElement.

Un problème vu ailleurs mais avec les NodeList

Notez que j’ai cherché plusieurs jours avant de trouver mon problème, et j’ai notamment vu chez StackOverFlow que la gestion par Chrome et Firefox des NodeList n’était pas la même :

the value of result in chrome / safari / opera is ‘[object NodeList]’.
In firefox and IE 9 , it is ‘[object HTMLCollection]’.

Donc il y a des chances que d’autres objets soient dans ce cas…

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.