Description: http://img2.websourcing.fr/files/2010/01/jquery-1-4-500x218.jpg

Alors comme ça petit padawan tu aimerais créer un plugin javascript pour cette merveilleuse librairie de fonctions? Voici un tutoriel fort inspiré de la documentation officielle sur les plugins jQuery en Anglais. Prêts à profiter du meilleur de jQuery et gagner un maximum de temps en développement pour davantage de sociabilité? Suivez le guide.

Pour commencer son plugin

Pour éviter que notre super plugin n'entre en conflit avec d'autres plugins utilisant le signe dollar il vaut mieux passer jQuery en fonction auto invoquée (Immediately-Invoked Function Expression , ou IIFE).

        (function( $ ) {

          $.fn.monSuperPlugin = function() {

               // les instructions trop bien ici

          };

        })( jQuery );

Le contexte

Avec cette base nous pouvons commencer à écrire notre contenu de plugin. Mais avant cela, parlons un peu du mot clé this qui à l'intérieur de notre fonction se réfère à l'objet jQuery sur lequel le plugin est invoqué. this se réfère au DOM (document object model) natif. Il n'est donc pas besoin d'entourer this par les parenthèses du sélécteur jQuery dans ce contexte.

        (function( $ ) {

          $.fn.monSuperPlugin = function() {

               // les instructions trop bien ici

               this.fadeIn('normal', function(){

                 // le mot clé this est un élément du DOM

               });

          };

        })( jQuery );

pour actionner notre plugin on pourra donc l'appeler ainsi sur un #element de votre choix ou plusieurs grâce à la puissance des sélecteurs CSS.

        $('#element').myPlugin();

Les bases

Maintenant que nous comprennons le contexte des plugins jQuery, écrivons un code qui fait réellement quelque chose.

        (function( $ ){

          $.fn.hauteurMax = function() {

               var max = 0;

               this.each(function() {

                 max = Math.max( max, $(this).height() );

               });

               return max;

          };

        })( jQuery );

Par exemple, un simple plugin qui évalue les hauteurs pour retourner la plus grande dans le jeu d'éléments sélectionnés.

var tallest = $('div').hauteurMax();

Ceci donne à la variable tallest la valeur de la div la plus haute de la page.

Maintenir la continuité

L'exemple précédent retourne un nombre entier, mais bien souvent le but d'un plugin est de modifier un jeu d'éléments et de les passer à la méthode suivante dans la chaîne de fonctions. C'est ce qui fait la beauté du design de jQuery et explique sa popularité. Donc, pour maintenir la continuité de la chaîne dans vos plugins, vous devez faire en sorte que les retours de plugins comprennent le mot clé this.

        (function( $ ){

          $.fn.verrouTailles = function( type ) { 

               return this.each(function() {

                 var $this = $(this);

                 if ( !type || type == 'width' ) {

                       $this.width( $this.width() );

                 }

                 if ( !type || type == 'height' ) {

                       $this.height( $this.height() );

                 }

               });

          };

        })( jQuery );

Ce plugin associe la largeur et la hauteur actuelle de chaque élément du jeu sélectionné. Il sera ajouté dans le HTML de la page un attribut width et height à chaque balise ainsi sélectionnée. Nous pouvons donc y mettre une autre méthode à la suite, comme css(). Et pour le mettre en place dans une chaîne:

        $('div').verrouTailles('width').css('color', 'red');

Parce que le mot clé this est retourné dans la lunette de script du plugin, la continuité est maintenue. Aussi, nous pouvons mettre des options et des choix par défaut dans nos plugins.

Options et défauts

Les configurations par défaut peuvent être étendues avec $.extend http://docs.jquery.com/Utilities/jQuery.extend quand le plugin est invoqué. jQuery.extend( cible [, objet1] [, objetN]) extend sert à fusionner le contenu de plusieurs objets dans le premier objet. Au lieu d'invoquer un plugin avec un grand nombre d'arguments, vous pouvez passer un seul objet des options que vous voulez modifier en argument.

        (function( $ ){

          $.fn.tooltip = function( options ) { 

               // Créer quelques options par defaut, les étendre comme nous voulons.

               var settings = $.extend( {

                 'location'         : 'top',

                 'background-color' : 'blue'

               }, options);

               return this.each(function() {       

                 // code du plugin Tooltip ici

               });

          };

        })( jQuery );

ce qui donne en pratique avec une option définie dans un objet:

        $('div').tooltip({

          'location' : 'left'

        });

Dans cet exemple, après avoir appelé le plugin tooltip avec les options choisies, la localisation par défaut topdevient réécrite en left, alors que la configuration de couleur d'arrière plan reste bleue car elle n'a pas été spécifiée. la config settings de l'objet devient donc comme ceci:

        {

          'location'         : 'left',

          'background-color' : 'blue'

        }

C'est une bonne pratique et un très bon moyen de rendre un plugin configurable sans avoir besoin de donner toutes les options à chaque fois.

Espace de noms

Choisir un espace de nommage est un moyen idéal pour éviter qu'un autre plugin chargé sur la même page ne vienne remplacer le notre ou le modifier contre notre gré. En tant que développeur ça nous rend la vie plus facile pour mieux trier nos méthodes, évènements et données.

