Positionnement des images à la volée

indigene

WRInaute accro
La galerie que j'ai développée est assez complète. Je peux charger 4 images par article, il y a un chapo, le corps de l'article, des tags, possibilité de lien externe en bas des articles. Tout ceci est géré automatiquement. Mais pour l'instant, les 4 images, si elles sont chargées, vont s'afficher en haut de l'article les unes en dessous des autres.

Je voudrais coder un truc pour pouvoir les positionner où je veux dans mon article, avec un float left, un float right, centrée ou cadrée à gauche ou à droite.

J'ai imaginé insérer dans le corps de mon article des codes de mise en forme qui seront utilisés par le script au moment de l'affichage.

Exemple de codes :
<IMAGE2FL> pour un float left de la seconde image
<IMAGE2G> pour un cadrage à gauche de la seconde image puis retour à la ligne (facile)
<IMAGE2D> pour un cadrage à droite de la seconde image puis retour à la ligne (un float ou un tableau)
<IMAGE2FR> pour un float right
<IMAGE2C> pour centrer (facile)

Les mêmes balises persos seront utilisées avec les images 1, 2, 3 et 4

Le problème va survenir quand je vais vouloir coder les DIV avec les float

Le corps du texte va se présenter comme ceci :
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blabla blablabla blablablabla blablablablablablabla blablablabla blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
<IMAGE2FL>
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blabla blablabla blablablabla blablablablablablabla blablablablablablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blabla blablabla blablablabla blablablablablablabla blablablabla blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla

C'est simple de coder la DIV avec le float left à la place de la balise (un simple remplacement avec un morceau de code en litéral et le nom des images pris dans la base). Mais ensuite, il faudrait que j'encadre toute la suite dans une nouvelle DIV. Jusque là rien de compliqué, je referme la DIV à la fin de mon contenu. Sauf si j'ai une seconde balise un peu plus loin. Il faudrait que la fermeture de la DIV ne se fasse pas à la fin du contenu mais juste avant l'ouverture de la seconde balise DIV, comme ceci :
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blabla blablabla blablablabla blablablablablablabla blablablabla blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
<DIV style="float:left;"><img src="www.example.com/nomdelimage2.jpg alt="titre de l'image2"></DIV><DIV>
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blabla blablabla blablablabla blablablablablablabla blablablablablablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla</DIV>
<DIV style="clear:both; float:right;"><img src="www.example.com/nomdelimage3.jpg alt="titre de l'image 3"></DIV><DIV>
blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla
blabla blablabla blablablabla blablablablablablabla blablablabla blablabla blabla bla blablablabla blabla blabla blablabla blablablabla blablablablablablabla blablablabla</DIV>

Auriez-vous une solution à me proposer pour coder ceci le plus simplement possible en php, sans avoir à exploser mon contenu en plusieurs morceaux que j'assemblerai par la suite les uns à la suite des autres avec les images qui s'intercalent entre chaque morceau ? Une expression régulière peut-être ? Cette expression positionnerait les <DIV> ouvrantes et fermantes et ensuite je n'aurai plus qu'à remplacer le nom des images (IMAGE2, etc...) par les infos trouvées en base. S'il ne reste que ça c'est simple à faire.

Notez que chaque image n'est pas forcément affichée dans l'ordre (je peux utiliser la 4 avant la 2, par exemple), je peux même utiliser la même image plusieurs fois.

Actuellement je code directement du html à l'intérieur de mes articles, c'est fastidieux
 

Leonick

WRInaute accro
pourquoi encapsuler l'image dans un div ? si tu mettais directement une class=à gauche" ou "à droite" sur ton image, ça ne pourrait pas le faire ?
 

indigene

WRInaute accro
Quand on dit float:left pour un objet il n'a en fait rien de flottant mais c'est tout le reste qui flotte autour de lui pour venir l'entourer. Je pourrais en effet mettre un float sur les images directement, mais ça ne changerait rien au fait que ce qui suit devrait être encapsuler dans une div et c'est là qu'était le problème, car si j'ouvre une DIV il faut ensuite la refermer et annuler ensuite le float.

J'ai résolu le problème en codant tout l'après-midi mais mon code est relativement lourd puisque la page source est passée de 43 ko à 64 ko. Mais ça fonctionne parfaitement :D

Maintenant je pourrais insérer des illustrations dans mes pages en codant juste une pseudo-balise très simple. La prochaine étape sera d'insérer la balise directement en javascript avec un petit bouton de ma fenêtre d'édition.
 

Leonick

