PRATIQUE CLIENTS WEB 
5 JavaScripts vraiment utiles
 
Pas de fioritures parmi ces cinq fonctions, qui trouveront leur place dans la bibliothèque de tous les développeurs : getElementById() pour les anciens navigateurs, getElementsByClass(), getElementsByAttributes(), getElementsByAnything() et domEl(). (12/05/2006)
  Forum

Réagissez dans les forums de JDN Développeurs

JavaScript revient en force depuis 2004. D'un langage sous-estimé, voire mal vu, il est devenu le point de passage obligé du fameux Web 2.0, et est aujourd'hui un atout pour les utilisateurs plutôt qu'un handicap. Ce regain d'intérêt a amené les développeurs à instaurer des bonnes pratiques, à commencer par professer l'usage de JavaScript non intrusif, ou au moins se dégradant sans perte sur les navigateurs disposant d'une vieille implémentation.

Outre ces bonnes pratiques, nombre de développeurs se sont mis à créer des scripts palliant certains manquent du langage, ou simplement leur facilitant certaines tâches. Nous en regroupant ici cinq des plus importantes, avec code source et explications.

1) getElementById()
L'une des fonctionnalités les plus utilisées du DOM est getElementById(). Désormais reconnue par tous les navigateurs modernes, elle reste cependant inaccessible aux autres. Pour que les scripts modernes puissent cependant fonctionner sur les navigateurs ne reconnaissant pas cette méthode très appréciée, la voici recréée en JavaScript. A placer au début de tout script faisant appel à getElementById().
  1. if (!document.getElementById) {
  2.   if (document.all)
  3.     document.getElementById=function() {
  4.       if ( typeof(document.all[arguments[0]]) != "undefined")
  5.         return document.all[arguments[0]];
  6.       else
  7.         return null;
  8.       }
  9.   else if (document.layers)
  10.     document.getElementById=function() {
  11.       if ( typeof(document[arguments[0]]) != "undefined")
  12.         return document[arguments[0]];
  13.       else
  14.         return null;
  15.       }
  16.   }
L'usage est le même que pour la fonction originale : getElementById("identifiant").

2) getElementsByClass()
Après avoir recréé une fonction JavaScript dans ce même langage, l'étape suivante consiste à pallier aux manques de ce langage. Notamment, nombre de développeurs se sont trouvés frustrés de pouvoir sélectionner un élément que par identifiant avec getElementById(), mais auraient voulu également pouvoir sélectionner l'ensemble des éléments correspondant à une certaine classe - ce que le DOM ne propose pas. De nombreuses versions de getElementsByClass() ont donc été conçues au fil des années. En voici deux. La première a été créée par Dustin Diaz :
  1. function getElementsByClass(searchClass, node, tag) {
  2.     var classElements = new Array();
  3.     if ( node == null )
  4.         node = document;
  5.     if ( tag == null )
  6.         tag = '*';
  7.     var els = node.getElementsByTagName(tag);
  8.     var elsLen = els.length;
  9.     var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
  10.     for (i = 0, j = 0; i < elsLen; i++) {
  11.         if ( pattern.test(els[i].className) ) {
  12.             classElements[j] = els[i];
  13.             j++;
  14.         }
  15.     }
  16.     return classElements;
  17. }
La seconde provient de Dylan Schiemann, et propose de passer par les méthodes XPath proposées par le DOM, dans le cadre d'une page XHTML :
  1. function getElementByClassName(needle) {
  2.   var xpathResult = document.evaluate('//*[@class = "'needle'"]', document, null, 0, null);
  3.   var outArray = new Array();
  4.   var item; while (item = xpathResult.iterateNext()) outArray[outArray.length] = item;
  5.   return outArray;
  6.   }
En l'état, la fonction de Dustin Diaz est plus efficace, car elle offre deux arguments supplémentaires et optionnels : le premier pour préciser que la recherche se fait au sein d'un élément (récupéré via getElementById(), par exemple), la seconde pour limiter la recherche à un nom de balise donnée (on peut également utiliser le joker * dans le cas par exemple de sélecteurs multiple).

3) getElementsByAttribute()
Cette fonction est un pas supplémentaire dans l'accès aux balises par JavaScript : viser les balises disposant d'un même attribut d'une valeur donnée. Elle est disponible chez certains parseurs XML. Cette version a été créée par Robert Nyman.
  1. /*
  2.     Copyright Robert Nyman, http://www.robertnyman.com
  3.     Free to use if this text is included
  4. */
  5. function getElementsByAttribute(oElm, strTagName, strAttributeName, strAttributeValue) {
  6.     var arrElements = (strTagName == "*" && document.all)? document.all : oElm.getElementsByTagName(strTagName);
  7.     var arrReturnElements = new Array();
  8.     var oAttributeValue = (typeof strAttributeValue != "undefined")? new RegExp("(^|\\s)" + strAttributeValue + "(\\s|$)") : null;
  9.     var oCurrent;
  10.     var oAttribute;
  11.     for(var i=0; i<arrElements.length; i++) {
  12.         oCurrent = arrElements[i];
  13.         oAttribute = oCurrent.getAttribute(strAttributeName);
  14.         if (typeof oAttribute == "string" && oAttribute.length > 0) {
  15.             if (typeof strAttributeValue == "undefined" || (oAttributeValue && oAttributeValue.test(oAttribute))){
  16.                 arrReturnElements.push(oCurrent);
  17.             }
  18.         }
  19.     }
  20.     return arrReturnElements;
  21. }
