Date de publication: le vendredi 1 mai 2009 à 19h20
Dernière modification: par Pascal BOYER le lundi 4 mai 2009 à 18h54
« Article précédent: eZ Publish : créer une galerie d'images avec la librairie highSlide
» Article suivant: eZ Publish : création automatique d'une galerie d'images CSS - Partie I
L'objet de cet article est en lien direct avec celui-ci, eZ Publish : créer une galerie d'images avec la librairie highSlide , en ce qu'il en constitue en quelque sorte la suite. Il s'agit en effet de présenter ici la mise en oeuvre d'une page de contact utilisant, conjointement à la galerie d'images, la librairie highSlide. Cette mise en oeuvre justifie un article en raison des nombreux problèmes que posent et la double utilisation de highslide et l'utilisation de plusieurs templates par le système d'envoi de formulaires.
Exemple de page de contact
Ressources
Vous trouverez sur le site highslide.com beaucoup de renseignements utiles et particulièrement:
- Une page de documentation sur l'installation de highSlide: Installation
- Un tutorial: Tutorial
- Une page référençant l'ensemble des variables, fonctions etc...: Référence
- La même référence que ci-dessus enrichie d'exemples: Références avec exemples
- Une page de questions fréquemment posées: FAQ
- Un forum: Forum
Problèmes rencontrés
- Paramétrage distinct pour chaque page utilisant highSlide,
- Affichage de la page de contact dès son chargement sans passer par un clic sur un lien,
- Positionnement du bouton de fermeture de la popup,
- Lier le bouton de fermeture de la popup à un lien de redirection,
- Affichage dans la popup des différents templates du système d'envoi du formulaire,
- Problème d'affichage avec IE7.
I - Le fichier highSlide-full.js
Le fichier javascript highSlide-full.js peut être téléchargé sur cette page: http://highslide.com/download.php
Comme nous serons amenés à modifier certaines valeurs de paramètres de ce fichier, mieux vaut ne pas télécharger dès à présent la version highSlide-full.packed.js. Il sera toujours temps d'obfusquer et/ou de compresser ce fichier ultérieurement.
Nous utilisons cette version complète (mais un peu lourde) pour être sûr, lors de la mise en oeuvre de la page de contact, de ne pas rencontrer de problèmes javascript liés à l'absence d'options dans le fichier highSlide.js
L'inclusion de ce javascript dans le template pagelayout.tpl requière le code suivant (juste après la balide <body>):
{section name=JavaScript loop=ezini( 'JavaScriptSettings', 'JavaScriptList', 'design.ini' ) } <script language="JavaScript" type="text/javascript" src={concat( 'javascript/',$:item )|ezdesign}></script> {/section}
Ce qui implique de modifier ainsi le fichier de surcharge design.ini.append.php du siteaccess public:
[JavaScriptSettings] JavaScriptList[]=highslide-full.js
Par ailleurs, sous la balise {/section}, nous ajoutons ces lignes:
{literal} <script type="text/javascript"> hs.graphicsDir = '/design/plain_site/images/graphics/'; </script> {/literal}
La troisième ligne indique à highSlide le chemin vers le sous-répertoire graphics dans lequel il trouvera les différents éléments graphiques utilisés pour afficher la popup.
:
Il est tout à fait possible de ne pas inclure les 5 lignes ci-dessus et de modifier directement la ligne 55 de highSlide-full.js:
56 graphicsDir : '/design/plain_site/images/graphics/'
II - La galerie photo highSlide
Le template highSlide.tpl
Ayant légèrement modifié la classe d'objet et le code du template design/plain_site/override/templates/photos/ highSlide.tpl présenté par l'article eZ Publish : créer une galerie d'images avec la librairie highSlide , voici le code modifié (et commenté) de ce template:
1 {* CE TEMPLATE PERMET DE CREER UNE GALERIE D'IMAGES highSlide *} 2 {literal} 3 <script type="text/javascript"> 4 hs.showCredits = true; // Autorise l'affichage des options hs.lang au début de highslide.js 5 hs.align = 'center'; // Définit le positionnement de la popup 6 hs.transitions = ['expand', 'crossfade']; 7 hs.fadeInOut = 'true'; 8 hs.outlineType = 'rounded-white'; // Définit le type d'encadrement (voir répertoire design/plain_site/images/graphics/outlines/) 9 hs.numberPosition = 'caption'; // Définit la position de l'affichage de "Image 1 of X" 10 hs.dimmingOpacity = 0.35; // Définit l'opacité de fond extérieur à la popup 11 hs.addSlideshow({ 12 //slideshowGroup: 'group', 13 interval: 5000, // Définit l'intervalle de temps entre deux image en mode slideshow 14 repeat: true, // Retour à la première image une fois arrivé à la dernière 15 useControls: true, // Valide l'affichage des boutons de contrôle 16 fixedControls: 'fit', 17 overlayOptions: { 18 opacity: .75, // Opacité des boutons de contrôle 19 position: 'bottom center', // Position des boutons de contrôle 20 hideOnMouseOut: true, // Cache les boutons de contrôle lorsque la souris n'est plus au-dessus de l'image 21 } 22 }); 23 </script> 24 {/literal} 25 {* $liste_galeries CONTIENT LA LISTE DES DOSSIERS INSTANCIES A PARTIR DE LA CLASSE gallery_photos *} 26 {def $liste_galeries=fetch_alias( children, 27 hash( 'parent_node_id', $node.node_id, 28 depth, 1, 29 class_filter_type, include, 30 class_filter_array, array( 'gallery_photos' ))) 31 $i='1'} 32 {* POUR CHAQUE DOSSIER DE LA CLASSE gallery_photos *} 33 {foreach $liste_galeries as $gallery} 34 <div class="highslide-gallery"> 35 {* SI LE DOSSIER CONTIENT DES IMAGES C'EST À DIRE S'IL CONTIENT DES OBJETS DE LA CLASSE image_music *} 36 {if gt($gallery.children_count,0)} 37 {* ALORS ON RECUPÈRE LE PREMIER OBJET image_music DANS LA VAIRIABLE $liste_images - CE PREMIER OBJET EST LA PREMIÈRE IMAGE DE LA GALERIE *} 38 {def $liste_images=fetch_alias( children, 39 hash( 'parent_node_id', $gallery.node_id, 40 depth, 1, 41 limit, 1, 42 class_filter_type, include, 43 class_filter_array, array( 'image_music' )))} 44 {* ET ON ECRIT LE CODE HTML QUI AFFICHERA LA VIGNETTE DE LA GALERIE TRAITÉE - C'EST LA PREMIÈRE IMAGE DE LA GALERIE *} 45 <a id="thumb1" href={$liste_images.0.data_map.image.content.original.url|ezroot} class="highslide" {literal}onclick="return hs.expand(this, { slideshowGroup:{/literal} {$i} {literal}} )"{/literal}><img src={$liste_images.0.data_map.image.content.original.url|ezroot} alt="Highslide JS" title="Click to enlarge" /></a> 46 {* PUIS ON ECRIT LE COMMENTAIRE LIÉ À CETTE PREMIÈRE VIGNETTE *} 47 <div class="highslide-caption">{attribute_view_gui attribute=$liste_images.0.data_map.commentaire_image}</div> 48 {* PUIS ON REGARDE S'IL EXISTE D'AUTRES IMAGES DANS LA GALERIE *} 49 {if gt($gallery.children_count,1)} 50 <div class="hidden-container"> 51 {* AUQUEL CAS ON RECUPÈRE LA LISTE DE CES AUTRES IMAGES - ON DECALE LE DÉBUT DE LA RECHERCHE À LA DEUXIÈME IMAGE: offset, 1 *} 52 {def $liste_images1=fetch_alias( children, 53 hash( 'parent_node_id', $gallery.node_id, 54 offset, 1, 55 depth, 1, 56 class_filter_type, include, 57 class_filter_array, array( 'image_music' )))} 58 {* ET POUR CHACUNE DE CES AUTRES IMAGES *} 59 {foreach $liste_images1 as $image1} 60 {* ON ÉCRIT LE CODE HTML NECESSAIRE À LEUR AFFICHAGE *} 61 <a href={$image1.data_map.image.content.original.url|ezroot} class="highslide" {literal}onclick="return hs.expand(this, { thumbnailId: 'thumb1', slideshowGroup:{/literal} {$i} {literal} } )"{/literal} ></a> 62 {* AINSI QUE LE COMMENTAIRE AFFÉRENT *} 63 <div class="highslide-caption">{attribute_view_gui attribute=$image1.data_map.commentaire_image}</div> 64 {/foreach} 65 </div> 66 {/if} 67 {/if} 68 {* ON ECRIT ICI LE TITRE DE LA GALERIE = LE NOM DU DOSSIER gallery_photos *} 69 <div class="titreGalerie">{$gallery.data_map.nom_dossier.content}</div> 70 </div> 71 {* ON INCRÉMENTE LA VARIABLE $i DE UNE UNITÉ *} 72 {set $i=inc( $i )} 73 {/foreach} 74 <div class="break"></div>
:
Il est très important de commenter la ligne 12.
Voilà donc la galerie de photos highSlide fonctionnelles et utilisant ses propres paramètres.
III - La page de contact
Considérations générales
La page de contact affiche, dans son fonctionnement par défaut, le contenu du template design/plain_site/override/templates/full/ pagecontact.tpl.
Par ailleurs, par défaut, un élément highSlide ne s'affiche qu'après avoir cliqué sur un lien.
On peut donc s'attendre à avoir, par défaut, le fonctionnement suivant de la page contact « highslidesisée»:
- L'utilisateur clique sur le menu Contact,
- Une page s'affiche avec un lien (le formulaire du template pagecontact.tpl est caché par highSlide),
- L'utilisateur clique sur le lien,
- Le formulaire s'affiche dans la popup.
Autant dire que ce fonctionnement n'est pas satisfaisant du tout. Le but à atteindre est en effet que le formulaire s'affiche dans la popup dès que l'utilisateur clique sur le menu Contact.
Autre difficulté: le système de validation du formulaire fait appel aux deux templates suivants:
- design/standard/templates/content/ collectedinfo_validation.tpl : page de validation présentant une erreur de saisie,
- design/standard/templates/content/collectedinfo/ form.tpl : page récapitulative des informations effectivement envoyées.
Le premier, inclus dans le code du template du formulaire de contact, s'affiche donc, lorsqu'il est utilisé, dans la page affichant le contenu du template pagecontact.tpl.
Le deuxième utilise quant à lui sa propre page d'affichage.
L'affichage de chacun de ces deux templates devra donc également se faire à l'intérieur d'une popup highSlide.
Enfin, selon la page affichée, le formulaire ou la page de validation ou encore la page récapitulative, que voit l'utilisateur s'il clique sur le bouton Close de la popup ? Une page blanche. Or ceci non plus n'est pas acceptable. Il faut donc que le bouton de fermeture de la popup soit, par exemple, un lien vers la page d'accueil du site.
Le code du template pagecontact.tpl
Voici le code commenté du template pagecontact.tpl:
1 {literal} 2 <script type="text/javascript"> 3 hs.addEventListener(window, "load", function() { 4 // click the element virtually: 5 document.getElementById("autoload").onclick(); 6 }); 7 hs.showCredits = false; // On supprime l'affichage de "Powered by ..." 8 hs.dimmingOpacity = 0.55; // Opacité du fond général 9 hs.expandDuration = 750; // Temps d'affichage de la popup 10 hs.numberPosition = null; // Supprime l'affichage de "Image 1 of X" 11 hs.headingText = 'FEMOCA'; // Définit le titre de la popup 12 hs.align = 'center'; // Définit la position de la popup 13 hs.marginLeft = -140; // Redéfinit la marge à gauche relativement à la position centrale définit ci-dessus (ATTENTION : PAS DE VALEURS NEGATIVES A CAUSE DE IE !!!!!!!!! ) 14 hs.onDimmerClick = function() { // Supprime la fermeture de la popup si on clic à l'extérieur de la popup 15 return false; // si on clique sur le fond général opaque 16 }; 17 hs.registerOverlay({ // Surcharge certaines règles CSS de certaines classes 18 html: '<div class="closebutton" title="Fermer"><a href="http://monsite.fr" style="display: block; width: 30px; height: 30px; outline: none; margin: -2px -12px 0 0;"></a></div>', 19 position: 'top right', // Position du bouton de fermeture 20 fade: 2, // fading the semi-transparent overlay looks bad in IE 21 useOnHtml: true // Active la surcharge: TRES IMPORTANT. 22 }); 23 </script> 24 {/literal} 25 <a id="autoload" href="#" {literal}onclick="return hs.htmlExpand(this, { outlineType: 'glossy-dark', wrapperClassName: 'draggable-header'})"{/literal} class="highslide"></a> 26 <div class="highslide-maincontent"> 27 <div class="content-view-full"> 28 <div class="class-feedback-form"> 29 {include name=Validation uri='design:content/collectedinfo_validation.tpl' 30 class='message-warning' 31 validation=$validation collection_attributes=$collection_attributes} 32 33 <div class="attribute-short"> 34 {attribute_view_gui attribute=$node.data_map.descriptif_formulaire} 35 </div> 36 <form method="post" action={"content/action"|ezurl}> 37 38 <div class="titreChamp">{$node.data_map.nom_expediteur.contentclass_attribute.name}<span class="champObligatoire"> (*)</span></div> 39 <div class="attribute-email"> 40 {attribute_view_gui attribute=$node.data_map.nom_expediteur} 41 </div> 42 <div class="titreChamp">{$node.data_map.mail_expediteur.contentclass_attribute.name}<span class="champObligatoire"> (*)</span></div> 43 <div class="attribute-email"> 44 {attribute_view_gui attribute=$node.data_map.mail_expediteur} 45 </div> 46 <div class="titreChamp">{$node.data_map.coordonnees_expediteur.contentclass_attribute.name}</div> 47 <div class="attribute-email"> 48 {attribute_view_gui attribute=$node.data_map.coordonnees_expediteur} 49 </div> 50 <div class="titreChamp">{$node.data_map.objet.contentclass_attribute.name}<span class="champObligatoire"> (*)</span></div> 51 <div class="attribute-email"> 52 {attribute_view_gui attribute=$node.data_map.objet} 53 </div> 54 <div class="titreChamp">{$node.data_map.message_expediteur.contentclass_attribute.name}<span class="champObligatoire"> (*)</span></div> 55 <div class="attribute-email"> 56 {attribute_view_gui attribute=$node.data_map.message_expediteur} 57 </div> 58 59 <div class="content-action"> 60 <input type="submit" class="defaultbutton" name="ActionCollectInformation" value="{"Send form"|i18n("design/base")}" /> 61 <input type="hidden" name="ContentNodeID" value="{$node.node_id}" /> 62 <input type="hidden" name="ContentObjectID" value="{$node.object.id}" /> 63 <input type="hidden" name="ViewMode" value="full" /> 64 </div> 65 </form> 66 <br /> 67 </div> 68 </div> 69 </div>
- Lignes 3 et 5 : indiquent que le formulaire doit être affiché lors du chargement de la page. Ceci permet de ne pas devoir cliquer sur un lien lorsque s'affiche la page qui affiche le contenu du template pagecontact.tpl.
Le bouton de fermeture de la popup
-
Lignes 17 à 22 : surchargent la classe CSS closebutton et font de celui-ci un lien vers la page d'accueil du site.
En complément de ces 6 lignes, il sera nécessaire d'adapter les lignes suivantes de la feuille de styles highslide.css:
133 .closebutton {
134 position: relative;
135 top: -15px;
136 left: 15px;
137 width: 30px;
138 height: 30px;
139 cursor: pointer;
140 background: url(../images/graphics/close.png);
141 /* NOTE! For IE6, you also need to update the highslide-ie6.css file. */
142 }
...
...
341 .draggable-header .highslide-header .highslide-close { /* POSITION DU BOUTON PAR DEFAUT DE FERMETURE DE LA POPUP */
342 display: none; /* Cache le bouton Close utilisé par défaut */
Le template de validation/contrôle collectedinfo_validation.tpl
Par défaut, le template de validation des saisies de l'utilisateur est design/standard/templates/content/ collectedinfo_validation.tpl. Ce template est appelé par la ligne 29 du template pagecontact.tpl.
Pour ne pas faire de surcharge tout en n'utilisant pas le template par défaut, il suffit de copier collectedinfo_validation.tpl dans le design du siteaccess public.
Si le répertoire content n'existe pas dans design/plain_site/templates/ lancez les trois commandes suivantes:
cp -Rp design/standard/templates/content/ design/plain_site/templates/
rm -R design/plain_site/templates/content/*
cp -p design/standard/templates/content/collectedinfo_validation.tpl design/plain_site/templates/content/
Si le répertoire content existe déjà dans design/plain_site/templates/ lancez la commande suivante:
cp -p design/standard/templates/content/collectedinfo_validation.tpl design/plain_site/templates/content/
Il devient dès lors possible de modifier à notre guise le template design/plain_site/templates/content/ collectedinfo_validation.tpl sans toucher à celui par défaut.
L'utilisation de ce template ne pose aucun problème avec highSlide et sans modification particulière sera affiché dans la popup.
Le template récapitulatif form.tpl
Le template utilisé par défaut pour présenter un récapitulatif des informations saisies et envoyées est design/standard/templates/content/collectedinfo/ form.tpl. Comme pour le template collectedinfo_validation.tpl, nous allons en faire une copie dans design/plain_site/templates/content/collectedinfo/
Si le répertoire collectedinfo n'existe pas dans design/plain_site/templates/content/ lancez les trois commandes suivantes:
cp -Rp design/standard/templates/content/collectedinfo/ design/plain_site/templates/content/
rm -R design/plain_site/templates/content/collectedinfo/*
cp -p design/standard/templates/content/collectedinfo/form.tpl design/plain_site/templates/content/collectedinfo/
Si le répertoire collectedinfo existe déjà dans design/plain_site/templates/content/ lancez la commande suivante:
cp -p design/standard/templates/content/collectedinfo/form.tpl design/plain_site/templates/content/collectedinfo/
Le code commenté du template form.tpl est le suivant:
1 {literal} 2 <script type="text/javascript"> 3 hs.addEventListener(window, "load", function() { 4 // click the element virtually: 5 document.getElementById("autoload").onclick(); 6 }); 7 hs.showCredits = false; // On supprime l'affichage de "Powered by ..." 8 hs.dimmingOpacity = 0.55; // Opacité du fond général 9 hs.expandDuration = 750; // Temps d'affichage de la popup 10 hs.numberPosition = null; // Supprime l'affichage de "Image 1 of X" 11 hs.headingText = 'FEMOCA'; // Définit le titre de la popup 12 hs.align = 'center'; // Définit la position de la popup 13 hs.marginLeft = -140; // Redéfinit la marge à gauche relativement à la position centrale définit ci-dessus 14 hs.onDimmerClick = function() { // Supprime la fermeture de la popup si 15 return false; // on clique sur le fond général opaque 16 }; 17 hs.registerOverlay({ // Surcharge certaines règles CSS de certaines classes 18 html: '<div class="closebutton" title="Fermer"><a href="http://linuxorable.fr/femoca" style="display: block; width: 30px; height: 30px; outline: none; margin: -2px -17px 0 5px;"></a></div>', 19 position: 'top right', // Position du bouton de fermeture 20 fade: 2, // fading the semi-transparent overlay looks bad in IE 21 useOnHtml: true // Active la surcharge: TRES IMPORTANT. 22 }); 23 </script> 24 {/literal} 25 <a id="autoload" href="#" {literal}onclick="return hs.htmlExpand(this, { outlineType: 'glossy-dark', wrapperClassName: 'draggable-header'})"{/literal} class="highslide"></a> 26 <div class="highslide-maincontent"> 27 {default collection=cond( $collection_id, fetch( content, collected_info_collection, hash( collection_id, $collection_id ) ), 28 fetch( content, collected_info_collection, hash( contentobject_id, $node.contentobject_id ) ) )} 29 30 {set-block scope=global variable=title}{'Form %formname'|i18n('design/standard/content/form',,hash('%formname',$node.name|wash))}{/set-block} 31 32 <h1>{'Collected information'|i18n('design/standard/content/form')}</h1> 33 34 <h2>{$object.name|wash}</h2> 35 36 {section show=$error} 37 38 {section show=$error_existing_data} 39 <p>{'You have already submitted this form. The previously submitted data was:'|i18n('design/standard/content/form')}</p> 40 {/section} 41 42 {/section} 43 44 {section loop=$collection.attributes} 45 46 <h3>{$:item.contentclass_attribute_name|wash}</h3> 47 48 {attribute_result_gui view=info attribute=$:item} 49 50 {/section} 51 52 <p/> 53 {/default} 54 </div>
Après avoir vidé les caches, tout devrait fonctionner parfaitement.
Commentaires














