custom_dir
Fonctionnalités avancées
Utiliser le custom_dir
permet de modifier le comportement du thème en profondeur ou d'en réutiliser certaines fonctionnalités.
Pour bien mettre Ă profit le custom_dir
, il faut être familier avec la personnalisation d'un thème mkdocs.
"With great powers..."
Définir un custom_dir
#
Il suffit d'ajouter un dossier Ă la racine du projet, et d'ajouter son nom dans la section theme
du fichier mkdocs.yml
.
Typiquement, le nom de dossier est overrides
, mais il est possible d'utiliser un autre nom aussi.
theme:
custom_dir: overrides
Utilisation#
Surcharges de fichiers#
Il est possible d'ajouter autant de fichiers que nécessaire dans un custom_dir
, du moment qu'ils n'ont pas les mêmes noms que ceux déclarés par les thèmes parents.
Si par contre il s'agit de modifier l'un des fichiers définis par un des thèmes parents, il faut identifier le thème qui définit le fichier concerné, récupérer le contenu du fichier à modifier, puis créer un fichier du même nom et chemin relatif par rapport au custom_dir
que dans le dossier templates
d'origine, et y faire les modifications souhaitées.
Il est possible de trouver les fichiers définis par les thèmes aux endroits suivants :
- Dossier
templates
du thème (PMT) - Dossier
templates
de material. - Il est aussi possible de retrouver ces dossiers sur une installation locale, dans les répertoires d'installation des thèmes.
Surcharge de main.html
#
À partir de la version 3.2.0 du thème, il est possible de surcharger le fichier main.html
du thème, comme cela se fait avec mkdocs-material, pour pouvoir injecter sa propre logique autour de celle du thème, voire pour modifier certains comportements du thème.
Pour cela, il suffit d'ajouter dans le custom_dir
du projet un fichier main.html
avec le contenu suivant :
{% extends "base_pmt.html" %}
Notez que le fichier à étendre est celui du thème, et non le fichier "base.html"
provenant de mkdocs-material (et sur lequel s'appuie le thème lui-même).
Il est ensuite possible d'ajouter de la logique autour des différents blocs Jinja
:
{% extends "base_pmt.html" %}
{% block scripts %}
<!-- Things to do before the original block... -->
{{ super() }}
<!-- Things to do after... -->
{% endblock %}
Modifier le JS de PMT#
Il est possible de modifier relativement facilement les classes utilisées dans la couche JS du thème pour y ajouter des nouveaux comportements ou les modifier.
Très exposé aux "breaking changes"
Modifier les comportements du thème implique d'écrire du code qui a beaucoup plus de chances de "casser" suite à des modifications internes du code du thème.
En effet, Pyodide-Mkdocs-Theme est développé avec en vue des utilisateurs travaillant pour l'essentiel avec une documentation markdown/mkdocs et ne personnalisant pas ou alors très peu le thème lui-même (en dehors des options proposées).
Ainsi, l'interface "externe" (les macros, la configuration du plugin) introduit le moins possible des breaking changes, mais ceux-ci sont nettement plus fréquents dans la machinerie interne s'ils permettent d'introduire diverses améliorations.
Ă€ partir de la version 4.0.0
du thème, le remplacement des classes du thème (Ide
, Terminal
, Qcm
, ...) peut se faire en surchargeant le fichier js-scripts/overlord.js
depuis le custom_dir
. Pour cela :
- Créer un fichier
overrides/js-scripts/overlord.js
(ou équivalent si votrecustom_dir
n'est pas nomméoverrides
). -
Y ajouter le code suivant :
import { waitForClassesPoolReady } from "functools"; // Réexporte pour que ce module soit importable depuis subscriptions.js: export default waitForClassesPoolReady waitForClassesPoolReady(_=>{ /* Cette fonction est appelée (sans argument) une fois que toutes les classes du thème nécessaires à la page en cours ont été enregistrées dans `CONFIG.CLASSES_POOL`. Vous pouvez les remplacer comme bon vous semble (à vos risques et périls...). Nota: l'objet CONFIG est disponible depuis l'environnement global. */ return true /* Ne pas oublier de renvoyer true une fois vos remplacements effectués. Renvoyer undefined lèverait une erreur. Renvoyer une valeur "falsy" ferait que la fonction sera rappelée plus tard, jusqu'à ce qu'elle finisse par renvoyer une valeur "truthy". Il faut impérativement qu'une valeur "truthy" soient renvoyée à un moment, sans quoi les éléments de la page ne seront jamais fonctionnels : le script `subscriptions.js` attend la résolution de cette étape pour faire son travail ! */ })
Cette logistique permet de garantir que votre code sera exécuté au moment approprié malgré les importations asynchrones :
- Après que toutes les classes nécessaires à la page aient été enregistrées.
- Avant que le thème n'ait créé les objets nécessaires au fonctionnement de la page à partir des classes enregistrées dans
CONFIG.CLASSES_POOL
.
-
Le modifier en créant vos propres classes.
- Vos classes devraient étendre les classes existantes, pour garantir le bon fonctionnement de l'ensemble.
- Avant d'étendre une classe, il faut vérifier si elle est bien définie dans
CONFIG.CLASSES_POOL
: en effet, seules les classes utiles à la page sont chargées, alors que le fichieroverlord.js
est exécuté quel que soit le contenu de la page.
Voici un exemple d'utilisation simplifié à l'extrême, qui fait en sorte que tous les IDEs démarrent avec le message Yup!
présent dans le terminal :
import { waitForClassesPoolReady } from "functools";
// Réexporte pour que ce module soit importable depuis subscriptions.js:
export default waitForClassesPoolReady
waitForClassesPoolReady(_=>{
// Si la classe est définie, on la remplace :
if(CONFIG.CLASSES_POOL.Ide){
// On étend la classe existante :
class YupIde extends CONFIG.CLASSES_POOL.Ide {
build(){
super.build()
this.terminalEcho('Yup!') // Modification de comportement voulue...
}
}
// On remplace la classe enregistrée par la nôtre:
CONFIG.CLASSES_POOL.Ide = YupIde
}
// On n'oublie pas de "dire qu'on a terminé":
return true
})
Remplacement des classes JS du thème (3.2.0 <= PMT < 4.0.0
)
Pour utiliser vos propres classes JS à la place de celles du thème, il suffit de créer un fichier main.html
et d'y modifier le bloc Jinja scripts
avec un code utilisant la logique suivante:
{% extends "base_pmt.html" %}
{% block scripts %}
<!--
Insérer ici une balise script ou un lien vers un fichier JS dont le code va
modifier les classes de `CONFIG.CLASSES_POOL` avant que les objets ne soient
instanciés dans la page (depuis le bloc `scripts` parent).
Exemple simple ci-dessous, créant tous les IDEs avec un message `"Yup!"`
affiché dès le démarrage dans les terminaux :
-->
<script>
if(CONFIG.CLASSES_POOL.Ide){
class YupIde extends CONFIG.CLASSES_POOL.Ide {
build(){
super.build()
this.terminalEcho('Yup!')
}
}
CONFIG.CLASSES_POOL.Ide = YupIde
}
</script>
{{ super() }}
{% endblock %}
Remarques sur le code JS utilisé
-
La classe déclarée dans ce code étend la classe
IdeRunner
, stockée dansCONFIG.CLASSES_POOL.Ide
. Ceci permet de modifier les comportements existants des IDEs.
Notez qu'il est de loin préférable de leur ajouter des comportements que de modifier les comportements existants, ce qui est beaucoup plus propice à casser lors d'une mise à jour du thème. -
Comme les scripts du thème ne sont chargés que s'ils sont utiles au contenu de la page, il faut vérifier que la classe a bien été définie et stockée dans
CONFIG.CLASSES_POOL
avant d'écrire le code l'étendant. -
Une fois la classe personnalisée déclarée, elle doit remplacer la classe d'origine dans l'objet
CONFIG.CLASSES_POOL
afin d'être utilisée pour créer les objets dans la page.
Crochets html (obsolètes) #
Avant la version 3.2.0, surcharger le fichier main.html
n'était pas possible. Un système de "fichiers crochets" avait donc été mis en place pour permettre une certaine flexibilité malgré tout.
Ces fichiers crochets sont toujours utilisables, mais leur présence sur le disque provoque un warning dans le terminal, lors des mkdocs build
ou serve
. Il est conseillé de les remplacer par la surcharge du fichier main.html
du thème.
Utilisation des fichiers crochets (PMT < 3.2.0
)
Afin de facilité la personnalisation du thème, sans avoir besoin de redéclarer des fichiers entiers, le thème met à disposition des fichiers "crochets" qui permettent d'insérer de la logique à différents moments, dans le code html de chaque page.
Pour utiliser ces crochets, il suffit d'ajouter au custom_dir
un dossier hooks
contenant le ou les fichiers html appropriés à votre usage :
Crochet | Insère de la logique dans le fichier main.html ... |
---|---|
hooks/libsBefore.html |
...au début du bloc libs |
hooks/libsAfter.html |
...Ă la fin du bloc libs |
hooks/contentBefore.html |
...au début du bloc content |
hooks/contentAfter.html |
...Ă la fin du bloc content |
hooks/scriptsBefore.html |
...au début du bloc scripts |
hooks/scriptsAfter.html |
...Ă la fin du bloc scripts |
Ces fichiers sont inclus via la commande Jinja {% include "..." ignore missing %}
, ce qui permet d'y utiliser également des fonctionnalités Jinja, ou encore du css ou du js en y écrivant les balises appropriées.
C'est notamment la façon idoine de réintroduire des balises <scripts>
ou <style>
chargeant des fichiers issues de CDNs dans le fichier main.html
, si leur insertion via mkdocs.yml:extra_javascript
a échoué (1).
- Les scripts introduits via
extra_javascript
sont ajoutés en bas de la page html, juste avant le contenu du footer. Une erreur peut alors être levée si du code JS essaie d'utiliser ce contenu plus haut dans la page, alors que le cdn n'est pas encore chargé (sauf astuces assez moches... :shhhh: ). Dans ce genre de cas, insérer la balise depuis un des crochetslibs
devrait permettre de résoudre le problème.
Personnaliser le JS de PMT
Il est possible de modifier relativement facilement les classes utilisées dans la couche JS pour y ajouter des nouveaux comportements ou les modifier.
La procédure est la suivante :
- Créer un fichier
hooks/scriptsBefore.html
dans lecustom_dir
. - Ajouter dans ce fichier une balise
<script>
qui contiendra le code de la classe personnalisée. - Avant de déclarer la classe personnalisée, vérifier que la classe d'origine est disponible dans l'objet
CONFIG.CLASSES_POOL
(voir le fichierpyodide_mkdocs_theme/templates/js-libs/0-config.js
).
Le thème ne charge les scripts de définition des classes que si elles sont utilisées dans la page en cours, alors que les fichiers crochets seront lancés sur toutes les pages. D'où la nécessité de vérifier l'existence de la classe avant de déclarer la customisation. - Si la classe à modifier existe, créer la classe personnalisée en étendant la classe d'origine, et y ajouter/modifier tous les comportements désirés.
- Une fois la classe déclarée, remplacer la classe d'origine dans
CONFIG.CLASSES_POOL
par la classe personnalisée.
Exemple
Contenu du fichier hooks/scriptsBefore.html
:
<script>
if(CONFIG.CLASSES_POOL.Ide){
class YupIde extends CONFIG.CLASSES_POOL.Ide {
build(){
super.build()
this.terminalEcho('Yup!')
}
}
CONFIG.CLASSES_POOL.Ide = YupIde
}
</script>
Ce qui conduit tous les IDEs Ă afficher Yup!
lors de leur cration :