4) $()
La dernière innovation en la matière est la fonction baptisée $(), issue du projet Prototype et qui sert de remplacement efficace à getElementById(). En effet, grâce à elle, un développeur peut remplacer ces appels de la forme var el = document.getElementById('id'); en var el = $('id'). C'est bien sûr plus court, mais $() va plus loin, en donnant la possibilité d'appeller plusieurs id différents pour obtenir un tableau d'éléments à parcourir ensuite : var el = $('id1', 'id2', 'id3');. La version que nous présentons ici est celle de Matthew Pennell :
  1. function $() {
  2.     var elements = new Array();
  3.     for (var i=0,len=arguments.length;i<len;i++) {
  4.         var element = arguments[i];
  5.         if (typeof element == 'string') {
  6.             var matched = document.getElementById(element);
  7.             if (matched) {
  8.                 elements.push(matched);
  9.             } else {
  10.                 var allels = (document.all) ? document.all : document.getElementsByTagName('*');
  11.                 var regexp = new RegExp('(^| )'+element+'( |$)');
  12.                 for (var i=0,len=allels.length;i<len;i++) if (regexp.test(allels[i].className)) elements.push(allels[i]);
  13.             }
  14.             if (!elements.length) elements = document.getElementsByTagName(element);
  15.             if (!elements.length) {
  16.                 elements = new Array();
  17.                 var allels = (document.all) ? document.all : document.getElementsByTagName('*');
  18.                 for (var i=0,len=allels.length;i<len;i++) if (allels[i].getAttribute(element)) elements.push(allels[i]);
  19.             }
  20.             if (!elements.length) {
  21.                 var allels = (document.all) ? document.all : document.getElementsByTagName('*');
  22.                 for (var i=0,len=allels.length;i<len;i++) if (allels[i].attributes) for (var j=0,lenn=allels[i].attributes.length;j<lenn;j++) if (allels[i].attributes[j].specified) if (allels[i].attributes[j].nodeValue == element) elements.push(allels[i]);
  23.             }
  24.         } else {
  25.             elements.push(element);
  26.         }
  27.     }
  28.     if (elements.length == 1) {
  29.         return elements[0];
  30.     } else {
  31.         return elements;
  32.     }
  33. }
L'idée de cette version est d'offrir un raccourci non seulement pour getElementById(), mais également getElementsByTagName() et getElementsByClass(), le tout en une seule fonction. En somme, une boîte à outils entière en une seule fonction simple d'usage : l'auteur la surnomme d'ailleurs getElementsByAnything().

5) domEl()
domEl() est encore une fonction personnelle, créée par Pawal Knapvik, autorisant une manipulation plus rapide du DOM : elle combine plusieurs fonctions afin d'ajouter simplement un nouvel élément HTML au DOM en cours. L'exemple de l'auteur est comme suit :

var link = document.createElement('a');
link.setAttribute('href', 'index.html');
link.appendChild(document.createTextNode('go home'));
document.getElementById('content').appendChild(link);


...devient...

domEl('a', 'go home', [['href', 'index.html']], document.getElementById('content'));

domEl() prend 5 arguments, la plupart optionnels ce qui permet d'avoir plusieurs cas de figure. Le premier donne le type de l'élément à créer, le second le contenu de cet élément, le troisième ses attributs, le quatrième indique dans quel(s) élément(s) celui-ci doit être créé, et le dernier précise si l'élément remplace les éléments existants, ou s'ajoute à eux.
  1. var domEl = function(e,c,a,p,x) {
  2. if(e||c) {
  3.     c=(typeof c=='string'||(typeof c=='object'&&!c.length))?[c]:c;   
  4.     e=(!e&&c.length==1)?document.createTextNode(c[0]):e;   
  5.     var n = (typeof e=='string')?document.createElement(e) : !(e&&e===c[0])?e.cloneNode(false):e.cloneNode(true);   
  6.     if(e.nodeType!=3) {
  7.         c[0]===e?c[0]='':'';
  8.         for(var i=0,j=c.length;i<j;i++) typeof c[i]=='string'? n.appendChild(document.createTextNode(c[i]))  : n.appendChild(c[i].cloneNode(true));
  9.         if(a) {for(var i=(a.length-1);i>=0;i--) a[i][0]=='class' ? n.className=a[i][1] : n.setAttribute(a[i][0],a[i][1]);}
  10.     }
  11. }
  12.     if(!p)return n;
  13.     p=(typeof p=='object'&&!p.length)?[p]:p;
  14.     for(var i=(p.length-1);i>=0;i--) {
  15.         if(x) { while(p[i].firstChild) p[i].removeChild(p[i].firstChild);
  16.             if(!e&&!c&&p[i].parentNode) p[i].parentNode.removeChild(p[i]);}
  17.         if(n) p[i].appendChild(n.cloneNode(true));
  18.     }   
  19. }
 
Xavier Borderie, JDN Développeurs
 
 
Accueil | Haut de page