Overblog Suivre ce blog
Editer l'article Administration Créer mon blog
24 novembre 2009 2 24 /11 /novembre /2009 23:00

Voici donc la mise en pièces du programme addTopicTitle.js présenté dans "Ajouter un 'topicTitle' un peu partout". Lisez cet article (pas long !) si vous ne voyez pas de quoi il est question, ensuite revenez ici.

Le but du jeu

Dans une page de catégorie, telle que la fabrique OverBlog, le titre se présente ainsi dans le code source :

 <div class="articles" > <h2 class="topicTitle">JavaScript Mania</h2> <div> <div class="before_articles"> <div class="pagination center"> <!-- ensuite viennent la pagination, puis les articles--> 

Que voulons-nous accomplir ? Pour les pages d'archives et pour la liste complète des articles nous voulons, par du JS, fabriquer l'équivalent de ce qui est en gras puis le greffer à la bonne place dans ces pages. La bonne place en question est le tout début du module des articles. Voilà.

Premières questions, premières réponses

En développant la description précédente, il vient quatre étapes :

  1. déterminer la nature de la page : archive, liste complète ou autre,
  2. pour les archives et la liste complète : composer le texte du nouveau titre,
  3. trouver l'endroit où insérer ce texte,
  4. l'insérer.

Comment connaître le type d'une page ? À partir de son URL. Veine : c'est un travail que nous avons déjà fait pour "'Styler' les pages de blog selon leur URL" ! Le démontage correspondant contient une étude complète des URL OverBlog, je ne vais pas vous l'infliger à nouveau.

De plus l'URL d'une page d'archive nous renseigne sur la date de cette archive : nous pourrons en déduire le titre à donner à la page. Quant aux pages de liste des articles, nous nous contenterons d'un texte passe-partout.

Où insérer ce texte ? Juste au début du module des articles (voyez le bout de HTML ci-dessus). Le plus simple, pour trouver ce module par du JS, est de lui donner un identifiant.

Comment insérer ce texte ? On a déjà fait quelque chose dans ce goût-là pour dupliquer une pagination, on en a parlé dans le démontage associé.

Bref : ça se présente bien !

Voici donc la première version du programme :

 function addTopicTitle() { /* analyser l'url de la page */ /* construire le nouveau h2 */ /* trouver le div articles */ /* insérer le nouveau h2 */ } addTopicTitle(); /* déclenchement du traitement précédent */ 

Et même, en appliquant ce qui est dit dans  Démontage : détecter en CSS la présence de JavaScript , on peut condenser un peu :

 (function () { /* analyser l'url de la page */ /* construire le nouveau h2 */ /* trouver le div articles */ /* insérer le nouveau h2 */ })(); 

Ne reste plus qu'à remplacer chaque commentaire par des instructions JavaScript.

Analyser l'url

