Overblog
Suivre ce blog Administration + Créer mon blog
26 mars 2007 1 26 /03 /mars /2007 03:07
(article revu en août 2008 : simplification de la technique employée et correction du lien vers PêUR)

L'idée originale vient de cet article de PêUR, avec quelques perfectionnements mineurs dans le présent article et dans le suivant.

Rien de très difficile et, s'il ne s'agissait que de livrer la recette, vous ne liriez qu'un plagiat. Seulement mon intention n'est pas de fournir un poisson mais d'apprendre à pêcher : on va faire comme si on inventait la solution nous-mêmes au lieu de la repiquer toute prête, et je m'efforcerai d'expliquer tous les choix techniques au passage. Plus long mais plus instructif, je trouve.

Mais si décidément JavaScript vous effraie trop voici aussi une solution en pur CSS, plus limitée mais bien plus simple, qui vous suffira peut-être.

Notes :

  • PêUR ayant eu la grande gentillesse de signaler cet article, vous êtes assez nombreux à le lire ces derniers temps. Votre avis m'intéresse, vous savez ? Est-ce utile ? clair ? trop long ? trop fouillé ? pas assez (hum…) ? Mêmes questions d'ailleurs pour chaque papier technique : utile ? instructif ? rasoir ? Dites-moi, je suis preneur !
  • Cette technique n'est pas réservée aux blogs OverBlog.
  • Chez OverBlog, elle est utilisable dès le niveau  Confiance .
  • Vous pouvez bien sûr faire un copier-coller bestial du code, en négligeant les explications. Mais j'aime bien comprendre ce que je fais, pas vous ? Faites-moi donc plaisir : revenez lire le topo à tête reposée quand vous aurez victorieusement greffé le gadget chez vous.

Préambule : HTML, CSS, JavaScript en quelques mots

Du simple au compliqué.

Une page HTML, c'est d'abord du texte. Preuve : créez avec le bloc-notes un fichier de texte tout simple (ni balises ni rien de spécial), ouvrez-le avec le navigateur : ça marche. Certes c'est vilain, brut de décoffrage, mais ça marche.

Le langage HTML permet d'organiser ce texte en blocs : paragraphes ou listes ou autres. Il permet d'y ajouter des titres, des références à des images (pas les images elles-mêmes) ou à d'autres pages HTML (pas ces pages elles-mêmes), tout ceci par l'emploi de balises. Un progrès : c'est organisé. Mais ça reste brut d'aspect.

Le langage CSS permet de préciser la présentation de ce texte organisé : polices de caractères, couleurs, disposition, etc. Nouveau progrès : c'est organisé et, en plus, (on espère que) c'est joli à regarder.

Analogie avec le papier : HTML c'est la rédaction (machine à écrire), CSS la mise en page (colle et ciseaux). Mais le résultat reste essentiellement statique, à part les effets obtenus au survol de certains éléments (pseudo-classe :hover) : HTML et CSS sont des langages de présentation, pas de programmation – ce qui n'est nullement une tare.

Animer ce paysage demande d'autres outils, leur catalogue est épais. Les uns agissent sur le serveur mais ils ne sont pas disponibles au niveau  Confiance , donc nous ferons l'impasse dessus. Les autres agissent sur le client (=votre navigateur). Le plus utilisé de ces langages  à faire bouger le navigateur  s'appelle JavaScript – nous y voilà.

Maintenant, on va penser…

Résultat

Voilà donc le bébé, à ne pas recopier en l'état :

 <p>Début de l'article</p> <a href="#escamotable" onclick=" /* Petit gestionnaire d'événements. Vous êtes en train de lire un commentaire JavaScript à la syntaxe furieusement proche de celle du CSS. */ document.getElementById('nom_unique').style.display= ''; /* redonne au div son display 'normal' */ return false; // (ceci est un commentaire en fin de ligne) ">Lire la suite…</a> <div id="nom_unique" style="display:none"> <p>Le texte à cacher</p> </div> 

Pourquoi ne faut-il pas le recopier ? Utilisateurs d'OverBlog, quand vous copiez/collez un Javascript tel que celui-ci, SUPPRIMEZ LES COMMENTAIRES DE FIN DE LIGNE, ceux précédés par //. Pourquoi ? L'éditeur d'articles peut supprimer les caractères de fin de ligne… du coup, le premier commentaire  de fin de ligne  (ici écrit après return false;) se trouve indûment étendu jusqu'à la fin du programme, ce qui n'est pas bon du tout ! Voici donc le bébé définitif, copiable en toute sécurité :

 <p>Début de l'article</p> <a href="#nom_unique" onclick=" document.getElementById('nom_unique').style.display= ''; return false;">Lire la suite…</a> <div id="nom_unique" style="display:none"> <p>Le texte à cacher</p> </div> 

