Développer un plugin jQuery UI : héritage

Bookmark and Share
Lundi 5 septembre 2011
Posté par Gilles Felix

Développer un plugin jQuery UI : héritage
En cinq chapitres, nous avons appris à développer un plugin jQuery UI. J'espère que, comme moi, vous avez été convaincus par l'architecture de widget mise à disposition par le framework jQuery UI.
Personnellement c'est le chapitre d'aujourd'hui qui m'a le plus attiré dans la démarche jQuery UI : la possibilité d'étendre facilement un widget.

Sommaire du tutoriel
Développer un plugin jQuery UI

  1. Introduction
  2. Mise en forme
  3. Options et méthodes
  4. Événements
  5. Fonctionnalités avancées
  6. Héritage

Le développement Javascript utilise encore trop peu les concepts de développement Objet. L'explosion des sites interactifs, déportant la complexité du développement du serveur vers le navigateur, est assez récente. Le Javascript embarqué dans les pages se limitait, il y a encore quelques années, à quelques fonctions pour valider les formulaires et deux / trois autres, toutes faites, pour gérer du rollover. Les bonnes pratiques du développement Javascript émergent petit à petit, comme pour tout langage informatique. Il faut reconnaître également qu'en Javascript "de base", créer et manipuler des objets est tout sauf intuitif, y compris (et surtout ?) pour un développeur maîtrisant cette technique dans un autre langage.

Il existe quelques frameworks Javascript facilitant le codage en Objet. Pour parler franchement je n'en ai testé aucun : quand je code du Javascript en Objet, je réinvente la roue à chaque fois. Jusqu'à ce que je lise ce tutorial jQuery dont je vous ai parlé au premier chapitre. À l'époque je cherchais un plugin jQuery du type "popup DHTML". J'aimais bien le widget Dialog de jQuery UI mais il lui manquait quelques fonctionnalités dont j'avais absolument besoin. A + B = BAnco, et si j'étendais le widget Dialog pour lui ajouter les fonctionnalités qui me manquaient.

Au final, mon projet a changé de direction et je n'ai pas eu besoin de mon widget Dialog étendu. Mais j'ai gardé l'habitude de coder mes widgets en jQuery UI et je ne le regrette pas. Aujourd'hui je développe une interface type navigateur avec une barre d'onglets bourrée de fonctionnalités, et bien entendu je suis parti du widget Tabs de jQuery UI.

Quand est-ce qu'on revoit du code ?

Mais assez causé. Revenons à notre exemple. Mettons-nous dans la peau d'un développeur qui est prêt à utiliser notre widget mais qui aimerait bien lui ajouter un petit plus non prévu.

Notre plugin encapsule un élément, lui ajoute un titre et permet d'ouvrir / fermer le bloc. Notre développeur aimerait ajouter une petite poignée en bas du bloc pour rendre l'ouverture / fermeture plus intuitive.

Commençons par étendre notre widget initial.

// Notre nouveau widget s'appelle blocextend
// Le second paramètre est notre widget bloc initial
// Le troisième paramètre contient le JSON qui va étendre l'objet bloc initial
// Toute fonction ou option non redéfinie sera identique à la version de bloc
$.widget ('demo.blocextend', $.demo.bloc, {
});

Ajoutons notre petite poignée via une redéfinition de la méthode _create.

_create: function() {
    var self  = this;

    // On appelle la méthode _create du widget bloc initial
    $.demo.bloc.prototype._create.call(this);

    // Notre poignée est un simple lien
    this.uiBlocHandle = $('<a href="#"></a>')
        // La classe ui-bloc-handle nous permettra de positionner correctement la poignée
        .addClass('ui-bloc-handle ui-corner-all ui-state-default')
        // Ajout d'effets visuels d'interaction par les classes CSS d'état de jQuery UI
        .hover(function() {
            self.uiBlocHandle.addClass('ui-state-hover');
        }, function() {
            self.uiBlocHandle.removeClass('ui-state-hover');
        })
        .focus(function() {
            self.uiBlocHandle.addClass('ui-state-focus');
        })
        .blur(function() {
            self.uiBlocHandle.removeClass('ui-state-focus');
        })
        // On ajoute la poignée au container de widget créé dans le bloc initial
        .appendTo(self.uiBlocContainer);

    // Notre poignée contient un SPAN
    this.uiBlocHandleText = $('<span></span>')
        // Le SPAN sera une icône en forme de chevron orienté vers le Nord (ui-icon-carat-1-n)
        // Voir la page du themeroller de jQuery UI : http://jqueryui.com/themeroller/
        .addClass('ui-icon ui-icon-carat-1-n')
        // Le texte par défaut de notre poignée
        .text('Ouvrir le bloc')
        // On ajoute le SPAN à la poignée
        .appendTo(self.uiBlocHandle);
},