WRInaute accro
indigene a dit:
Quand on dit float:left pour un objet il n'a en fait rien de flottant
si, il flotte, lui aussi
tiens, recopie ce code html
Code:
Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, <img src="http://www.indigene.free.fr/search_engines_animation.gif" style="float:right" />quand un peintre anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte.
Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker.
<img src="http://www.indigene.free.fr/search_engines_animation.gif" style="float:left" />Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un peintre anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker.
dans http://codepen.io/pen/?editors=111
tu verras que ça glisse sans problème à gauche ou à droite
 

indigene

WRInaute accro
Ca ne fera pas la même chose qu'avec des DIV car imagine que ton image de gauche soit en format vertical et plus haute que le texte, si ensuite tu veux mettre une autre image mais centrée dans la page, comme tu fais, elle ne sera pas centrée dans la page mais centrée dans l'espace à droite de l'image de gauche. En encapsulant dans une DIV, avant d'afficher l'image centrée, je referme la DIV et je fais un clear:both. La prochaine DIV sera positionnée en dessous de la première.

Je ne l'ai pas testé et je peux me tromper, mais en toute logique c'est comme ça que ça doit se passer. Si tu peux vérifier et me dire ce qu'il en est.
 

Leonick

WRInaute accro
tout dépend de ce que tu veux comme mise en page. Globalement, tu as raison dans ton raisonnement, sauf qu'on ne peut centrer horizontalement une image qu'en ayant un <div> / <p> qui prenne toute la largeur et on centre l'image dans ce div. Sauf à connaitre exactement la largeur de l'image et du div et de jouer avec la marge gauche/droite de l'image
 

indigene

WRInaute accro
pour centrer j'utilise tout simplement la balise standard du html : center
Ca a toujours fonctionné et ça fonctionne toujours, tout comme b pour mettre en gras, strong pour mettre en évidence quelque chose d'important, em, i, etc... Je n'utilise le css que quand il n'y a pas moyen de faire en html, pour les polices et les float par exemple. Et pour imbriquer les conteneurs DIV plutôt que de faire des tableaux.

Maintenant que j'arrive à positionner mes illustrations de 5 ou 6 manières différentes sans insérer de code dans mes articles mais juste avec une balise ultra simple, mon nouveau soucis est de pouvoir forcer l'attribut ALT et de pouvoir insérer une légende en dessous de l'illustration, tout aussi facilement. Je réfléchis encore à la technique que je vais adopter. Pour le ALT je reprend pour l'instant le titre de l'article en ajoutant "illustration" devant, mais du coup toutes les images complémentaires vont avoir le même attribut ALT. La meilleure solution et surtout la plus simple serait d'ajouter ces informations en base, je pense. Ca va part contre me faire beaucoup plus d'une page à modifier. Et étant donné que les illustrations ne sont pas présentes dans tous les articles, loin de là, et qu'ensuite c'est pas toujours que j'aurai à préciser un texte différent que celui que j'utilise en automatique, un systeme avec un balisage dans l'article serait peut-être plus adapté. Mais bonjour la complexité pour extraire ces informations d'une balise. Je gère déjà séparément les 5 variantes pour les 4 images. Si mes balises se transforment en "<IMAGE2FL alt="blabla" legende="une legende pour l'image"> c'est déjà du code et je perd l'avantage de la simplicité. Je ne peux pas proposer cela à un client alors que pour positionner les illustrations il dispose de 5 boutons qui vont insérer en javascript la balise <IMAGE2FL> (par exemple), il suffit juste de changer le numéro de l'image pour que ça s'applique à l'image que l'on veut. Difficile de faire plus simple.
 

Leonick

