Les fichiers README
, par exemple sur les dépôts Github, sont écrits en markdown. Markdown est un langage de balisage léger permettant d’être interprété pour générer du HTML
ou du PDF
, et de disposer d’un fichier facile à lire en l’état, et simple à modifier. Github dispose d’une cheatsheet présentant les caractéristiques du langage, se voulant assez généraliste. L’extension d’un fichier markdown est .md
.
L’objectif de cet article est de décrire l’interprétation du fichier Markdown à l’aide d’une classe php
permettant d’interpréter le langage, et la mise en place d’instructions javascript
pour générer un sommaire en début de l’article produit.
Le paquet Parsedown
Parsedown
est une classe php
qui fournit des méthodes permettant la génération d’un code HTML
, rapide et sans dépendance. On télécharge donc le fichier Parsedown.php
, il suffit alors de l’inclure où l’on en a besion et créer une instance de la classe pour appeler la méthode text()
. On lit le contenu du fichier md
, ici README.md
, et l’on définit l’url
des images, copies d’écran screenshots que l’on souhaite intégrer au fichier HTML produit.
1 2 3 4 |
require '/path/to/Parsedown.php'; $readme = file_get_contents( '/path/to/README.md' ); $parse = new Parsedown(); $screenshots = 'https:/url/to/images/screenshots'; |
Les paths
chemins et l’url
Uniform Resource Locator sont à adapter aux besoins. L’url
du dossier screenshots
n’a pas de /
slash à la fin, c’est important pour l’expression régulière par la suite.
À présent, pour afficher le fichier HTML
, il suffit d’écrire :
1 |
$html = $parse->text( $readme ); |
Et par exemple :
1 2 3 4 5 |
ob_start(); ?> <div id="myWrapper"> <?php echo $html; ?> </div> <?php echo ob_get_clean(); |
Affichage des screenshots
En Markdown, une image est affichée de la façon suivante :
1 |
 |
Le code HTML produit est :
1 |
<img src="my-image.jpg" alt="My alternative text"> |
On pourrait entrer des URL
valides dans les parenthèses markdown. On va cependant laisser seulement les noms de fichiers et changer l’attribut src
en php
. Cela peut se faire en javascript
si l’on connaît la variable $screenshots
, qui donne l’url
du répertoire des images.
En php
:
1 |
$html = preg_replace( '/img src="([^\/"]+)"/', "img src=\"{$screenshots}/$1\"", $parse->text( $tuto ) ); |
En Markdown, on peut écrire des balises html
telles que img
. Dans ce cas, l’instruction précédente ne remplacera rien si il y au moins un /
slash dans l’attribut src
de img
.
En javascript
, on met l’url
des images dans la variable screenshots
. Avec WordPress, cela peut se faire avec la fonction localize_script()
si l’on a définit cette url
en php.
1 2 3 4 5 6 7 8 |
const screenshot = '/url/to/screenshots'; myWrapper.querySelectorAll('img').forEach(img => { const regex = new RegExp('[^\/]+$'); if (regex.test(img.src)) { const match = img.src.match(regex); img.src = sreenshots + '/' + match[0]; } }); |
Le problème de cette seconde solution est que l’on risque d’avoir des erreurs dans la console, indiquant que certains fichiers images sont introuvables, avant que le changement avec la regex ait pu être fait. myWrapper est la div qui englobe le markdown traduit en html.
Sommaire
Le principe repose sur la recherche en javascript
des titres h2
en leur assignant un identifiant unique suivi d’une flèche de retour en haut de la page. Les liens vers ces titres sont écrits en haut de page dans une liste ordonnée.
Les identifiants seront basés sur le contenus des titres h2
, donc si l’on a deux titres identiques, cela risque de coincer, mais cela sera rarement le cas. Cela serait éventuellement à prévoir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
const myWrapper = document.getElementbyId('myWrapper'); var sommaire = '<ol>' document.querySelectorAll('#myWrapper h2').forEach((el, index) => { // On enlève les accents, on remplace les ponctuations const regex = new RegExp('[\'",;.?!:\/«» ]', 'g'); const id = el.innerText.normalize('NFD').replace(/[\u0300-\u036f]/g, "") .replace(regex, '-'); el.id = id; sommaire += '<li><a href="#' + id + '">' + el.innerText + '</li>'; const toTop = document.createElement('span'); toTop.classList.add('clio-arrow-up-a', 'toTop'); if (index) el.append(toTop); toTop.addEventListener('click', e => { scroll({ top: 0, behavior: 'smooth', }) }); }); sommaire += '</ul>'; // On insère le sommaire devant le premier titre h2 const firsth2 = clioTuto.querySelector('h2:first-of-type'); clioTuto.insertBefore(sommaire, firsth2); const diff = 50; sommaire.querySelectorAll('a[href^="#"]').forEach(a => { a.addEventListener('click', e => { e.preventDefault(); const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const rect = document.getElementById(a.hash.slice(1)).getBoundingClientRect(); scroll({ top: rect.top + scrollTop - diff, behavior: 'smooth', }); }); }); // Restyle paragraph with multiple image document.querySelectorAll('p img:nth-of-type(2').forEach(img => { const parent = img.parentNode; parent.style.display = 'flex'; parent.style.flexWrap = 'wrap'; parent.style.justifyContent = 'space-around'; parent.style.alignItems = 'center'; parent.querySelectorAll('img').forEach(elimg => { elimg.style.margin = '1em'; }); }); |
L’élément <span class="clio-arrow-up-a"></span>
est un icon flèche haut .
On écrit dans la variable sommaire
la liste ordonnée des liens du sommaire, que l’on insère avant le premier tire h2
. On définit un défilement doux lorsque l’on clique sur l’un des liens, ou sur la flèche de retour en haut de la page. On insère pas la flèche sur le premier titre.
Enfin, si plusieurs images se suivent, on définit un style flexbox wrap et une marge pour chaque image.
Et hop, un sommaire automatique, le fichier markdown traduit.