Ajoutons un comportement à notre poignée via la méthode _init − pour comprendre la différence en _create et _init, voir le chapitre fonctionnalités avancées.

_init : function() {
    var self = this;

    // On appelle la méthode _init du widget bloc initial
    $.demo.bloc.prototype._init.call(this);

    // On enlève tous les événements click de la poignée
    // En cas de réinitialisation, cela évite d'ajouter un nouvel événement click
    // à notre poignée qui en a déjà potentiellement un
    self.uiBlocHandle.unbind('click');

    if (self.options.togglable) {
        // Notre bloc est fermable
        // On ajoute l'événement click à la poignée qui se contente de déclencher le click sur le titre
        self.uiBlocHandle.click(function(event) {
            self.uiBlocTitle.click();
        }).show(); // On affiche la poignée
    } else {
        // Le bloc n'est pas fermable, on cache la poignée
        self.uiBlocHandle.hide();
    }
},

Pour finir modifions les méthodes _open et _close pour ajuster le look de notre poignée en fonction de l'état du bloc.

_close: function() {
    var self = this;

    // On appelle la méthode _close du widget bloc initial
    $.demo.bloc.prototype._close.call(this);

    if (self.options.togglable) {
        // Notre bloc est fermable
        // On affiche la poignée qui a été cachée par la méthode _close du bloc initial
        self.uiBlocHandle.show();
    }

    // L'icône de la poignée devient un chevron orienté vers le sud
    // On change aussi le texte
    this.uiBlocHandleText.removeClass('ui-icon-carat-1-n').addClass('ui-icon-carat-1-s').text('Ouvrir le bloc');
},

_open: function() {
    var self = this;

    // On appelle la méthode _open du widget bloc initial
    $.demo.bloc.prototype._open.call(this);

    // L'icône de la poignée devient un chevron orienté vers le nord
    // On change aussi le texte
    this.uiBlocHandleText.removeClass('ui-icon-carat-1-s').addClass('ui-icon-carat-1-n').text('Fermer le bloc');
}

 

Un peu de CSS tout de même

Notre poignée est pour l'instant un simple lien à la fin du container de notre bloc. On va la positionner de façon à ce qu'elle apparaisse à cheval sur le bord inférieur du bloc, au milieu de la largeur.

/* CSS du widget blocextend pour positionner la poignée */
.ui-bloc {
    /* le bloc est passé en position relative pour pouvoir positionner la poignée à l'intérieur en absolu */
    position: relative;
}
.ui-bloc .ui-bloc-handle {
    /* La poignée est positionnée en absolu par rapport à son container */
    position: absolute;
    right: 50%; /* Elle s'affiche au milieu de la largeur du bloc */
    bottom: 0; /* Elle s'affiche en bas du bloc */
    margin: 0 -10px -10px 0; /* On décale les margin droit et bas de 10 pixels pour l'effet "A cheval" sur la bordure */
}

 

Elle est pas belle ma poignée ?

2 commentaires
  • Commentaire par kanor
    Mercredi 4 avril 2012 17:38
    Merci pour le tuto très intéressant
    petit détail il est conseillé de ne pas utilisé le namespace ui pour les plugin non lié au projet jquery ui
    http://ajpiano.com/widgetfactory/#slide22
  • Commentaire par Gilles FELIX
    Jeudi 5 avril 2012 08:28
    @Kanor : c'est exact je corrige ça de suite.
    Merci pour la remarque.
Laissez votre commentaire :