Il vaudrait donc mieux ne pas mettre un seul espace de nom par plugin dans l'objet jQuery.fn mais plutôt stocker nos plugins dans un objet qui agira comme pour la configuration par défaut que nous venons de voir. Mais cette fois nous donnons par défaut non pas de simples variables mais des noms associés à des méthodes.

        (function( $ ){

 

          var methods = {

               init : function( options ) {

                 // THIS

               },

               show : function( ) {

                 // IS

               },

               hide : function( ) {

                 // GOOD

               },

               update : function( content ) {

                 // !!!

               }

          };

 

          $.fn.tooltip = function( method ) {

              

               // logique d'appel de méthode

               if ( methods[method] ) {

                 return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));

               } else if ( typeof method === 'object' || ! method ) {

                 return methods.init.apply( this, arguments );

               } else {

                 $.error( 'La Méthode ' +  method + ' n'existe pas dans jQuery.tooltip' );

               }   

          };

        })( jQuery );

        // appelle la méthode initiatrice

        $('div').tooltip();

        // appelle la méthode initiatrice avec une option

        $('div').tooltip({

          foo : 'bar'

        });

        // appelle la méthode hide

$('div').tooltip('hide');

// appelle la méthode update avec une option

$('div').tooltip('update', 'This is the new tooltip content!');

c'est une façon standard d'encapsuler ses méthodes de plugins dans la communauté jQuery, c'est aussi le cas pour jQueryUI. http://jqueryui.com/

Évènements

la méthode bind() permet de donner un espace de nom à des évènements liés. Si votre plugin lie un évènement, c'est une bonne pratique de lui donner un espace de nom. ainsi, si vous avez besoin de le délier avec unbind() sans interférer avec les autres évènements qui pourraient avoir été liés avec le même type d'évènement. Vous pouvez ajouter le nom de l'espace nom_de_namespace au type d'évènement que vous liez, comme ceci.

        (function( $ ){

          var methods = {

                init : function( options ) {

                  return this.each(function(){

                        $(window).bind('resize.tooltip', methods.reposition);

                  });

                },

                destroy : function( ) {

                  return this.each(function(){

                        $(window).unbind('.tooltip');

                  })%%

                },

                reposition : function( ) {

                  // ...

                },

                show : function( ) {

                  // ...

                },

                hide : function( ) {

                  // ...

                },

                update : function( content ) {

                  // ...

                }

          };

          $.fn.tooltip = function( method ) {

               if ( methods[method] ) {

                 return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));

               } else if ( typeof method === 'object' || ! method ) {

                 return methods.init.apply( this, arguments );

               } else {

                 $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );

               }   

          };

        })( jQuery );

        $('#fun').tooltip();

        // et un peu plus tard...

        $('#fun').tooltip('destroy');

Dans cet exemple, quand tooltip est initialisé avec la méthode init la méthode reposition est liée à l'évènement de redimension de la fenêtre sous l'espace de nom tooltip. Plus loin, si le développeur a besoin de détruire tooltip, nous pouvons délier les évènements liés à ce plugin en lui passant le nom de l'espace, ici tooltip, à la méthode unbind. Cela nous permet de délier les évènements d'un plugin en toute sécurité sans délier d'autres évènements liés en dehors du plugin.

Data

Quand nous avons besoin de maintenir un état ou de vérifier que notre plugin a été initialisé sur un certain élément, la méthode jQuery data est un très bon moyen de garder une trace des variables sur les éléments. Cependant, au lieu de garder une trace de quelques appels de données séparés avec des noms différents, il vaut mieux utiliser un objet pour héberger toutes les variables et accéder à cet objet par un seul espace de nom.

        (function( $ ){

          var methods = {

                init : function( options ) {

                  return this.each(function(){

                        var $this = $(this),

                                data = $this.data('tooltip'),

                                tooltip = $('<div />', {

                                  text : $this.attr('title')

                                });

                        // si le plugin n'a pas encore été initialisé

                        if ( ! data ) {

                        

                          /*

                                faire des trucs ici

                          */

                          $(this).data('tooltip', {

                                  target : $this,

                                  tooltip : tooltip

                          });

                        }

                  });

                },

                destroy : function( ) {

                  return this.each(function(){

                        var $this = $(this),

                                data = $this.data('tooltip');

                        // Namespacing FTW

                        $(window).unbind('.tooltip');

                        data.tooltip.remove();

                        $this.removeData('tooltip');

                  })

                },

                reposition : function( ) { // ... },

                show : function( ) { // ... },

                hide : function( ) { // ... },

                update : function( content ) { // ...}

          };

          $.fn.tooltip = function( method ) {

               if ( methods[method] ) {

                 return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));

               } else if ( typeof method === 'object' || ! method ) {

                 return methods.init.apply( this, arguments );

               } else {

                 $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );

               }   

          };

        })( jQuery );

Résumé et meilleures pratiques

Écrire des plugins jQuery vous permet à tirer le meilleur profit de la bibliothèque et abstraire vos plus intelligentes et utiles fonctions à travers un code réutilisable pouvant vous faire faire un grand gain de temps et rendre votre développement encore plus efficace. Voici un bref résumé de cet article et ce que vous devez garder à l'esprit quand vous développerez votre prochain plugin jQuery:

Comme le conseille Paul Irish un des auteurs de Boiler Plate, consulter la source commentée de jQuery pour comprendre comment elle fonctionne est un excellent moyen d'apprendre à manier le javascript en profondeur et développer ses propres solutions.

http://code.jquery.com/jquery.js

Mettez la en marque page :) à vous de jouer maintenant!