Attention encore ! Pensez à remplacer  nom_unique  par quelque chose de vraiment unique dans tout votre blog ! Par exemple en combinant le titre de l'article et un mot désignant la section escamotable de l'article. Exemple ici-même : le corps (escamotable) de l'article s'appelle fairelirelasuite et la  dissection  qui arrive maintenant (escamotable dans l'escamotable) s'appelle lirelasuite_dissection.

Peut-être vous demandez-vous pourquoi l'identifiant doit être unique dans tout le blog ? Bonne question, puisqu'il suffit qu'il soit unique dans la page. Bien sûr (non ?) vous penserez à éviter les identifiants déjà employés par OB, tels que top ou global, donc on pourrait se contenter d'utiliser systématiquementsuite, par exemple. Mais si vous mettez plusieurs sections escamotables dans le même article vous serez mal. D'accord, donc avec suite1, suite2… on s'en sort, non ? Pas sûr : vous avez peut-être configuré votre blog pour afficher plusieurs articles par page, ou vous le ferez un jour. Si deux articles dotés d'un escamotable se retrouvent sur la même page, vous serez mal de nouveau. Donc : unique dans tout le blog, ce n'est pas si difficile et beaucoup plus sûr.


Dissection de la bête

Le gestionnaire onclick est un attribut du lien, tout comme href ou title, et il est syntaxé de la même manière : sa valeur (=le code JS) s'écrit entre guillemets (doubles) après le signe   =   .

Chaque instruction se termine par un point-virgule, même la dernière (restons prudents). Ici, présentation un peu soignée avec marge et retours à la ligne, mais rien n'interdit de tout écrire sur une seule ligne : notre gestionnaire ne comporte, après tout, que deux instructions…

La première est de la forme un_truc = 'chaine_de_caracteres' ; . Les apostrophes simples signalent une constante de type  chaîne de caractères , c'est assez classique en programmation (ici la chaîne est vide, explication bientôt). À gauche du signe  égale , les choses sont plus intéressantes : on indique l'entité (en jargon, l' objet ) à laquelle on affecte cette valeur, et cette entité porte un nom à rallonges. Ici il y a trois rallonges, séparées par des points. De gauche à droite on va du plus large au plus spécifique. Examinons l'assemblage, dans cet ordre :

document
désigne le document HTML chargé dans le navigateur.
Comme beaucoup de ce qu'on manipule en JavaScript se rattache peu ou prou au document, vous comprenez que ce mot figurera très souvent dans un programme JavaScript.
document.getElementById
est une  méthode  du document.
Ce qui veut dire ? En gros, une fonction (une série d'instructions) attachée au document, une manière de cuisiner des données.
Il existe tout un troupeau de telles méthodes, rédigées par les auteurs du navigateur. Tout l'art du programmeur JavaScript consiste à trouver la bonne documentation de référence, et ce n'est pas toujours simple. Laissez la question de côté pour aujourd'hui, faites-moi confiance et continuons.

Le nom de la méthode s'écrit en minuscules. Il se compose ici de quatre mots ("get" "element" "by" "id", mais sans espaces intercalés), le début de chaque mot est marqué par une majuscule sauf le premier. Pas de tiret haut ou bas pour séparer les mots. Ceci n'est pas une norme officielle, juste une convention acceptée par tout le monde ; autant la connaître et la respecter.
Elle fait quoi, cette méthode ? Elle va, dans le document, chercher (get) le morceau de HTML (Element) porteur de l'identifiant (ById) indiqué juste après, entre parenthèses (ce qui est entre les parenthèses s'appelle un  argument  de la méthode). Rappelez-vous : un identifiant est unique dans une page, donc il existe au plus un élément portant ce nom – on accepte l'échec mais pas l'ambigüité.
Quand la méthode a trouvé l'élément, elle en fait quoi ? Elle met à disposition du programme une référence à cet élément, autrement dit un zigouigoui, à usage interne, indiquant à quel endroit de mémoire se trouvent les informations relatives à l'élément (on peut aussi dire  un pointeur , mais c'est devenu un gros mot qui trahit le vieux programmeur démodé). On pourrait le stocker (le zigouigoui, pas le programmeur) dans un coin (= dans une variable) si on devait s'en resservir, mais ce n'est pas le cas ici. Enfin, la méthode getElementById, contrairement à d'autres, ne change rien ni à l'élément ni au document.

document.getElementById('nom_unique')
écrire le nom de la méthode avec des arguments en provoque l'exécution.
Donc  Médor rapporte le nonosse  et voilà : tout comme  document  désignait le document,  document.getElementById('nom_unique')  désigne l'élément nommé  nom_unique .
Cet élément, à son tour, peut porter d'autres méthodes. Il peut porter aussi des informations toutes simples (on parle d'  attributs ) telles que son texte, sa couleur, sa position… encore un troupeau, encore une question de trouver la bonne doc. Continuez à me faire confiance et avançons.
document.getElementById('nom_unique').style
ceci désigne les informations de style attachées à l'élément dans le HTML, c'est à dire par un attribut style="propriété:valeur" s'il y en a un (style  local ).
Ceci ne tient donc aucun compte du style indiqué dans le CSS. Le style effectif de l'élément ( computed style ), celui qui résulte du CSS et de l'éventuel style local, est plus compliqué à obtenir en JavaScript – et hors sujet pour aujourd'hui (ouf !).
document.getElementById('nom_unique').style.display
ceci désigne la propriété display du style local
document.getElementById('nom_unique').style.display = '';
ceci remet la propriété display du style local à  rien  : l'élément revient au display résultant du CSS, quel que soit ce display.

Maintenant, la deuxième et dernière instruction return false;. Le mot return indique qu'on renvoie des informations au navigateur, et ce qu'en fera le navigateur dépend du contexte. Ici, nous sommes dans un lien <a> et cette valeur renvoyée sert à décider de suivre ou non le href du lien. true on le suit, false on ne le suit pas, c'est tout bête.

Déroulement du film

Concrètement, comment tout cela marche-t-il ?

  1. le navigateur charge la page. Pour mettre le div en forme, il suit les indications du CSS et celles du style local éventuel. Le display du div est donc none et le div est caché. Le lien, lui, apparaît comme un brave lien dont rien ne signale qu'il transporte une machine infernale. Bien sûr, on suppose pour la suite que le navigateur accepte de traiter le JavaScript sinon c'est pas drôle.
  2. Tant que l'utilisateur ne fait rien, il ne se passe rien…
  3. … mais SI l'utilisateur clique sur le lien (voilà un événement), le navigateur, voyant le gestionnaire onclick, en commence l'exécution…
  4. … trouve, par la méthode getElementById, les coordonnées du div nommé 'nom_unique'…
  5. … change le style local de ce div et en tire aussitôt les conséquences : le div apparaît. Première instruction terminée.
  6. Deuxième instruction : ne pas suivre le href en sortant. Bon, on ne le suivra pas.
  7. C'est donc fini

Premier perfectionnement

Cliquer sur le lien ne fait qu'une seule chose : révéler le div caché.

Mais le lien continuera de se voir, c'est un peu déroutant. On pourrait vouloir qu'un deuxième clic cache de nouveau le div, que le texte du lien s'adapte aux circonstances, que sais-je encore ? C'est possible mais moins simple, on en reparlera dans le prochain article. Pour aujourd'hui on se contentera de faire disparaître le lien.

Le principe est le même : changer le style local du lien comme on change celui du div. Et soulève donc la même question : comment obtenir la référence du lien ?

On pourrait lui donner la même réponse : donner un identifiant (unique dans tout le blog !) au lien, et vogue la galère du document.getElementById('id_du_lien').style.display='none';

Mais là on peut faire plus simple, parce qu'il s'agit d'intervenir sur l'élément cliqué plutôt qu'ailleurs dans la page. Un raccourci permet d'accéder à cet élément sans l'encombrer d'un identifiant, ce raccourci est le mot this.

En clair, le onclick grossit d'une ligne :

 <p>Début de l'article</p> <a href="#nom_unique" onclick=" document.getElementById('nom_unique').style.display= ''; this.style.display= 'none'; return false;">Lire la suite…</a> <div id="nom_unique" style="display:none"> <p>Le texte à cacher</p> </div> 

Quand on explique c'est plus clair, non ?

Comparaison avec la solution de PêUR

PêUR fait figurer l'identifiant du div dans le CSS et pas moi : dans le principe, déjà, ça m'ennuyait de mentionner dans le CSS (à vocation générale) le traitement d'un article particulier. De plus, tout se complique si, ayant plusieurs articles par page, on veut appliquer la technique à plus d'un article : plus question d'employer un identifiant à tout faire !

PêUR propose d'utiliser alors #cache1, #cache2, etc. et de compléter le CSS en conséquence. Je crains tout de même qu'au fil de la vie du blog (suppression d'articles, changement de catégorie ou de date…) deux articles utilisant le même id ne se retrouvent dans la même page. Pour l'éviter, on peut utiliser un id spécifique à chaque section escamotable de chaque article, ce que je fais d'ailleurs : #fairelirelasuite, #ordremethode5, etc. Mais le CSS deviendrait alors interminable et jamais à jour, d'où le recours à une pure intervention sur le style local.

Autre gain accessoire : puisqu'il n'y aura plus à s'inquiéter du CSS, rien n'empêchera de mettre plusieurs  lire la suite  successifs ou imbriqués dans un même article très long. Ça peut rendre service, voyez donc la  dissection  qui précède !


Pas trop souffert ? Cet article est (nettement) plus long que celui de PêUR, pour une solution à peine retouchée. C'est parce que cette manip', très simple en soi, a servi de prétexte à exposer pas mal de choses, tout le  comment  et le  pourquoi , et j'ai du mal à rester bref en ces matières.

Le prochain article, bientôt, présentera quelques variations autour de ce thème – et il sera plus court !


Archives