Mise à jour : Février 2013

Un plugin CKEditor pour les carrousels jQuery

Les carrousels jQuery sont élégants, dynamiques et pratique pour visualiser des photos. Il en existe une multitude sur le web. Ils sont généralement faciles à installer, mais la mise à jour régulière des images peut être fastidieuse. L'objectif est donc de créer un plugin pour CKEditor adaptable à de nombreux carrousels.

Ce plugin très simple prend l'aspect d'un bouton dans CKEditor. Ce bouton permet de sélectionner une image et d'y ajouter un texte de description. Il récupère également la dimension de l'image. Le plugin génère ensuite, vers l'éditeur, un code HTML compatible avec le carrousel. Il suffit donc d'intégrer le carrousel dans un template pour le piloter depuis un CMS utilisant CKEditor.

Plugin Carrousel pour CKEditor

Ce plugin s'appellera 'gallery'. Dans le dossier ckeditor/plugins/gallery/, on placera le fichier plugin.js et le bouton. Dans le dossier ckeditor/plugins/gallery/dialogs/, le fichier gallery.js. Voici un bouton inspiré du bouton image : bouton gallery

Voici le fichier plugin.js :

// gallery/plugin.js
CKEDITOR.plugins.add('gallery',   //nom du plugin
    {   
    requires: ['dialog'], // besoin d'une fenetre de dialogue
    init:function(a) {
        var b="gallery";
        var c=a.addCommand(b,new CKEDITOR.dialogCommand(b));
        c.modes={wysiwyg:1,source:1};
        c.canUndo=true;
 
        // ajout d'un bouton pour CKEditor
        a.ui.addButton("gallery",
            {
            label:'Gallery carrousel',
            command:b,
            icon:this.path+"gallery.png"
            });
        // emplacement de la boite de dialogue
        CKEDITOR.dialog.add(b,this.path+"dialogs/gallery.js")
        }
    });

Et le fichier gallery.js :

// gallery/dialogs/gallery.js
// (inspiré du plugin image)
CKEDITOR.dialog.add("gallery",function(e)
    {
    var carH = 600, carV = 60; // dimension du carrousel à ajuster
    //
    var out, uri, des, tit, wid, hei, previewPreloader;
    var resetSize = function( dialog ) // mise à jour height et width
        {
        var oImageOriginal = dialog.originalElement;
        if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
            {
            wid = dialog.getContentElement( 'info', 'txtWidth' );
            hei = dialog.getContentElement( 'info', 'txtHeight' );
            wid && wid.setValue( oImageOriginal.$.width );
            hei && hei.setValue( oImageOriginal.$.height );
            }
        };
    var onImgLoadEvent = function() // image ready
        {
        var original = this.originalElement;
        original.setCustomData( 'isReady', 'true' );
        original.removeListener( 'load', onImgLoadEvent );
        resetSize( this );
        };
         
    return{
        title:'Gallery carrousel - ' + carH + 'x' + carV,
        resizable : CKEDITOR.DIALOG_RESIZE_BOTH,
        minWidth:300, minHeight:150,
        onShow : function()
            {
            var editor = this.getParentEditor(),
            sel = this.getParentEditor().getSelection(),
            element = sel.getSelectedElement(),
            previewPreloader=new CKEDITOR.dom.element('img',editor.document);
            this.preview = CKEDITOR.document.getById( 'previewImage1');
            this.originalElement = editor.document.createElement( 'img' );
            this.originalElement.setCustomData( 'isReady', 'false' );
            },
        onOk:function()
            {
            if (wid/hei>carH/carV) // mise aux dimensions du carrousel
                { hei = Math.round(hei*carH/wid); wid = carH; }
            else { wid = Math.round(wid*carV/hei); hei = carV; }
         
            // HTML de sortie à parametrer
            out = '<ul class="ad-thumb-list"><li>';
            out += '<a href="'+uri+'"><img src="'+uri+'" width="'+wid+'"
            height="'+hei+'" alt="'+des+'" class="image0"></a>';
            out += '</li></ul>';
             
            editor.insertHtml(out);
            },
        contents:[
            {
            id:'info',
            name:'info',
            label:'Tab',
            elements:[
                {
                type : 'button',
                hidden : true,
                id : 'browse',
                filebrowser :
                    {
                    action:'Browse',
                    target:'info:txtid', // Mise à jour du champ
                    // url:'template/js/kcfinder/browse.php?type=images', // KCFINDER
                    url:editor.config.filebrowserImageBrowseLinkUrl,
                    },
                label : editor.lang.common.browseServer,
                style : 'float:right',
                },
                {
                id:'txtid',
                name:'txtid',
                type:'text',
                label:'Url',
                validate:function(){uri=this.getValue();},
                onChange : function()
                    {
                    var dialog = this.getDialog(),
                    newUrl = this.getValue();
                    if ( newUrl.length > 0 )
                        {
                        dialog = this.getDialog();
                        var original = dialog.originalElement;
                        original.setCustomData( 'isReady', 'false' );
                        original.on( 'load', onImgLoadEvent, dialog );
                        original.setAttribute( 'src', newUrl );
                        }
                    },
                },
                {
                id:'desid',
                name:'desid',
                type:'text',
                label:'Description',
                validate:function(){des=this.getValue();},
                },
                {
                id:'titid',
                name:'titid',
                type:'text',
                label:'Titre',
                style : 'visibility:hidden;', // suivant besoins
                validate:function(){tit=this.getValue();},
                },
                { // boite masquée
                id:'txtWidth',
                name:'txtWidth',
                type : 'text',
                style : 'visibility:hidden;',
                width: '40px',
                label:'Width',
                validate:function(){wid=this.getValue();},
                },
                { // boite masquée
                id:'txtHeight',
                name:'txtHeight',
                type : 'text',
                style : 'visibility:hidden;',
                width: '40px',
                label:'Height',
                validate:function(){hei=this.getValue();},
                },
                { // boite masquée
                type : 'vbox',
                height : '20px',
                children :
                    [
                    {
                    type : 'html',
                    id : 'htmlPreview',
                    style : 'visibility:hidden;',
                    html : '<div>Image<br><img id="previewImage1" alt="">',
                    }
                    ]
                }
                ]
            }],
        buttons:[
        CKEDITOR.dialog.okButton,
        CKEDITOR.dialog.cancelButton],
        };
    });

