Toujours plongé ces dernières semaines dans ce magnifique outil qu’est
le DOM,
j’ai de nouveau été confronté aux insuffisances de divers navigateurs.
Il est vraiment dommage que IE
fasse bande à part, hormis pour une grande partie du module
Core. Cela complique réellement
la tâche du développeur et l’oblige à réaliser toute une série de
tests pour obtenir une compatibilité avec tous les navigateurs du
marché.
Comme je le disais, IE
(surtout la version 6.x) reconnait, à peu de choses près, l’ensemble du
module Core. Là où il diverge
passablement des normes, c’est avec les modules d’évènements et
de styles (je ne me suis pas encore attaqué aux modules de vues et
de traversée). Dans ces deux cas, Microsoft a défini ses propres
objets, méthodes et propriétés, quand il en a défini, ce qui n’est
pas toujours le cas.
Définir ses propres méthodes
Mon objectif est simple : Pas de code propriétaire dans
mes scripts. Je me suis donc mis en tête de créer un script ajoutant
les méthodes standard manquantes dans
IE.
Exemple :
if( !window.addEventListener )
{
window.addEventListener = function(eventType, listener, useCapture) {
this.attachEvent("on" + eventType, listener);
}
}
Un petit problème cependant, il me faut faire cela pour chaque
élément du document, ce qui m’impose de faire une boucle qui
traitera chaqu’un de ces éléments. Un peu lourd… D’autant plus que
ce n’est pas la seule boucle, il y a d’autres objets à "normaliser".
J’ai donc commencé à chercher un moyen d'ajouter automatiquement
une méthode à toutes les instances d’un objet, m’appuyant sur un
passage de la documentation sur JavaScript 1.5 dont voici un extrait :
If you add a new property to an object that is being used as the
prototype for a constructor function, you add that property to all
objects that inherit properties from the prototype. For example,
you can add a specialty property to all employees with the
following statement :
Employee.prototype.specialty = "none";
Mais évidemment, car cela eût été trop simple, cela n'a pas fonctionné,
ou du moins de la façon dont j’ai testé:
if( !window.addEventListener )
{
document.getElementById('body').prototype.addEventListener = function(eventType, listener, useCapture) {
this.attachEvent("on" + eventType, listener);
}
}
Propriété inexistante… Puis je suis tombé sur cette page:
The prototype object of JavaScript 1.1 (cette page et la suivante).
Cet objet prototype
existe donc depuis belle lurette,
les tests sont d’ailleurs concluants, de plus, l’exemple de la dernière
page me confirme qu’il est possible d’ajouter une méthode à un objet
prédéfini, ce qui n’était pas forcément évident à la lecture de la
documentation de Netscape.
J’ai cherché longtemps. C’est simple, j’ai bien dù y perdre mon week-end.
Mais j’ai fini par trouver la solution. Ahh, le pied quand on cherche
inlassablement et qu’on finit enfin par trouver :)
Donc pour ajouter une méthode à un objet, et qu’elle soit héritée par
toutes les instances en cours et à venir de l’objet, il fallait finalement
faire :
if( !window.addEventListener )
{
// Objet HTMLElement, l'objet constructeur de tous les éléments du document
HTMLElement.prototype.addEventListener = function(eventType, listener, useCapture) {
this.attachEvent("on" + eventType, listener);
}
}
// ou encore
if( !window.addEventListener )
{
// Objet 'constructor' pour accéder à l'objet constructeur
document.getElementById('body').constructor.prototype.addEventListener = function(eventType, listener, useCapture) {
this.attachEvent("on" + eventType, listener);
}
}
Les deux façons de faire fonctionnement parfaitement dans Firefox,
la seconde seulement fonctionne dans Opera 7.22 et sur
IE 6.x,
… aucune… Autant vous dire que je suis extrèmement frustré, et ce,
pour plusieurs raisons.
- Cette possibilité est vraiment interessante, pas très connue
ou utilisée de ce que j’ai pu en voir cependant.
- Je tombe à nouveau sur une carence de
IE
alors que je cherchais à en combler une autre
Du coup, je suis à court d’idées et me suis rabattu sur les boucles.
Je ne désespère pas de trouver une solution (il doit forcément y avoir un
moyen d’accéder au constructeur d’un objet quel qu’il soit non ?).
Évènement souris et bouton cliqué
Alors là, c’est pire que d’habitude. Il n’y a plus deux modèles
(W3C
et Microsoft) pour connaitre le bouton de souris sur lequel a cliqué
l’utilisateur mais trois ! Et oui, Opera fait lui aussi bande
à part sur ce coup là.
Lorsqu'un évènement est lancé, on reçoit en argument de la fonction
appellée un objet contenant diverses informations sur l’évènement
enclenché. Ça, c’est pour le modèle du
W3C.
Chez microsoft, on dispose d’un objet similaire (du moins dans son
origine) mais il se trouve rattaché à l’objet window
.
Bref, cet objet a une propriété button
contenant le numéro
du bouton de la souris qui a été pressé. Voici la valeur de cette
propriété selon les différents modèles existants :
|
W3C |
Microsoft |
Opera |
Bouton gauche
| 0 |
1 |
1 |
Bouton milieu
| 1 |
4 |
3 |
Bouton droite
| 2 |
2 |
2 |
Mhhh…, difficile de s’y retrouver n’est ce pas ? Il y a une autre
propriété interessante dans l'objet event
, c’est la propriété
which
, présente uniquement sur Mozilla, Safari et Opera.
Pour un évènement souris adèquat, elle contient la même valeur que
button
sous Safari et Opera, sous Mozilla, cette valeur est
incrémentée de un. En mixant tout ça, je pense être parvenu à une solution
adéquat pour obtenir la même valeur sous ces trois navigateurs ainsi que
sous IE.
Si ça peut aider :
var button = event.button;
if( event.button != 0 && event.button != 2 && ( typeof(event.which) == 'undefined' || event.which > 0 ) )
{
if( typeof(event.which) != 'undefined' )// Mozilla, Safari et Opera
{
button = event.which;
}
button--;
if( button == 2 || button == 3 )// Correction Opera et MS
{
button = 1;
}
}