(CS-108) Un userscript pour améliorer la lisibilité des consignes
March 01, 2024
• ...
Hello, nouveau tutoriel pour le cours CS-108 de Michel Schinz.
L’objectif ici est d’améliorer un peu la lisibilité des consignes en réglant deux problèmes :
- les conseils de programmation sont toujours après la définition de la méthode
- souvent, le nom des méthode à créer n’est pas assez mis en avant à mon goût
- on ne peut pas copier les liens des sections pour les référencer ailleurs (sur ED par exemple)
Pour cela, nous allons devoir modifier le style de la page dynamiquement avec un userscript (un script JavaScript écrit par un utilisateur pour modifier le comportement d’un site).
Le résultat final nous permettra de mettre en avant les méthodes, et d’ajouter un lien pour jumper aux conseils spécifique à chaque méthode sans attendre
Il existe des dizaines d’extensions permettant de mettre en place ces userscripts
. Nous allons ici utiliser ViolentMonkey
, open source et bien maintenu.
TL;DR le lien du script final (à importer dans ViolentMonkey)
Détection des définitions de méthodes
Dans un premier temps, il nous faut détecter les méthodes présentes dans la consigne. Cela peut se faire à l’aide de l’instruction suivante :
const methods = new Set();const listItems = document.querySelectorAll('li');for (listItem of listItems) {const firstCode = listItem.querySelector('code:first-of-type');if (firstCode) {firstCode.style.backgroundColor = '#808080';firstCode.style.color = 'white';console.log('[METHODE] définition de méthode trouvée, ' + firstCode.innerText);methods.add(firstCode);}}
Pour cela, on a donc pris le premier élément formatté comme du code dans chaque liste. Nous appliquons un background gris et modifions la couleur du texte.
Nous stockons également la méthode dans un Set
, qui nous servira plus tard.
Détection des conseils de programmation
Dans un second temps, nous voulons détecter les conseils de programmation. Nous pouvons utiliser notre code précédent vérifiant si le titre de la section est “Conseils de programmation”.
const listItems = document.querySelectorAll('li');for (listItem of listItems) {// are we in a conseils de programmation ? :)const parentDiv = listItem.parentNode.parentNode;const isConseilsDeProg = parentDiv.id.includes('outline-container') && parentDiv.children[0].innerHTML.includes('Conseils de programmation');if (isConseilsDeProg) conseilsDeProg.add(parentDiv);}
Lier les deux
Enfin, nous pouvons lier les deux en utilisant ce bout de code qui fait le matching entre une méthode et un conseil, et qui créé une balise de lien <a>
pour jumper vers le bon conseil.
conseilsDeProg.forEach((parentDiv) => {const titles = parentDiv.querySelectorAll('li > code:first-of-type');for (title of titles) {console.log('[CONSEIL] conseil trouvé pour la méthode ' + title.innerText);const id = title.parentNode.children[0].id;for (method of methods) {if (method.innerText.includes(title.innerText)) {console.log('[MATCHING] conseil pour ' + title.innerText + ' matched');const a = document.createElement('a');a.innerHTML = '<b> (voir les conseils de programmation) </b>';a.href = '#' + id;method.parentNode.appendChild(a);}}}});
Finalement, on boucle sur tous les titres pour leur ajouter un lien de référence :
for (header of document.querySelectorAll('h3, h4, h5, h6')) {console.log(header.id);const a = document.createElement('a');a.href = 'javascript:void(0)';a.innerText = '(📋)';a.style.marginLeft = '5px';header.appendChild(a);const link = `${window.location.origin}${window.location.pathname}#${header.id}`;a.onclick = () => {a.innerText = '(✅ link copied)';setTimeout(() => a.innerText = '(📋)', 1_000);navigator.clipboard.writeText(link).then(function() {console.log('Async: Copying to clipboard was successful!');}, function(err) {console.error('Async: Could not copy text: ', err);});}}