Pour être pris en compte par CKEditor, il faut déclarer ce plugin. Ouvrir le fichier config.js du dossier ckeditor et ajouter :

CKEDITOR.editorConfig = function( config )
    {
    config.extraPlugins='gallery';
// et ajouter le bouton 'gallery' à la liste des boutons.

Avec le CMS GetSimple, ce n'est pas config.js mais gsconfig.php, à la racine, qu'il faut modifier :

# WYSIWYG Editor Options   
define('GSEDITOROPTIONS',"skin : 'v2', 
extraPlugins:'jwplayer,gallery',
// et ajouter le bouton 'gallery' à la liste des boutons.

Le template doit contenir les ressources du carrousel :

  • Les lignes d'import de JQuery et du carrousel ;
  • Le script de lancement du carrousel.

Par exemple pour JCarousel :

<script type="text/javascript" src="chemin vers/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="chemin vers/jquery.jcarousel.min.js"></script>
<script type="text/javascript">
    jQuery(document).ready(function() {
        jQuery('#mycarousel').jcarousel({
        wrap: 'circular',
        auto: 2
        });
    });
</script>

Plugin Jcarousel

Il est nécessaire d'ajuster les paramètres selon le fonctionnement du carrousel. Par exemple, ad-gallery réclame la séquence suivante :

<div id="gallery" class="ad-gallery">
    <div class="ad-image-wrapper"></div>
    <div class="ad-controls"></div>
    <div class="ad-nav">
        <div class="ad-thumbs">
            <ul class="ad-thumb-list">
                <li>
                <a href="1.jpg">
                    <img src="thumb1.jpg" alt="This is a very nice...">
                </a>
                </li>
                <li>
                <a href="10.jpg">
                    <img src="thumb10.jpg" alt="This is incredibly ...">
                </a>
                </li>
                <!-- et ainsi de suite -->
            </ul>
        </div>
    </div>
</div>

Notre plugin va s'occuper de la chaine comprenant les balises LI. Attention, comme CKEditor veut bien faire, il corrige systématiquement le code ce qui complique la tâche. Le code doit donc être ajusté. Dans le cas présent, la balise UL est intégrée à la séquence car CKEditor supprime les doublons UL pour n'en mettre que deux (voir plus haut, ligne 48).

Dans le fichier HTML, il suffira de placer l'ensemble du code du carrousel ci-dessus, de retirer ce qui est pris en compte par le plugin et de le remplacer par la commande spécifique au CMS pour inclure une page.

Enfin, pour ce carrousel ad-gallery, la dimension des images concerne les vignettes (les images grands formats se dimensionnent automatiquement). Il faut donc donner une petite valeur à carV (gallery.js).

Autre exemple avec slick accessible slideshow, un carrousel très souple et sans fichier externe. La séquence à répéter est très simple et largement modifiable.

<div class="slide">
    <h2>Web Development Tutorial (titre)</h2>
    <p><a href="/"><img src="1.jpg" alt="alt" height="145" width="215"></a>
    If you're into developing web apps, blablabla (tag HTML possible)</p>
</div>

Ici, il faut un titre en plus d'une description. La ligne 106 dans gallery.js doit être supprimée.

Avec les balises DIV, CKEditor peut réagir curieusement. Pour éviter ce désagrément, on ajoute une balise HR, en fin de séquence, qui n'est pas gênante pour le carrousel :

// HTML de sortie à parametrer
out = '<div class="slide"><h2>'+tit+'</h2><p><a href="'+uri+'">
<img src="'+uri+'" width="'+wid+'" height="'+hei+'" alt="'+des+'"></a>'
+des+'</p></div><hr>';

Avec certains carrousels, le HR ou les balises supplémentaires posées par CKEditor (les P !) peuvent poser des problèmes. CKEditor peut également corriger systématiquement la séquence pour la rendre incompatible avec le carrousel. Avec un peu de jQuery, il est possible d'effacer ces modifications. Par exemple, pour supprimer le [P] qui englobe les balises [IMG], il suffit d'ajouter ce script en bas de la page HTML :

<script type="text/javascript">
    imgs = $('#slider').children('p').html();
    $('#slider').children('p').remove();
    $('#slider').append(imgs);
</script>

Cette astuce fonctionne parfaitement avec le superbe Nivo Slider qui offre de nombreuses transitions magnifiques.

NivoSlider