Confions ce travail à une nouvelle fonction (qui reste à écrire) :

 (function () { function buildTitle() { // analyse d'url et construction du titre } /* construire le nouveau h2 */ /* trouver le div articles */ /* insérer le nouveau h2 */ })(); 

Cette nouvelle fonction buildTitle se trouve à l'intérieur de celle en cours de rédaction. Ainsi buildTitle n'est connue que là (=ne risque pas d'être utilisée accidentellement par un autre programme) et, inversement, la fonction en cours de rédaction ne connaît que ce buildTitle (=ne risque pas d'utiliser une buildTitle qui serait définie ailleurs). On n'est jamais trop prudent.

Revenons à l'URL. Elle se trouve dans window.location.pathname. Ne nous intéresse que la fin de cette URL (après le dernier slash), ne nous intéresse même que ce qui précède le point de .html. Traduit en JavaScript, adapté du démontage de "'Styler' les pages de blog selon leur URL", ça nous donne :

 function buildTitle() { // analyse d'url et construction du titre var f = window.location.pathname.split('\/'); // récup d'url et découpe selon les slash f = f.pop(); // le dernier tronçon (gna-gna-gna.html) f = f.split('.')[0]; // découpe selon le ., récup de ce qui le précède (gna-gna-gna) } 

En condensant :

 function buildTitle() { // analyse d'url et construction du titre var f = window.location.pathname.split('\/').pop().split('.')[0]; } 

Précaution : l'accueil du blog ne comporte pas de nom explicite, il faut comprendre que c'est index :

 if (!f) f='index'; // cas de la page d'accueil du blog 

Préparation de la suite : la chaîne f est une suite de mots séparés par des tirets, décomposons-la :

 f = f.split('-'); // découpe selon les - 
f est désormais un tableau. On en récupère le premier mot puis l'élimine du tableau :
 var mot = f.shift(); // premier mot 

Ce premier mot est souvent la nature de la page (archive, categorie, index …) mais il peut aussi être un numéro de page (comme dans 1-index.html, 2-index.html, etc.). Dans ce cas il faut récupérer/éliminer le mot suivant :

 if (mot== 1*mot) mot=f.shift(); // si numéro de page, on l'élimine de f 

À ce stade, le code de buildTitle est :

 function buildTitle() { // analyse d'url et construction du titre var mot, f = window.location.pathname.split('\/').pop().split('.')[0]; if (!f) f='index'; // cas de la page d'accueil du blog f = f.split('-'); // découpe selon les - mot = f.shift(); // premier mot if (mot== 1*mot) mot=f.shift(); // si 1er mot est un numéro on passe au 2e /* fin de l'analyse d'url */ /* construction du titre */ } 
et mot contient la nature de la page. Reste à élaborer le texte du nouveau titre dans les deux seuls cas qui nous intéressent ici : mot=='articles' et mot=='archive'.

L'aiguillage entre ces deux cas se fera par une instruction switch plutôt que par des if multiples : plus clair, plus facile à maintenir. Le texte du titre sera stocké dans une nouvelle variable t (chaîne vide en dehors des deux cas utiles) que la fonction buildTitle renverra :

 var t; switch (mot) { case 'articles': /* calcul de t pour la liste complète */ break; case 'archive' : /* calcul de t pour une archive */ break; default : t=''; } return t; 

Détaillons les deux branches de l'aiguillage :

  • pour articles (= la liste complète) c'est simple, une phrase courte suffira (j'ai choisi "Tout le blog" mais peu importe) ;
  • pour archive c'est un peu plus complexe : l'URL peut être en mm-aaaa (mois-année, archive mensuelle) ou mm-jj-aaaa (mois-jour-année, archive d'un jour précis). Il faut donc reconnaître ces deux cas (deux mots ou trois ?), traduire le numéro de mois en un texte (c'est plus joli, non ?), insérer des espaces aux bons endroits.

Voilà la cuisine, les détails sont dans les commentaires :

 var t; switch (mot) { case 'articles': t="Tout le blog"; break; // liste complète : tjrs le même texte case 'archive' : // ici f= mm-aaaa ou bien mm-jj-aaaa var mois = // douze noms dans un tableau. L'indice va de 0 à 11 ['Janvier','Février','Mars','Avril','Mai','Juin' ,'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] // nombre de mots : 2 (mm-aaaa) ou 3 (mm-jj-aaaa) ,nbMots=f.length ; t=(nbMots == 3 ? f[1] + ' ' : '') // utilisation du jour, s'il est mentionné + mois[f[0]-1] // traduction du numéro de mois +' ' // espace intercalaire + f[nbMots-1]; // année break; // page autre qu'archive ou liste complète : pas de titre default : t=''; } 

Voici donc la fonction achevée :

 function buildTitle() { var t,mot,nbMots ,mois = ['Janvier','Février','Mars','Avril','Mai','Juin' ,'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] ,f = window.location.pathname.split('\/').pop().split('.')[0]; if (!f) f='index'; f = f.split('-'); mot = f.shift(); if (mot== 1*mot) mot=f.shift(); switch (mot) { case 'articles': t="Tout le blog"; break; case 'archive' : nbMots=f.length; t=(nbMots == 3 ? f[1] + ' ' : '') + mois[f[0]-1] + ' ' + f[nbMots-1]; break; default : t=''; } return t; } 

Elle renvoie une chaîne de caractères, chaîne vide s'il n'y a rien à faire. Nous venons d'écrire la plus grosse partie du programme, qui est aussi la moins intéressante.

Fabriquer le nouveau H2, le mettre en place

Ces deux traitements si difficiles en apparence sont si brefs que je les ai réunis en une seule fonction :

 function addH2(s,t) {//ajout d'un h2 de texte s juste au début de l'élément t /* traitements bien choisis*/ } 

Vous voulez créer un nouveau h2, comme si vous écriviez, en mode source :

 <h2></h2> 

Bon. En JavaScript vous le dites ainsi (sans chercher très loin j'ai baptisé la variable h2 mais vous mettez bien ce que vous voulez) :

 var h2=document.createElement('h2'); 

Ce h2 doit porter la classe topicTitle, comme si on écrivait ceci ?

 <h2 class="topicTitle"></h2> 

Bon, vous complétez le JavaScript :

 var h2=document.createElement('h2'); h2.className='topicTitle'; 

Il faut un certain texte à l'intérieur, comme si… ?

 <h2 class="topicTitle">texte contenu dans la chaîne s</h2> 

Rassemblant tout ceci, nous obtenons un bon morceau de addH2 :

 function addH2(s,t) { //ajout d'un h2 de texte s juste au début de l'élément t var h2=document.createElement('h2'); // création du h2 h2.className='topicTitle'; // ajout de la classe h2.innerHTML=s; // ajout du texte /* maintenant, il faut greffer h2 au bon endroit */ } 

À ce point le nouveau titre est prêt à l'emploi mais n'apparaît encore nulle part dans la page (ni donc à l'écran). Il faut le mettre en place au début de la série des  enfants  du div de classe articles, ici l'argument t de la fonction addH2.

Il n'y a que deux méthodes pour ce genre de greffe : appendChild permet d'ajouter un  enfant  à la fin de la liste et insertBefore de l'insérer avant un autre. Sachant que le premier  enfant  du div de référence t s'appelle t.firstChild, nous avons tout ce qu'il nous faut :

 t.insertBefore(h2,t.firstChild); 

La fonction addH2 complète, avec des tests de validité au début, s'écrit donc, pour finir :

 function addH2(s,t) { if(!s||!t) return; var h2=document.createElement('h2');h2.className='topicTitle';h2.innerHTML=s; t.insertBefore(h2,t.firstChild) } 

Trois lignes pour cinq instructions tout compris : c'est beau, non ?

Trouver le module des articles

Trouver quelque chose dans la page est une question si fréquente que j'y réponds dans cette fiche cuisine et les suivantes. Ici nous irons au plus simple en demandant que le module des articles porte un identifiant. Et d'où on le sort, cet identifiant ? On le passera en argument au programme, lequel en fera certainement bon usage. Tiens, nommons cet argument articles. Vous verrez ça bientôt.

Assemblage

Où en sommes-nous ? Nous avons écrit deux fonctions élémentaires, internes à addTopicTitle :

  • buildTitle fabrique le nouveau titre à partir de l'url, si l'url s'y prête ;
  • addH2 crée un h2 doté d'un certain texte et le greffe au début d'un certain élément, si le certain texte et le certain élément ne sont pas nuls.

Ne reste plus qu'à combiner tout ça :

 addH2(buildTitle(),document.getElementById(articles)); 

Manière élégante (oui, j'aime bien les compliments) de combiner les trois appels en une seule instruction.

Pour conclure : le programme définitif

Relisez bien tout, vous verrez que nous venons de fabriquer ceci :

 (function (articles) { function buildTitle() { var t,mot,nbMots ,mois = ['Janvier','Février','Mars','Avril','Mai','Juin' ,'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] ,f = window.location.pathname.split('\/').pop().split('.')[0]; if (!f) f='index'; f = f.split('-'); mot = f.shift(); if (mot== 1*mot) mot=f.shift(); switch (mot) { case 'articles': t="Tout le blog"; break; case 'archive' : nbMots=f.length; t=(nbMots == 3 ? f[1] + ' ' : '') + mois[f[0]-1] + ' ' + f[nbMots-1]; break; default : t=''; } return t; } function addH2(s,t) { if(!s||!t) return; var h2=document.createElement('h2');h2.className='topicTitle';h2.innerHTML=s; t.insertBefore(h2,t.firstChild) } addH2(buildTitle(),document.getElementById(articles)); })('lesArticles'); 

J'ai mis en gras la dernière nouveauté : l'emploi de l'argument articles. J'ai supposé, paresseusement, que l'identifiant du module des articles était lesArticles comme sur mon blog, il revient à l'utilisateur du programme de corriger cette valeur si besoin est.


Ce programme ne satisfait qu'un besoin bien mince, mais il illustre à merveille l'aptitude de JavaScript à remodeler une page. C'est aussi pour bien distinguer les différentes étapes du traitement que j'ai pris la peine de décomposer ce traitement en deux fonctions – ce n'était franchement pas indispensable en pure technique mais c'est plus clair.

La séquence  je crée un nouvel élément - je cherche son point d'insertion - je le greffe  sert à plusieurs endroits de ce blog : le lien qui ouvre les commentaires dans un popup, les liens de tirage aléatoire dans les bandeaux de pagination, les menus en haut à droite des articles… tous ces éléments ne figurent nulle part dans les pages que les fabrique OB.

Cette même séquence sert aussi bien à déplacer un élément dans la page :  je crée un nouvel élément  (avec document.createElement) est simplement remplacé par  je repère l'élément à déplacer  (avec document.getElementById ou tout autre moyen). C'est ainsi qu'on retrouve le module  abonnement à la newsletter  au milieu d'un autre module de texte libre ( Abonnements & autres ).

Moi, je trouve tout ça plutôt amusant…


À toutes fins utiles : quelques bonnes adresses pour en savoir plus sur JavaScript.

par Aïe mes doigts ! - dans JavaScript Mania
commenter cet article

commentaires

Archives