Pliage de code dans bookdown et blogdown
L’option code_folding: true
, comme dans les documents rmarkdown
classiques, ne fonctionne pas avec bookdown ou blogdown. Il est quand même possible de l’activer avec quelques astuces. Tous les fichiers présentés ici, les fichiers javascript
et Rmd
nécessaires à bookdown et les fichiers html
nécessaires à blogdown, pour activer le pliage de code, sont disponibles sur mon github (blog tips).
Comme pour l’article de blog que vous êtes en train de lire, ces codes permettent:
- un bouton sur chaque bloc de code pour afficher/cacher
- un bouton global avec un menu déroulant pour afficher/masquer tous les codes sur la page
J’ai passé des thèmes Hugo avec du code folding, retrouvez la liste ici.
Pliage du code dans bookdown
Il y a quelque temps, j’ai répondu à une question sur stackoverflow pour activer le pliage de code avec bookdown. Bien que cette réponse fonctionne, je n’étais pas totalement satisfait du comportement du bouton “Afficher/Masquer Global”. Aujourd’hui, je l’ai corrigé et il fonctionne proprement ! J’ai fait de “l’ingénierie inverse” pour trouver ce qui fonctionnait dans le rmarkdown
classique et j’ai redéfini le css
approprié pour bookdown.
Quelques codes javascript
La fonction principale de javascript qui sera appelée codefolding.js
doit trouver le tag .sourceCode
pour fonctionner avec bookdown. Cela nécessite également des fonctions javascript complémentaires de la librairie bootstrap, mais pas toutes.
Voici les étapes:
- Créez un dossier
js
dans le même répertoire que votre fichierRmd
. - Téléchargez les fonctions javascript
transition.js
,collapse.js
etdropdown.js
ici par exemple: https://github.com/twbs/bootstrap/tree/v3.3.7/js et stockez-les dans votre dossierjs
. - Créez un nouveau fichier dans le dossier
js
appelécodefolding.js
avec le code suivant. C’est la même chose que pour l’optioncode_folding
dermarkdown
mais avecpre.sourceCode
ajouté pour que la fonction trouve les morceaux de code R. Vous pouvez ajouter d’autres langage de code avecpre.lang
dans ce fichier.
Le fichier codefolding.js
:
window.initializeCodeFolding = function(show) {
// handlers for show-all and hide all
$("#rmd-show-all-code").click(function() {
$('div.r-code-collapse').each(function() {
$(this).collapse('show');
});
});
$("#rmd-hide-all-code").click(function() {
$('div.r-code-collapse').each(function() {
$(this).collapse('hide');
});
});
// index for unique code element ids
var currentIndex = 1;
// select all R code blocks
var rCodeBlocks = $('pre.sourceCode, pre.r, pre.python, pre.bash, pre.sql, pre.cpp, pre.stan, pre.js');
rCodeBlocks.each(function() {
// create a collapsable div to wrap the code in
var div = $('<div class="collapse r-code-collapse"></div>');
if (show)
div.addClass('in');
var id = 'rcode-643E0F36' + currentIndex++;
div.attr('id', id);
$(this).before(div);
$(this).detach().appendTo(div);
// add a show code button right above
var showCodeText = $('<span>' + (show ? 'Hide' : 'Code') + '</span>');
var showCodeButton = $('<button type="button" class="btn btn-default btn-xs code-folding-btn pull-right"></button>');
showCodeButton.append(showCodeText);
showCodeButton
.attr('data-toggle', 'collapse')
.attr('data-target', '#' + id)
.attr('aria-expanded', show)
.attr('aria-controls', id);
var buttonRow = $('<div class="row"></div>');
var buttonCol = $('<div class="col-md-12"></div>');
buttonCol.append(showCodeButton);
buttonRow.append(buttonCol);
div.before(buttonRow);
// update state of button on show/hide
div.on('hidden.bs.collapse', function () {
showCodeText.text('Code');
});
div.on('show.bs.collapse', function () {
showCodeText.text('Hide');
});
});
}
Le fichier Rmd
Le script Rmd
pour bookdown inclut toutes les fonctions js
directement écrites dans l’en-tête, de sorte que le dossier js
n’est pas utile pour le document final lui-même. Dans le bloc setup
, j’ai défini l’option pour afficher tous les blocs de code par défaut dans le document, mais vous pouvez choisir de les masquer par défaut avec 'show' === 'hide'
. Le fichier Rmd complet à utiliser comme base pour un document bookdown se trouve sur mon répertoire “blog tips” sur github.
- L’en-tête YAML suivant lit un fichier
header.html
qui est construit en “knittant” le fichier Rmd.
---
title: "Toggle R code"
author: "StatnMap"
date: '06 mai, 2020'
output:
bookdown::html_document2:
includes:
in_header: header.html
bookdown::gitbook:
includes:
in_header: header.html
---
- Le code R ci-dessous doit être inclus dans un bloc avec
echo=FALSE
. Ce code lit les fichiersjs
et les inclut dans un fichierheader.html
externe avec lecss
associé. Ceheader.html
est ensuite directement inclus dans les fichiers bookdown grâce à la configurationyaml
ci-dessus.
Vous verrez qu’il y a quelquescss
dans ce code pour gérer pour la position, les couleurs, … des boutons à cliquer.
codejs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/codefolding.js")
collapsejs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/collapse.js")
transitionjs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/transition.js")
dropdownjs <- readr::read_lines("/mnt/Data/autoentrepreneur/js/dropdown.js")
htmlhead <- c(
paste('
<script>',
paste(transitionjs, collapse = "\n"),
'</script>
<script>',
paste(collapsejs, collapse = "\n"),
'</script>
<script>',
paste(codejs, collapse = "\n"),
'</script>
<script>',
paste(dropdownjs, collapse = "\n"),
'</script>
<style type="text/css">
.code-folding-btn { margin-bottom: 4px; }
.row { display: flex; }
.collapse { display: none; }
.in { display:block }
.pull-right > .dropdown-menu {
right: 0;
left: auto;
}
.open > .dropdown-menu {
display: block;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
display: none;
float: left;
min-width: 160px;
padding: 5px 0;
margin: 2px 0 0;
font-size: 14px;
text-align: left;
list-style: none;
background-color: #fff;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border: 1px solid #ccc;
border: 1px solid rgba(0,0,0,.15);
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
box-shadow: 0 6px 12px rgba(0,0,0,.175);
}
</style>
<script>
$(document).ready(function () {
window.initializeCodeFolding("show" === "show");
});
</script>
', sep = "\n"),
paste0('
<script>
document.write(\'<div class="btn-group pull-right" style="position: absolute; top: 20%; right: 2%; z-index: 200"><button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" data-_extension-text-contrast=""><span>Code</span> <span class="caret"></span></button><ul class="dropdown-menu" style="min-width: 50px;"><li><a id="rmd-show-all-code" href="#">Show All Code</a></li><li><a id="rmd-hide-all-code" href="#">Hide All Code</a></li></ul></div>\')
</script>
')
)
readr::write_lines(htmlhead, path = "/mnt/Data/autoentrepreneur/header.html")
Pliage du code en blogdown
Comme j’ai récemment migré vers hugo, j’ai décidé que je pouvais inclure cette astuce de pliage de code avec blogdown. Comme vous pouvez le voir sur l’article que vous lisez actuellement, le pliage de code est activé. Vous pouvez récupérer tous les codes qui vont suivre dans mon dossier “blog tips” sur github. Si vous voulez voir toutes les modifications que j’ai ajoutées à mon template de site Internet “hugo-statnmap-template” pour cette question de pliage de code, vous pouvez allez voir le “pull request” associé sur le github de mon template. Notez que mon template est multilingue, donc le code associé au pliage de code l’est aussi.
Le fonctionnement dépend des mêmes codes que pour bookdown, sauf que nous pouvons le configurer une seule fois pour l’ensemble du site en utilisant le thème.
Quelques bibliothèques javascripts
Les mêmes bibliothèques javascript sont nécessaires.
- Créez un dossier
js
dans le répertoirestatic
de votre thème hugo. - Ajoutez les fonctions javascript complémentaires de bootstrap:
transition.js
,collapse.js
etdropdown.js
(ici par exemple) dans le répertoirejs
. - Dans ce même répertoire
js
, créez un nouveau fichier appelécodefolding.js
. Le code est exactement le même que pour bookdown.
Le fichier codefolding.js
:
window.initializeCodeFolding = function(show) {
// handlers for show-all and hide all
$("#rmd-show-all-code").click(function() {
$('div.r-code-collapse').each(function() {
$(this).collapse('show');
});
});
$("#rmd-hide-all-code").click(function() {
$('div.r-code-collapse').each(function() {
$(this).collapse('hide');
});
});
// index for unique code element ids
var currentIndex = 1;
// select all R code blocks
var rCodeBlocks = $('pre.sourceCode, pre.r, pre.python, pre.bash, pre.sql, pre.cpp, pre.stan, pre.js');
rCodeBlocks.each(function() {
// create a collapsable div to wrap the code in
var div = $('<div class="collapse r-code-collapse"></div>');
if (show)
div.addClass('in');
var id = 'rcode-643E0F36' + currentIndex++;
div.attr('id', id);
$(this).before(div);
$(this).detach().appendTo(div);
// add a show code button right above
var showCodeText = $('<span>' + (show ? 'Hide' : 'Code') + '</span>');
var showCodeButton = $('<button type="button" class="btn btn-default btn-xs code-folding-btn pull-right"></button>');
showCodeButton.append(showCodeText);
showCodeButton
.attr('data-toggle', 'collapse')
.attr('data-target', '#' + id)
.attr('aria-expanded', show)
.attr('aria-controls', id);
var buttonRow = $('<div class="row"></div>');
var buttonCol = $('<div class="col-md-12"></div>');
buttonCol.append(showCodeButton);
buttonRow.append(buttonCol);
div.before(buttonRow);
// update state of button on show/hide
div.on('hidden.bs.collapse', function () {
showCodeText.text('Code');
});
div.on('show.bs.collapse', function () {
showCodeText.text('Hide');
});
});
}
Modifiez vos modèles de templates Hugo
- Dans votre fichier de configuration de thème, vous pouvez ajouter les paramètres suivants pour activer ou désactiver totalement le pliage de code dans le site Web et définir s’il est affiché ou non par défaut. Notez que ceci peut également être défini dans chaque article du blog (voir ci-dessous).
# Set to true to disable code folding
disable_codefolding = false
# Set to "hide" or "show" all codes by default
codefolding_show = "hide"
- Dans le pied de page principal (footer) ou l’en-tête (header) de votre thème, vous devez charger les libraries javascript. Vous pouvez utiliser le code suivant (
footer_js.html
).
{{ if not .Site.Params.disable_codefolding }}
<script src="{{ "js/collapse.js" | relURL }}"></script>
<script src="{{ "js/dropdown.js" | relURL }}"></script>
<script src="{{ "js/transition.js" | relURL }}"></script>
{{ end }}
- Pour pouvoir activer ou non le pliage de code dans chaque article, vous devez charger
codefolding.js
dans le pied de page (ou en-tête) de l’article directement. Vous pouvez également laisser la possibilité de choisir pour chaque article si tous les codes sont affichés ou masqués lors du chargement de l’article. C’est la même partie de code que pour bookdown avec"show" === "show"
, mais ici on utilise.Site.Params
ou.Params
pour le définir. Par exemple, sur mon site, vous pouvez aller sur les autres articles du blog et vous verrez que tous les codes sont cachés par défaut ("show" === "hide"
). En revanche, lorsque vous arrivez sur l’article actuel sur le pliage de code, tous les codes ont été ouverts. C’est parce que j’ai miscodefolding_show: 'show'
dans l’en-têteyaml
de mon fichierRmd
. De même pour le paramètredisable_codefolding: false
que vous pouvez paramétrer dans votre fichier de configuration du site principal ainsi que dans chaque article du blog. Pour ça, vous devez ajouter cette partie de code directement dans votre modèle de pied de page (ou en-tête) d’article (article_footer_js.html
).
{{ if and (not .Site.Params.disable_codefolding) (not .Params.disable_codefolding) (in (string .Content) "</pre>") }}
<script>
$(document).ready(function () {
window.initializeCodeFolding("show" === {{ if isset .Params "codefolding_show" }}{{ .Params.codefolding_show }}{{ else }}{{ default ("hide") .Site.Params.codefolding_show }}{{ end }});
});
</script>
<script src="{{ "js/codefolding.js" | relURL }}"></script>
{{ end }}
- Vous devez trouver l’endroit approprié pour ajouter le code suivant dans le template de vos articles, dans l’en-tête de l’article par exemple. Ce code permet de créer un bouton principal pour afficher/masquer tous les blocs de code en même temps. Dans mon cas, j’ai stocké le code suivant dans
header_maincodefolding.html
dans le répertoiretemplate/partials
. J’ai ensuite ajouté{{ partial "header_maincodefolding" . }}
dans l’en-tête de mon article.
{{ if and (not .Site.Params.disable_codefolding) (not .Params.disable_codefolding) (in (string .Content) "</pre>") }}
<div id="code-folding-buttons" class="btn-group pull-right">
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" data-_extension-text-contrast="">
<span>Show/Hide all code</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" style="min-width: 50px;">
<li><a id="rmd-show-all-code" href="#">Show All Code</a>
</li><li><a id="rmd-hide-all-code" href="#">Hide All Code</a></li>
</ul>
</div>
{{ end }}
Ajouter quelques css
Pour que tous les boutons apparaissent correctement sur votre page web, vous devez les placer avec un peu de css. Voici les codes css
que j’ai utilisés.
- Code pour le bouton principal “Afficher/masquer” tous les codes
#code-folding-buttons {float: right;}
#code-folding-buttons .pull-right > .dropdown-menu {
right: 0;
left: auto;
}
#code-folding-buttons .btn.btn-default.btn-xs.dropdown-toggle {
float: right;
}
#code-folding-buttons.open > .dropdown-menu {
display: block;
}
#code-folding-buttons .dropdown-menu {
top: 100%;
left: 0;
z-index: 1000;
display: none;
min-width: 160px;
padding: 5px 0;
margin: 2px 0 0;
font-size: 14px;
text-align: left;
list-style: none;
background-color: #fff;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border: 1px solid #ccc;
border: 1px solid rgba(0,0,0,.15);
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
box-shadow: 0 6px 12px rgba(0,0,0,.175);
}
#code-folding-buttons .dropdown-menu li {
padding: 5px;
}
- Code pour le bouton au-dessus de chaque bloc de code
.code-folding-btn {
margin-bottom: 4px;
}
.row {
display: flex;
border-bottom: solid 1px #d7d7d7;
}
.collapse {
display: none;
}
.in {
display: block ;
border: solid 1px #d7d7d7;
border-radius: 5px;
}
.col-md-12 {
margin: 0 0 0 auto;
}
Une fois encore, je rappelle que tous ces scripts sont disponibles dans mon dossier “blog tips” sur github
Citation :
Merci de citer ce travail avec :
Rochette Sébastien. (2017, nov.. 13). "Afficher / cacher les zones de code avec bookdown et blogdown". Retrieved from https://statnmap.com/fr/2017-11-13-afficher-cacher-les-zones-de-code-avec-bookdown-et-blogdown/.
Citation BibTex :
@misc{Roche2017Affic,
author = {Rochette Sébastien},
title = {Afficher / cacher les zones de code avec bookdown et blogdown},
url = {https://statnmap.com/fr/2017-11-13-afficher-cacher-les-zones-de-code-avec-bookdown-et-blogdown/},
year = {2017}
}