Scripts en JavaScript


Le pas de base de la java est très simple (je la soupçonne d’être une imitation populaire de la valse) : il suffit de piétiner sur place en se déhanchant. Le danseur commence avec le pied gauche, la danseuse avec le pied droit. On danse sur 6 temps, le premier et le quatrième sont accentués par l’accordéon. Rien ne vous empêche de partir en valse si vous avez la place. Vous l’avez compris, il faut interagir avec votre partenaire.

Nous allons directement partir sur un cas pratique en poursuivant la construction du mini quiz que nous avons commencé dans Blocs HTML et Classes CSS.

Nous réutiliserons les 3 questions du quiz et leurs réponses : en informatique on fait beaucoup de récupération. Vous pouvez dupliquer le code et les structures mais pas les contenus : les moteurs de recherche ont horreur des infos dupliquées, ils vous condamneront à l’oubli pour cela.

Le cahier des charges

  1. Donner à l’internaute la possibilité d’indiquer s’il a trouvé la bonne réponse (boîte à cocher)
    • C’est plus simple à réaliser
    • Ca reste dans l’esprit du site : l’internaute doit consulter les réponses et estimer s’il a bien répondu (on lui laisse la possibilité de tricher au cas où, contrairement à Socrate, il ne saurait pas qu’il ne sait rien)
  2. Mettre à disposition de l’internaute un bouton permettant de :
    • Compter et afficher le nombre de bonnes réponses (les cases cochées du point n° 1)
    • Et de calculer son score (pourcentage de bonnes réponses
    • Et, en fonction de son score, afficher le profil de l’internaute (prévoir 3 profils)
  3. Mettre à disposition de l’internaute un bouton :
    • Qui efface toutes les réponses saisie, y compris les cases à cocher du point n° 1
    • Qui efface le résultat affiché par le bouton du point n° 2
    • Qui referme toutes les réponses consultées non refermées
    • Qui repositionne l’écran au début du Quiz.

J’ai récupéré ci-dessous la 1ère question et sa réponse :

Cochez si c’est un fruit :

Le grain de blé

La fraise

Le trognon de pomme

Consultez la réponse

Il fallait tout cocher sauf la fraise :

  • Le grain de blé est un fruit particulier
  • La fraise est un faux fruit car elle naît du gonflement du réceptacle floral après fécondation. Les vrais fruits du fraisier sont les akènes, ces minuscules graines disséminées sur toute la robe rouge de la fraise. La fraise, c’est donc plus que plusieurs fruits !
  • La pomme que vous mangez n’est pas un fruit. Le vrai fruit est le trognon de pomme : après fécondation, la graine reste à l’intérieur des « carpelles » (le vrai fruit) et vous mangez la base de la fleur (ou réceptacle floral) qui grossit.

Structure d’une question du quiz avec réponses de type boîtes à cocher :

Ajouter la boîte pour cocher les bonnes réponses

L’objectif est de compléter tout ça avec une case à cocher pour répondre au point n° 1 du cahier des charges :

  • Comme je suis une grosse feignasse, je vais :
    1. Copier l’une des rangées du quiz
    2. Inverser l’ordre des éléments de la rangée
    3. Modifier le contenu du paragraphe et lui donner une apparence propre à attirer l’attention de l’internaute pour ne pas qu’il loupe cette étape

Résultats dans l’ordre :

Le grain de blé

Le grain de blé

Après sélectionner Paragraphe /Réglages /Arrière-plan /Dégradé :

Si vous avez bien répondu, cochez :

Il ne reste plus qu’à positionner ce bloc Rangée après le bloc Détails Consultez la réponse, de chacune des 3 questions, pour avoir un Quiz digne de ce nom :

LE QUIZ DU SIECLE

Cochez si c’est un fruit :

Le grain de blé

La fraise

Le trognon de pomme

Consultez la réponse

Il fallait tout cocher sauf la fraise :

  • Le grain de blé est un fruit particulier
  • La fraise est un faux fruit car elle naît du gonflement du réceptacle floral après fécondation. Les vrais fruits du fraisier sont les akènes, ces minuscules graines disséminées sur toute la robe rouge de la fraise. La fraise, c’est donc plus que plusieurs fruits !
  • La pomme que vous mangez n’est pas un fruit. Le vrai fruit est le trognon de pomme : après fécondation, la graine reste à l’intérieur des « carpelles » (le vrai fruit) et vous mangez la base de la fleur (ou réceptacle floral) qui grossit.

Si vous avez bien répondu, cochez :

HTTP est :

Un langage

Un protocole

Un serveur

Consultez la réponse

Un protocole.

Si vous avez bien répondu, cochez :

Un serveur est

Consultez la réponse

Réponse 5 : Un gros ordinateur qui héberge une ou plusieurs applications qui répondent à des internautes.

Si vous avez bien répondu, cochez :


Le quiz est terminé : comptabilisez vos bonnes réponses avec le bouton ci-dessous puis consultez votre frofil qui vient de s’afficher.

Il faut positionner le bouton ici !

Et afficher le profil ici !

N.B. : il vous faudra revenir à ce quiz pour tester le bon fonctionnement des boutons.

Compter les bonnes réponses

Le point n° 2 du cahier des charges va nécessiter un déhanché plus vigoureux. En particulier la mise en place du bouton qui va permettre de compter et afficher le nombre de bonnes réponses (le nombre de cases cochées parmi les 3 qu’on vient de rajouter).

Il faut que vous ayez conscience que vous ne faites plus du WP standard. Je vous emmène faire une virée sur les bords de la Marne dans les années 20 (il y a pile 100 ans ! )

Nous allons, sans utiliser les blocs WP, créer une structure HTML (composée d’un bouton et d’une zone pour afficher le résultat) à laquelle nous accoleront un script JS contenant la fonction qui se déclenchera quand on cliquera sur le bouton.

Voici la structure du code à inclure dans un bloc HTML Personnalisé à l’emplacement prévu pour le bouton (j’ai mis les commentaires en gras) :

<!-- Bouton "Comptabilisez vos bonnes réponses" -->

<!-- Attention, toutes les boîtes à cocher devant être comptées dans la page, doivent être définies ainsi en html : <input type="checkbox" name="bonnereponse"> -->

<div style="text-align: center;"> <!-- CSS pour centrer le bouton et le résultat du comptage-->

    <button onclick="count_chkBox();">Comptabilisez vos bonnes réponses</button>
    <br> <!-- saut de ligne -->
    <span id="spanresult"></span>
</div>
<script> //script JS
    function count_chkBox(){
        /* pour le moment, la fonction ne fait rien à part afficher un message pour vérifier qu'elle est bien appelée par le bouton */
        alert("La fonction count_chkBox est bien appelée.");
    {
</script>

Résultat :


Commentaires :

  • Toutes les boîtes à cocher devant être comptées dans la page, doivent être définies ainsi en html : <input type="checkbox" name="bonnereponse">
    • En effet <input type="checkbox"> n’est pas suffisant : il faut donner à toutes le même nom (name) pour que la fonction qui comptera ne les confonde pas avec les checkbox utilisées par certaines questions du quiz (en l’occurrence la première question)
    • Remarque : un bouton radio n’aurait pas pu être utilisé à la place d’une boîte à cocher car si plusieurs boutons radio ont le même nom alors un seul de ces boutons peut être coché.
  • <span> </span> est une balise HTML pour une ligne de texte
    • J’aurai pu utiliser <p> mais je voulais éviter les formatages du navigateur
    • J’ai donné un identifiant (id) à la balise <span> pour que la fonction puisse le repérer pour afficher le résultat
  • En JS, les commentaires peuvent être notés /* mon commentaire sur plusieurs lignes */ ou // mon commentaire en fin de ligne
  • alert(« La fonction count_chkBox est bien appelée. »);
    • Une fonction JS bien utile pour vérifier et débugger
    • En CSS, en JS et en PHP, toujours terminer une instruction par un point-virgule (même s’il n’y en a qu’une).

Pas de difficulté réelle jusqu’à présent : regardons à quoi va ressembler la fonction count_chkBox :

function count_chkBox(){
    /* variable locale (à la fonction) qui contient le résultat (au départ 0) : */
    let nbre_check = 0;

    /*tableau local qui récupère toutes les boîtes à contrôler : */
    let boites = document.getElementsByName("bonnereponse");

    /* constante contenant le nb de boîtes récupérées : */
    const nbquestions = boites.length; 

    /* Boucle parcourant le tableau contenant les boîtes à contrôler : */
    for (i=0; i<nbquestions; i++) {
         on 
        if (boites[i].checked){ // si la boite est cochée
         /* alors on incrémente d'une unité le résultat : */ 
            nbre_check ++ ;     contenant 
        }
    }
    /*
    //Une alternative à la boucle for :
    for (let boite of boites) {
        if (boite.checked) nbre_check ++ ;
    }
    */

    /* On affiche le résultat de façon informelle : */
    alert(nbre_check+" bonnes réponses sur "+nbquestions);
}

Résultat (j’ai ajouté ce code au précédent et j’ai ajouté name= »bonnereponse » dans les 3 checkbox) :


Commentaires :

  • let (anciennement var) : type de variable dont la valeur peut changer
    • Quand la valeur ne doit pas changer, on utilise le type const
  • let boites = document.getElementsByName ("bonnereponse");
    • On récupère (get) dans un tableau (let boites) les éléments (Elements) de la page (document) qui portent le nom (ByName) "bonnereponse"
    • Il existe en JS plusieurs fonctions de ce type permettant de récupérer les informations concernant une ou plusieurs balises et de modifier leurs attributs ou leurs contenus.
      • Dans le cas présent, on utilise une fonction qui se base sur le nom des éléments recherchées
      • boites.length donne la taille du tableau boites ainsi rempli (on a trouvé 3 boîtes portant le nom "bonnereponse"
  • La boucle for va tourner autant de fois qu'il y a de boîtes dans le tableau boîte (i=0; i<nbquestions;)
    • J'ai utilisé une boucle for car elle est connue de tous ceux qui on des bases de programmation
    • for (conditions) { traitement à chaque itération} :
      • à chaque itération, on regarde si (if) la boîte est cochée (checked)
      • pour passer de boîte en boîte, on se sert de la variable i de la boucle for : comme i est incrémenté d'une unité (i++) à chaque tour de boucle, ça permet de cibler successivement chaque boîte du tableau boîtes (au pluriel) ; en effet, on peut considérer chaque élément d'un tableau grâce à son indice (de 0 à taille du tableau moins 1) ; la 1ère boîte est donc boites[0], la 2e boites[1], la 3e boites[2]. En utilisant la variable i qui passe de 0 à 2 au fil des tours (i++), on adresse la boîte qui correspond au tour en cours avec boites[i] ! Astucieux n'est-ce pas ?
    • JS propose une syntaxe de boucle plus simple pour parcourir les valeurs des éléments d'un tableau :
      • for (let boite of boites) { if (boite.checked) {nbre_check ++ ;} }
      • Pour chaque boite du tableau boites, si boite est cochée alors nbre_check augmente de 1
      • Plus simple car on est sûr de parcourir toutes les valeurs contenues dans le tableau, du début à la fin, sans avoir à gérer de variable i.
  • alert(nbre_check+" bonnes réponses sur "+nbquestions);
    • Avant d'afficher le résultat sur la page, on vérifie au moyen de la fonction alert, les valeurs des variables mises à jour à la sortie de la boucle
    • Le symbole + permet de concaténer des chaînes de caractères (il suffit qu'il y ait une chaine de caractères pour que les contenus des variables soient convertis en chaines de caractères).

Afficher le score

Voyons justement comment afficher les résultats sur la page en avoutant ce code à la suite, à l'intérieur de la fonction count_chkBox :

        /*variable globale (pour donner accès au bouton RAZ) de la zone d'affichage du résultat : */
        spanresult = document.getElementById("spanresult");
        const s = (nbquestions > 1) ? "s" : ""; 
        let pourcentage = (100*( (nbre_check/nbquestions).toFixed(4))).toString();

        if(nbre_check == 0) {
            spanresult.textContent = "Aucune bonne réponse";
        }
        else if(nbre_check == 1) {
            spanresult.textContent = " 1 bonne réponse sur "+nbquestions+" question"+s+" soit "+ pourcentage +" %";
        }
        else if(nbre_check > 1) {
            spanresult.textContent = (nbre_check).toString() + " bonnes réponses sur " +nbquestions+" questions soit "+ pourcentage +" %";
        }

Résultat (j'ai ajouté ce code au précédent à l'intérieur de la fonction) :


Commentaires :

  • spanresult = document.getElementById ("spanresult");
    • "spanresult" est l'identifiant que j'adinné à ma balise <span> (pour afficher le résultat)
    • spanresult = : j'ai donné le même nom à ma variable chargé de récupérer les infos sur l'objet identifié (pas de danger que ça se mélange)
      • Je n'ai pas typé cette variable avec let ou const car je ne souhaite pas que sa portée soit limitée à la fonction count_chkBox : en ne la typant pas, je demande à ce que la variable spanresult soit globale, c'est à dire accessibles aux autres fonctions, notamment à la fonction qui sera chargée d'effacer le contenu de cette balise (point n° 3)
    • document.getElementById ("spanresult") : encore une fonction JS permettant de manipuler les balises de la page (document)
      • Remarquez qu'il n'y a pas de s à Element car je ne vais récupérer (get) qu'un seul objet : en effet, un Id est unique !
  • const s = (nbquestions > 1) ? "s" : "";
    • Cette instruction est l'équivalent de if(nbquestions > 1) s="s"; else s="";
      Mais en plus je peut déclarer ma constante en même temps (c'est la grosse frime)
    • Cette variable s va me permettre de gérer l'affichage du s de "questions" au cas où il n'y aurait qu'une seule question !
  • let pourcentage = 100*( (nbre_check/nbquestions).toFixed(4) );
    • je calcule le rapport bonnes réponses / nombre de questions
    • J'arrondis à 4 chiffres après la virgule avec nombre.toFixed(4)
    • Je multiplie le résultat par 100 pour convertir en pourcentages (j'aurai donc 2 chiffres après la virgule)
  • spanresult.textContent = "etc."
    • .textContent permet d'incérer du texte entre les balises d'affichage <span id="spanresult"> et </span> que je peux manipuler grâce à spanresult (ma variable qui porte le même nom mais que j'aurais pu appelée toto)
    • text content = contenu textuel
  • La structure if(condition) {faire} else if(condition) {faire} else if(condition) {faire} else(condition) {faire} est un grand classique
    • if = si et else = sinon
  • L'opérateur = sert à affecter une valeur dans une variable
    • let ma_variable = 3;
  • L'opérateur == sert à comparer deux valeurs (qu'elles soient concrètes ou contenues dans des variables)
    • if(ma_variable == 3) { alert("ma_variable vaut 3");}
      else {alert("ma_variable est différente de 3");}

Maintenant il reste à afficher le profil de l'internaute, en fonction de son pourcentage de bonnes réponses.

Afficher le profil de l'internaute

On va partir sur les 3 profils ci-dessous :

Consultez votre profil
Jusqu'à 25 % de bonnes réponses

Jeune passereau rêveur, vous parcourez les forêts natives à l'abri des vents forcenés qui balayent les côtes. Votre chant n'appartient qu'à vous. Que la chance vous accompagne.

De 26 % à 70 % bonnes réponses

Vous êtes un oiseau marcheur qui s'amuse des choses de ce monde avec plus ou moins d'honnêteté mais avec un intérêt qui ne demande qu'à grandir. Que votre joie demeure.

Plus de 70 % de bonnes réponses

Vous êtes un vautour de Rüppell au "cui cui" exceptionnel. Vous côtoyez les cimes, vous le savez bien. Attention aux jaloux et à l'altitude, ne prenez pas froid. Que la force soit avec vous.

La fonction doit ouvrir le bon détail en fonction du pourcentage de bonnes réponses obtenu :

  • On laissera accessibles les autres profils car ce quiz est ludique, la curiosité de l'internaute est sans borne et irrésistible le besoin de se comparer à son prochain (tout le monde n'a pas la sagesse d'un Socrate)
  • Mais les autres profils seront repliés.
  • On laissera accessibles les profils, même aux internautes qui ne font pas le quiz
  • On va attribuer des classes aux différents blocs Détails pour pouvoir les manipuler avec JS (on ne peut pas leur attribuer autre chose que des classes dans WP, alors on va faire avec) :

Voici les classes attribuées :

DétailLibellépourcentage1ère classe2e classe
Détail globalConsultez votre profilprofils
1er sous-détailJusqu'à 25 %<26profilprofil1
2e sous-détailDe 26 % à 70 %>25 et <71profilprofil2
3e sous-détailPlus de 70 % >70profilprofil3

Cela permettra de manipuler soit :

  • Le détail global avec la classe profils
  • Les 3 sous-détails à la fois avec la classe profil
  • Chaque sous-détails individuellement avec la classe numérotée

Avant de regarder le code essayons d'imaginer ce qu'il va falloir faire :

  1. Fermer les 3 sous-détails (classe profil)
    • En effet, l'internaute est peut-être allé fouiner avant de commencer le quiz
  2. Ouvrir le 1er sous-détails si pourcentage < 26 (classe profil1)
  3. Ouvrir le 2e sous-détails si pourcentage > 25 et pourcentage < 71 (classe profil2)
  4. Ouvrir le 3e sous-détails si pourcentage > 70 (classe profil3)
  5. Ouvrir le bloc Détails global (classe profils)

Nous allons voir qu'on peut simplifier les conditions grâce au jeux des sinon si.

Voyons le code à ajouter dans la fonction :

//AFFICHAGE DU PROFIL DE L'INTERNAUTE :

//Fermer les 3 sous-détails
let details = document.querySelectorAll('.profil');
for (let detail of details) {detail.open = false;};

//Ouvrir le 1er sous-détails si pourcentage < 26
if(pourcentage < 26) {
    let detail1 = document.querySelectorAll('.profil1');
    for (let detailbis of detail1) {detailbis.open = true;};
}
//Sinon, ouvrir le 2e sous-détails si pourcentage < 71 
else if(pourcentage < 71) {
    let detail2 = document.querySelectorAll('.profil2');
    for (let detailbis of detail2) {detailbis.open = true;};
}
//Sinon ouvrir le 3e sous-détails
else {
    let detail3 = document.querySelectorAll('.profil3');
    for (let detailbis of detail3) {detailbis.open = true;};
}

//Ouvrir le bloc Détails global 
let box = document.querySelectorAll('.profils');
for (let thebox of box) {thebox.open = true;};

Résultat :


Consultez votre profil [profils]
Jusqu'à 25 % de bonnes réponses [profil] [profil1]

Jeune passereau rêveur, vous parcourez les forêts natives à l'abri des vents forcenés qui balayent les côtes. Votre chant n'appartient qu'à vous. Que la chance vous accompagne.

De 26 % à 70 % bonnes réponses [profil] [profil2]

Vous êtes un oiseau marcheur qui s'amuse des choses de ce monde avec plus ou moins d'honnêteté mais avec un intérêt qui ne demande qu'à grandir. Que votre joie demeure.

Plus de 70 % de bonnes réponses [profil] [profil3]

Vous êtes un vautour de Rüppell au "cui cui" exceptionnel. Vous côtoyez les cimes, vous le savez bien. Attention aux jaloux et à l'altitude, ne prenez pas froid. Que la force soit avec vous.

Commentaires :

  • let details = document.querySelectorAll('.profil');
    • Encore une fonction magique de JS pour allez à la chasse aux balises (blocs)
    • Celle-ci permet de passer en paramètre un ciblage de type CSS : ici '.profil' n'est rien d'autre que la classe profil (le point devant respecte la syntaxe CSS pour cibler une classe)
    • Il faut savoir que les possibilités de ciblage de CSS sont très riches, nous n'avons qu'effleuré le sujet
    • Pour délimiter des chaînes de caractère, on peut utiliser indifféremment des quotes simples ou des doubles quotes
  • for (let detail of details) {detail.open = false;};
    • ou plus simple puisqu'une seule instruction :
      for (let detail of details) detail.open = false;
    • open (ouvert) est faux donc c'est fermé
  • else if(pourcentage < 71)
    • else if (sinon si) : on a donc éliminé le cas précédent (pourcentage < 26) donc la condition (pourcentage < 71) suffit pour statuer ; logique.

Voila pour ce premier bouton qui nous a donné un peu de fil à retordre. On a appris pas mal de choses. Ca sera d'autant plus facile pour le 2e bouton.

Réinitialiser le quiz

Le 2e bouton qui doit rappelons-le :

  • Réinitialiser toutes les cases à cocher, boutons radio, listes déroulantes
  • Effacer le score
  • Refermer tous les Détails
  • Repositionner l'écran au début du Quiz.

Voyons le code :

<!-- Bouton "Effacez toutes vos réponses" -->

<div style="text-align: center;">
    <button onclick="raz();">Réinitialiser le quiz</button>
</div>
<script>
    function raz(){

        //Repositionner toutes les listes déroulantes sur leurs 1ères valeurs :
        let selects = document.querySelectorAll('select');
        for (let select of selects) {select.selectedIndex = 0;}

        //Décocher tous les boutons radio :
        let radios = document.querySelectorAll('input[type=radio]');
        for (let radio of radios) {radio.checked = false;}

        //Décocher toutes les boîtes à cocher :
        let boxes = document.querySelectorAll('input[type=checkbox]');
        for (let box of boxes) {box.checked = false;};

        //Refermer tous les blocs Détails
        let details = document.querySelectorAll('details');
        for (let detail of details) {detail.open = false;};

        //Effacer le score mis à jour par la fonction count_chkBox dans la variable globale spanresult :
        spanresult.textContent = "";

        //Repositionner l'écran sur le bloc dont l'ancre est "quiz" (au début du quiz) :
        var quiz = document.getElementById("quiz");
        quiz.scrollIntoView();

    }
</script>

Résultat :

Il va sans dire que ces constructions à base de code peuvent être sauvegardées dans des compositions pour être réutilisées facilement (je me suis ainsi construit un template de quiz complet).

ANNEXES

Les codes complets des 2 boutons :
Score
<!-- Bouton "Comptabilisez vos bonnes réponses" -->

<!-- Attention, toutes les boîtes à cocher devant être comptées dans la page, doivent être définies ainsi en html : <input type="checkbox" name="bonnereponse"> -->

<div style="text-align: center;"> <!-- CSS pour centrer le bouton et le résultat du comptage-->

    <button onclick="count_chkBox();">Comptabilisez vos bonnes réponses</button>
    <br> <!-- saut de ligne -->
    <span id="spanresult"></span>
</div>
<script> //script JS
    function count_chkBox(){
        let nbre_check = 0;
        let boites = document.getElementsByName("bonnereponse");
        const nbquestions = boites.length;

        for (i=0; i<nbquestions; i++) {
            if (boites[i].checked) nbre_check ++ ;
        }
        //Alternative à la boucle for :
        //for (let boite of boites) if (boite.checked) nbre_check ++ ;
        
        // AFFICHAGE DU RESULTAT :
        /*variable globale (pour donner accès au bouton RAZ) de la zone d'affichage du résultat : */
        spanresult = document.getElementById("spanresult");
        const s = (nbquestions > 1) ? "s" : ""; 
        let pourcentage = 100*( (nbre_check/nbquestions).toFixed(4) );

        if(nbre_check == 0) {
            spanresult.textContent = "Aucune bonne réponse soit 0 %";
        }
        else if(nbre_check == 1) {
            spanresult.textContent = " 1 bonne réponse sur "+nbquestions+" question"+s+" soit "+ pourcentage +" %";
        }
        else { //nbre_check > 1
            spanresult.textContent = nbre_check + " bonnes réponses sur " +nbquestions+" questions soit "+ pourcentage +" %";
        }

        //AFFICHAGE DU PROFIL DE L'INTERNAUTE :

        //Fermer les 3 sous-détails
        let details = document.querySelectorAll('.profil');
        for (let detail of details) {detail.open = false;};

        //Ouvrir le 1er sous-détails si pourcentage < 26
        if(pourcentage < 26) {
            let detail1 = document.querySelectorAll('.profil1');
            for (let detailbis of detail1) {detailbis.open = true;};
        }
        //Sinon, ouvrir le 2e sous-détails si pourcentage < 71 
        else if(pourcentage < 71) {
            let detail2 = document.querySelectorAll('.profil2');
            for (let detailbis of detail2) {detailbis.open = true;};
        }
        //Sinon ouvrir le 3e sous-détails
        else {
            let detail3 = document.querySelectorAll('.profil3');
            for (let detailbis of detail3) {detailbis.open = true;};
        }

        //Ouvrir le bloc Détails global 
        let box = document.querySelectorAll('.profils');
        for (let thebox of box) {thebox.open = true;};

    }
</script>
RAZ
<!-- Bouton "Effacez toutes vos réponses" -->

<div style="text-align: center;">
    <button onclick="raz();">Réinitialiser le quiz</button>
</div>
<script>
    function raz(){

        //Repositionner toutes les listes déroulantes sur leurs 1ères valeurs :
        let selects = document.querySelectorAll('select');
        for (let select of selects) {select.selectedIndex = 0;}

        //Décocher tous les boutons radio :
        let radios = document.querySelectorAll('input[type=radio]');
        for (let radio of radios) {radio.checked = false;}

        //Décocher toutes les boîtes à cocher :
        let boxes = document.querySelectorAll('input[type=checkbox]');
        for (let box of boxes) {box.checked = false;}

        //Refermer tous les blocs Détails
        let details = document.querySelectorAll('details');
        for (let detail of details) {detail.open = false;}

        //Effacer le score mis à jour par la fonction count_chkBox dans la variable globale spanresult :
        spanresult.textContent = "";

        //Repositionner l'écran sur le bloc dont l'ancre est "quiz" (au début du quiz) :
        var quiz = document.getElementById("quiz");
        quiz.scrollIntoView();
        //quiz.focus();

    }
</script>

Bonus

BONUS n° 1

Bouton pour fermer un bloc Détail un peu long (ici, il ferme tous les blocs Dértail) :

<!-- Bouton "Effacez toutes vos réponses" -->
<div style="text-align: center;">
<button type="button" class="nice-button" onclick="raz();"><big><big>Fermer le mode d'emploi</big></big></button>
</div>
<script>
    function raz(){
        let details = document.querySelectorAll('details');
        for (let detail of details) { detail.open = false;};

        var debut = document.getElementById("debut");
        debut.scrollIntoView();
    }
</script>

CSS pour class="nice-button" :

.nice-button{
  width: auto;
  margin: auto;
  margin-top: 0.2em;

  color: white;
  background-color: #6495ED;
  text-shadow: 1px 1px black;

  text-decoration: none;
  text-align: center;
  padding: 2px;
  border: 3px outset #c0c0c0;
}

BONUS n° 2

Modèle Recherche : Efface le libellé "Catégorie :" quand il n'y a pas de catégorie fournie (cas des pages)

<script>
//Efface le libellé "Catégorie :" quand il n'y a pas de catégorie d'affichée (pages). Le libellé "Catégorie :" doit avoir la classe "libelle-categorie-recherche". Dans modèle Recherche.

let libellescategorie = document.getElementsByClassName("libelle-categorie-recherche");

for (let celibelle of libellescategorie) { 
    if (celibelle.parentNode.childNodes.length < 5) celibelle.style.display = "none";
}

</script>

BONUS n° 3

Effacer les liens de la page qui pointent vers la page elle-même, notamment dans les menus (modèle Pages) :

<script>
//Effacer les liens de la page qui pointent vers la page elle-même, notamment dans les menus (à mettre dans une composition, à la fin du modèle des pages) :

// Récupérer l'url de la page 
var urlcourante = document.location.href; 
// Supprimer l'éventuel dernier slash de l'URL
urlcourante = urlcourante.replace(/\/$/, "");
// Garder dans la variable queue_url, uniquement la portion derrière le dernier slash de urlcourante
var queue_url = urlcourante.substring (urlcourante.lastIndexOf( "/" )+1 );

// Récupérer tous les liens (balise <a>) dans un tableau
const liensPage = document.querySelectorAll("a");

if(liensPage.length > 0){
    var urlLien;
    var queue_urlLien
    for (let pas = 0; pas < liensPage.length; pas++) {
        //Si l'attribut "href" est pésent dans <a>
        if(liensPage[pas].hasAttribute("href")){
            urlLien = liensPage[pas].getAttribute("href");
            urlLien = urlLien.replace(/\/$/, "");
            queue_urlLien = urlLien.substring(urlLien.lastIndexOf("/") +1);

            // Si le slug de la page est égal au slug du lien
            if(queue_url == queue_urlLien){
                // Ne pas afficher le lien
                liensPage[pas].style.display = "none";
            }
        }
    }
} 
</script>

BONUS n° 4

Modèle Archive (catégorie) : supprimer les liens vers cette catégorie (puisqu'on est sur la page résultat) et supprimer le libellé "Catégorie :" si le lien est stylé "display: none" :

Balises à atteindre :

Code JS :

<script>

//Effacer les liens de la page qui pointent vers la page elle-même (modèle Archive) :

var urlcourante = document.location.href; 
// Supprimons l'éventuel dernier slash de l'URL
urlcourante = urlcourante.replace(/\/$/, "");
// Gardons dans la variable queue_url uniquement la portion derrière le dernier slash de urlcourante
var queue_url = urlcourante.substring (urlcourante.lastIndexOf( "/" )+1 );

const liensPage = document.querySelectorAll("a");
//alert(queue_url +" : "+ liensPage.length);
if(liensPage.length > 0){
    var urlLien;
    var queue_urlLien
    for (let pas = 0; pas < liensPage.length; pas++) {
        if(liensPage[pas].hasAttribute("href")){
            urlLien = liensPage[pas].getAttribute("href");
            urlLien = urlLien.replace(/\/$/, "");
            queue_urlLien = urlLien.substring(urlLien.lastIndexOf("/") +1);
            if(queue_url == queue_urlLien){
               liensPage[pas].style.display = "none";
            }
        }
    }

    //Efface le libellé "Catégorie :" quand le lien vers la catégorie a été effacé (articles). Le libellé "Catégorie :" doit avoir la classe "libelle-categorie-recherche". Dans modèle Archive.
/* Balises à atteindre (F12) :
    <div>
        <div></div>
        <p class="libelle-categorie-recherche"></p>
        <div>
            <a style="display: none;">
        </div>
    </div>
*/
    let libellescategorie = document.querySelectorAll(".libelle-categorie-recherche + div > a");
    let remontada;
    for (let celibelle of libellescategorie) { 
        if (celibelle.getAttribute("style") == "display: none;"){  
            remontada = celibelle.parentNode.parentNode.querySelectorAll("p");
            remontada[0].style.display = "none";
        }
    }
} 
</script>

BONUS n° 5

Effacer le libellé Autres résultats quand il n'y a pas plusieurs pages de résultat (modèles Recherche et Archive) :

<script>
// Le bloc à effacer doit avoir la classe "autres-pages"
if (!document.getElementsByClassName("page-numbers").length){
    let autresPages = document.getElementsByClassName("autres-pages");
    for (let libelleAutresPages of autresPages){
        libelleAutresPages.style.display = "none";
    }
}
</script>

BONUS n° 6

Affiche un sommaire H2-H3 avec liens, dans un groupe (div) ancré 'id-div-sommaire' à créer, par exemple avec une composition (la mienne s'appelle Groupe id-div-sommaire).

Mettre ce script en fin de page (sinon ça ne fonctionnera pas car il semble que ce genre de script soit exécuté sans attendre que la page soit prête à être affichée) :

<script>
/* Affiche un sommaire H2-H3 avec liens dans un groupe ancré 'id-div-sommaire'. Mettre ce sript en fin de page */
const titres = document.querySelectorAll("h2, h3");
const divSommaire = document.getElementById("id-div-sommaire");
if (titres.length > 0 && titres[0].tagName == "H2" && divSommaire !== null){
    let i=0;
    for(let titre of titres){
        if(titre.id == "") titre.id = "sommaire" + i++;
    }
    let previousH3 = false;
    let ul = '<ul>';

    for(titre of titres){
        if(titre.tagName == "H2" && previousH3){
            ul+= '</ul>';
            previousH3 = false;  
        }
        else if(titre.tagName == "H3" && !previousH3){
            ul+= '<ul>';
            previousH3 = true;
        }

        ul+= '<li><a href="#' + titre.id + '">' + titre.innerHTML + '</a></li>';
    }

    if(previousH3) ul+= '</ul>';
    ul+= '</ul>';

    divSommaire.innerHTML = ul;
}
</script>

Explications

  • const titres = document.querySelectorAll("h2, h3") : dans le tableau titres, je récupère dans l'ordre, du premier au dernier, les titres balisés h2 et h3 (je ne descends pas plus profond pour que les sommaires restent lisibles). Ca fonctionne même s'il n'y a pas de titre H3. "h2, h3" est un ciblage de type CSS.
  • const divSommaire = document.getElementById("id-div-sommaire") : je récupère dans divSommaire l'élément dont l'identifiant (id) est id-div-sommaire pour savoir s'il existe et pour lui injecter le sommaire une fois qu'il sera constitué.
  • if (titres.length > 0 && titres[0].tagName == "H2" && divSommaire !== null) : avant d'aller plus loin, je m'assure que :
    • J'ai récupéré au moins un titre (titres.length > 0)
    • Le 1er titre que j'ai récupéré est bien un H2 (si je commence par un H3 c'est qu'il manque un H2 avant lui). Les tableaux sont indexés à partir de 0 (titres[0].tagName == "H2"). Attention, le tagName (nom de la balise) est H2 et non h2 (c'est bizarre).
    • Mon groupe (div) qui contiendra le sommaire existe bien (divSommaire !== null). Remarque : != teste une différence de valeur ; !== teste une différence de valeur ou de type. Si je récupère l'objet null c'est que l'objet que j'ai essayé de récupéré plus haut (document.getElementById("id-div-sommaire") n'existe pas.
    • && : ET logique.
  • for(let titre of titres) : je vais parcourir tous les objets titres, récupérés dans mon tableau titres. A chaque tour, l'objet traité sera dans la variable titre que je déclare à la volée (let).
  • if(titre.id == "") titre.id = "sommaire" + i++ : lors de cette 1ère boucle for, je donne un identifiant (une ancre) au titre s'il n'en a pas déjà : ainsi je ne perturbe pas les ancres qui pourraient avoir été données au préalable, mais je fais en sorte qu'il n'y ai pas de titre sans id car je veux que les lignes de mon sommaire soient des liens vers les titres. Je ne mets pas d'accolades {} car mon if n'est suivi que par une seule instruction (mais on recommande souvent d'en mettre quand même).
  • i++ : i est préalablement incrémenté d'une unité (cette écriture évite une ligne de code préalable i = i+1)
  • let ul = '<ul>' : je vais fabriquer une liste (balise ul pour unordered list) que je vais mettre dans une variable que j'appelle ul (pourquoi pas). Je l'initialise avec '<ul>', la balise de ma liste principale, que je refermerai à la sortie de la boucle.
  • let previousH3 = false : j'aurai besoin de savoir si la dernière ligne que j'ai ajoutée dans ma variable ul était de type H3. Je l'initialise à false (faux) car je sais que je commence toujours par une ligne de type H2.
  • for(titre of titres) : je parcours à nouveau l'ensemble de mes titres, cette fois pour les organiser en liste HTML. En gros voila ce que ça doit donner (tout ça à la queuleuleu dans ma variable ul) :
<ul> <!-- liste ul de niveau supérieur -->
    <li><a>Titre H2</a></li>
    <li><a>Titre H2</a></li>
    <ul> <!-- liste ul de niveau inférieur indentée -->
        <li><a>Titre H3</a></li>
        <li><a>Titre H3</a></li>
    </ul>
    <li><a>Titre H2</a></li>
</ul>   
  • L'indentation des titres H3 se fera automatiquement en HTML au niveau des listes ul elles-mêmes incluses dans une liste ul de niveau supérieur.
  • if : je distingue 3 cas nécessitants des préparations différentes, 2 cas pour gérer les listes secondaires de titres de type H3, et les autres (je vous laisse vous prendre la tête, c'est de l'algorithmique : cf ci-après le détail Algorithmique de préparation, avant d'écrire le code)
  • ul+= '<li><a href="#' + titre.id + '">' + titre.innerHTML + '</a></li>' : dans tous les cas, une fois l'éventuelle gestion d'une balise de liste secondaire, je stocke mon titre proprement dit (titre.innerHTML) sous forme de lien (balise a) et j'indique la cible du lien dans l'attribut href, par exemple #sommaire9, c'est à dire # suivi de l'id que j'ai attribué tout à l'heure à mon titre et que je récupère grâce à titre.id (# permet de cibler un id, comme en CSS).
    • ul += 'blabla' est la même chose que ul = ul + 'blabla' : cela alonge la chaine de caractères contenue dans la variable ul.
    • Notez l'utilisation de la simple quotte qui permet d'embarquer des doubles quottes, par exemple : ul+= '<li><a href="#'
  • if(previousH3) ul+= '</ul>'; ul+= '</ul>';
    • Quand je sors de la boucle, je dois encore fermer la dernière ligne et la liste ul de niveau supérieur (ul+= '</ul>') ;
    • mais aussi possiblement une liste de niveau secondaire indentée (if(previousH3) ul+= '</li></ul>')
  • divSommaire.innerHTML = ul : enfin, j'injecte dans mon groupe (div) récepteur, ma variable ul contenant l'intégralité du HTML.
Algorithmique (préparation avant programmation)
1er titre = VRAI
Qui suit un titre H3 = FAUX
Boucle
    Cas 1 : cas du 1er titre
        <ul><li><a>H2</a></li>
        1er titre = FAUX
    Cas 2 : Titre H2 qui suit un titre H3
        </ul><li><a>H2</a></li>
        Qui suit un titre H3 = FAUX
    Cas 3 : Titre H2 qui suit un titre H2
        <li><a>H2</a></li>
    Cas 4 : Titre H3 qui suit un titre H3
        <li><a>H2</a></li>
    Cas 5 : Titre H3 qui suit un titre H2
        <ul><li><a>H2</a></li>
        Qui suit un titre H3 = VRAI
Fin boucle
Si Qui suit un titre H3 == VRAI alors </ul>
Dans tous les cas ajouter encore : </ul>

Je m'aperçois que :
o Tous les cas se terminent par <li><a>H2</a></li> que je vais factoriser en fin de traitement à l'intérieur de la boucle.
o Du coup, les cas 3 et 4, qui s'y résument, disparaissent.
o Les cas 2 et 5 sont symétriques et complémentaire
o je m'aperçois que le cas 1 peut être géré de façon particulière : il suffit que j'initialise la variable ul avec '<ul>' avant de commencer la boucle ; je ne risque ni de tomber dans le cas 2 (le 1er titre H2 ne suit pas un titre H3, Qui suit un titre H3 est initialisé à FAUX), ni de tomber dans le cas 5 (le titre est de type H2 et non H3). 

Rappel du code correspondant :

let firstCase = true;
let previousH3 = false;
for(titre of titres){
    if(titre.tagName == "H2" && previousH3){
        ul+= '</ul>';
        previousH3 = false;  
    } 
    else if(titre.tagName == "H3" && !previousH3){
        ul+= '<ul>';
        previousH3 = true;
    }

    ul+= '<li><a href="#' + titre.id + '">'
         + titre.innerHTML + '</a></li>';
}
if(previousH3){ul += '</ul>';}
ul += '</ul>';
HTML fabriqué par exemple pour la page https://xn--crire-9ra.fun/wordpress/documentation-du-site/

Codes observé pendant l'exécution grâce à la touche F12😉 :

Contenu de la variable ul affiché avec alert(ul)😉 :

<ul><li><a href="#pb">Problèmes en suspens</a></li><ul><li><a href="#sitemap">Sitemap</a></li><li><a href="#url">URL</a></li></ul><li><a href="#palette">Palette de couleur</a></li><li><a href="#categories">Catégories</a></li><li><a href="#modeles">Modèles</a></li><li><a href="#compo-synchro">Compositions Synchronisées</a></li><ul><li><a href="#effacer-liens">Effacer les liens et libellés inutiles</a></li><li><a href="#menus">Menus et sommaires</a></li><li><a href="#recherche">Recherche</a></li><li><a href="#quiz">Quiz</a></li><li><a href="#liens">Liens</a></li></ul><li><a href="#compo-non-synchro">Compositions Non synchronisées</a></li><ul><li><a href="#boutons">Boutons</a></li><li><a href="#quiz-non-synchro">Quiz</a></li><li><a href="#documents">Documents</a></li></ul><li><a href="#css">CSS</a></li></ul>

À retenir

<!-- Commentaire HTML qui explique ce que fait le code : Bouton "Replier les blocs Détails" et afficher en haut de la page le bloc dont l'ancre est "debut" -->

<!-- On met le bouton dans une paire de balise div pour pouvoir le centrer grâce au code CSS de la div, directement présent dans l’attribut style : -->

<div style="text-align: center;">

    <!-- La classe "niceButton", permet au bouton de bénéficier d’une mise en forme élaborée écrite en CSS ciblant cette classe (le code CSS se trouve dans WPè-admin /Apparence /Personnaliser /CSS additionnel). Et l’attribut onclick permet de définir ce qui doit se passer quand on appuie sur le bouton : ici exécuter la fonction replierDetail() : -->
    <button class="nice-button" onclick="replierDetails();">
        //Les balises big doublent la taille du texte (on aurait pu obtenir ce résultat avec du CSS) :      
        <big><big>Replier les blocs Détails</big></big>
    </button>
</div>

<!-- La fonction écrite en JavaScript est déclarée dans une paire de balises script : --> 
<script>
    function replierDetails(){

        //Récupérer les balises détails dans un tableau :   
        let details = document.querySelectorAll('details');


        //Et fermer toutes les balises détails :
        for (let detail of details) {detail.open = false;};

        //Récupérer la balise identifiée par "début" (ancre du bloc) :
        let debut = document.getElementById("debut");

        //Et positionner l’affichage sur cette balise :
        debut.scrollIntoView();
    }
</script>

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

Get 30% off your first purchase

X