WRInaute accro
si dans l'insert de tes images en bdd, tu permets au client d'ajouter une description et un titre à chacune de ses images (et je sais que c'est hyper dur à faire comprendre aux clients), ensuite, il tu suffiras de reprendre ces données dans ta bdd pour ajouter automatiquement alt et title
 

indigene

WRInaute accro
Oui, bien sur, c'est la solution la plus propre et la plus simple mais elle présente deux gros défauts :
- ça me fait modifier la base et tous les formulaires de saisie/modification d'article en plus des pages d'affichage
- ça ne sera utilisé que dans moins de 5% des cas

Je préfère de loin une solution de style BBCODE comme je l'utilise pour le positionnement des images ou pour les mises en forme simples (gras, italique, etc...). Même les liens sont insérés en cliquant juste sur un bouton après avoir sélectionné le texte et une pop-up s'ouvre et invite à la saisie d'une url. C'est même encore plus simple que ce forum car ici si on clique sur URL on ne sait pas trop comment ajouter le lien.
Je pourrais donc utiliser la même technique et afficher une pop-up pour faire saisir une balise alt ou une autre pour la légende (ou une seule qui servirait à la fois de balise alt et de légende affichée en dessous de l'image). Mais comment coder cela dans le corps de la page, sous forme de balise, pour ensuite l'interpréter et le convertir correctement ? Avec une expression régulière je pense que je pourrais m'en sortir pour récupérer le ALT avant d'insérer l'image. La structure de mes balises serait de la forme :
<IMAGEn??><ALT=blablabla><LEGENDE=edefdefsrf>
Mais ça ne va pas être un peu trop lourd d'appliquer toutes ces expressions régulières avant de pouvoir afficher mon contenu ? Et rien ne garantie que les balises ALT et LEGENDE seront insérées au bon endroit, c'est à dire juste après la fermeture de la balise IMAGEn??. Ca serait peut être plus sage de placer les balises avant la balise IMAGEn?? comme ceci j'aurai déjà récupéré les informations en variables avant de coder la balise image.

Je réfléchis en live mais si quelqu'un a déjà rencontré ce cas il pourrait expliquer quelle solution il a retenu.

L'avantage du BBCODE c'est qu'une fois les balises insérées on peut ensuite les modifier dans l'édition du texte sans aller chercher une autre zone de formulaire. C'est donc plus fluide à la relecture car elles se trouvent proche de la balise image. Et bien entendu elles sont facultatives.
 

Marie-Aude

WRInaute accro
Bah tu regardes comment fonctionne WordPress avec le shortcode [caption] qui fait exactement tout ça, avec en plus des beaux boutons d'insertion ^^
 

zeb

WRInaute accro
Perso mon contenu (zone complète texte, image et que sais je) je le gère avec ça : http://www.tinymce.com/tryit/full.php
Léger rapide propre pas casse cOuille rien a coder ... facilement paramétrable
Même pas besoins de changer les formulaire les <textarea> sont automatiquement converties en éditeur WYSIWYG.

Tes histoire d'images centrées qui se centrent mal car il y a une image float très haute etc ... se résolvent avec une balise <div style="clear:both;"></div> juste avant l'image qui doit occuper tout l'espace. Ça provoque la rupture de la gestion flottante pour se placer en dessous. Après que tu l'introduise avec du BBCode ou autre chose c'est kif ...

Avant (en V1,V2 de mon CMS) j'utilisais aussi le BBcode mais pt1 que c'est chiant dès que tu veux faire des trucs en plus faut modifier les parseurs, et les filtres de mise en forme bref autant stocker directement du html ... plus simple ...
Il dois juste me rester une classe "historique" dans le code qui permet de gérer des vieux contenu qui sont encore a ce format obsolète.
 

indigene

WRInaute accro
spout a dit:
+1 M-A, surtout l'idée d'un shortcode/bbcode au lieu d'un tag XML like.

Tu as raison, ça évite les erreurs de validation html

Finalement voici le code que j'ai pondu, ce n'est pas du grand art mais ça fonctionne.
L'idée, c'est que comme les balises [IMAGEnxx] peuvent être codées à la main dans l'article, je commence par ajouter à toutes ces balises les balises [ALT=""] et [LEGENDE=""] quand elles sont manquantes.
Ensuite je fais un preg_match_all pour mettre toutes les balises en tableau que je n'ai plus qu'à explorer dans l'ordre pour faire les remplacements.
Pour les remplacement je compte le nombre de DIV float ouvertes afin de commencer par les refermer et de faire un clear:both avant d'effectuer le remplacement de la balise suivante (qui elle-même peut ouvrir une nouvelle DIV, pour cela que c'est un compteur).

Code:
    // mise en forme des attributs ALT et LEGENDE
    // ------------------------------------------
    // ajout de la balise alt manquante
    $contenu = preg_replace ('`\[IMAGE([1-4])(.)(.)\](?!\[ALT=\")`', '[IMAGE$1$2$3][ALT=""]', $contenu);
    $contenu = preg_replace ('`\[IMAGE([1-4])(.)\](?!\[ALT=\")`', '[IMAGE$1$2][ALT=""]', $contenu);
    $contenu = preg_replace ('`\[IMAGE([1-4])\](?!\[ALT=\")`', '[IMAGE$1][ALT=""]', $contenu);
    // ajout de la balise legende manquante
    $contenu = preg_replace ('`\[IMAGE([1-4])(.)(.)\]\[ALT=\"(.*?)\"\](?!\[LEGENDE=\")`', '[IMAGE$1$2$3][ALT="$4"][LEGENDE=""]', $contenu);
    $contenu = preg_replace ('`\[IMAGE([1-4])(.)\]\[ALT=\"(.*?)\"\](?!\[LEGENDE=\")`', '[IMAGE$1$2][ALT="$3"][LEGENDE=""]', $contenu);
    $contenu = preg_replace ('`\[IMAGE([1-4])\]\[ALT=\"(.*?)\"\](?!\[LEGENDE=\")`', '[IMAGE$1][ALT="$2"][LEGENDE=""]', $contenu);
    $contenu = preg_replace ('`\[IMAGE([1-4])(.*?)\]\[ALT=\"(.*?)\"\]\[LEGENDE=\"(.*?)\"\]\[LEGENDE=\""\]`', '[IMAGE$1$2][ALT="$3"][LEGENDE="$4"]', $contenu);
    // mise en tableau
    preg_match_all ('`\[IMAGE([1-4])(.*?)\]\[ALT=\"(.*?)\"\]\[LEGENDE=\"(.*?)\"\]`', $contenu, $out2 );

    $numberremp = 0;  // indique le nombre de DIV ouvertes qu'il faut refermer
    
//1° remplacement
    $alt0 = ' alt="illustration '.stripslashes($prod['nom']).'"';
    $alt = $alt0;
    if  ($out2[3][0] != "") {
           $alt = ' alt="'.$out2[3][0].'"';
    }
    $legende = $out2[4][0];  
    getremplace ();
    $stop = count($out2[0]); 
    if ($stop > 1) {
       for ( $i = 1; $i < $stop; $i++ ) {

             //si on a fait un remplacement on regarde s'il en existe d'autres pour refermer la DIV
            if ($numberremp > 0) {      
               $alt = $alt0;
               if  ($out2[3][$i] != "") {
                   $alt = ' alt="'.$out2[3][$i].'"';
               }
               $legende = $out2[4][$i];
               getremplace ();      // on le fait avant de faire -1 car il faut aussi faire un clear:both
               $numberremp = $numberremp - 1;   
            }
//remplacement suivant 
            else  {
               $alt = $alt0;
               if  ($out2[3][$i] != "") {
                   $alt = ' alt="'.$out2[3][$i].'"';
               }
            $legende = $out2[4][$i];
            getremplace ();
            }
       } 
    }
//si on a encore une div non fermée on la ferme à la fin du contenu et on ajoute un clear:both
    if ($numberremp > 0) { 
       $contenu = $contenu.'</DIV><DIV style="clear:both; ">&nbsp;</DIV>';
    }

// nettoyage des anciennes balises du contenu
    $contenu = preg_replace ('`\[ALT=\"(.*?)\"\]\[LEGENDE=\"(.*?)\"\]`', '', $contenu);

et dans la fonction getremplace () j'ai codé les mises en forme pour tous les cas de figure.
Les variables alt et legende sont récupérées du tableau que j'ai constitué plus haut

Code:
      // fonction de remplacement de la prochaine balise <IMAGE
function getremplace() {
 global $contenu;
 global $numberremp;
 global $image1;
 global $image2;
 global $image3;
 global $image4;
 global $legende;
 global $alt;
    if ($contenu == "") return false;
    $rechbalise = "[IMAGE";   
    $posbalise = strpos($contenu, $rechbalise);   
    if ($posbalise === false) return false;   
    $rechbalise = substr ($contenu, $posbalise, 10); 

    if ($rechbalise == "[IMAGE1FL]") {
       if ($numberremp == 0) {
           if ($legende == "") {
              $chaineremplacement = '<DIV style="float:left; margin-right:15px; margin-top:5px; margin-botom:5px;"><img src='.$image1.$alt.'></DIV><DIV>';
           }
           else {
              $chaineremplacement = '<DIV style="float:left; margin-right:15px; margin-top:5px; margin-botom:5px; font-size:9px; text-align:center;"><img src='.$image1.$alt.'><br>'.$legende.'</DIV><DIV>';
                }
           $contenu = substr_replace($contenu,$chaineremplacement,$posbalise,10);
           $numberremp = $numberremp + 1;
           return false;
           }
       else {
           if ($legende == "") {
              $chaineremplacement = '</DIV><DIV style="clear:both; float:left; margin-right:15px; margin-top:5px; margin-botom:5px;"><img src='.$image1.$alt.'></DIV><DIV>';
           }
           else {
              $chaineremplacement = '</DIV><DIV style="clear:both; float:left; margin-right:15px; margin-top:5px; margin-botom:5px; font-size:9px; text-align:center;"><img src='.$image1.$alt.'><br>'.$legende.'</DIV><DIV>';
                }
           $contenu = substr_replace($contenu,$chaineremplacement,$posbalise,10);
           $numberremp = $numberremp + 1;
           return false;
       } 
    }

    if ($rechbalise == "[IMAGE2FL]") {
       if ($numberremp == 0) {
etc....
....
....
....

Je pense qu'il y a beaucoup d'amélioration à apporter au niveau du code mais je vais en rester là.
Merci à tous les intervenants de m'avoir donné quelques pistes.
 

Discussions similaires

Haut