/*!
* MathGraph32 Javascript : Software for animating online dynamic mathematics figures
* https://www.mathgraph32.org/
* @Author Yves Biton (yves.biton@sesamath.net)
* @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
* @version 5.7.0
*/
import { getMathjaxBase } from 'src/kernel/kernel'
export default loadMathJax
const loadDelay = 40 // en s (avec peu de débit ça peut être assez long)
// en local on impose l'url de notre pnpm start avec notre port par défaut, si on veut autre chose faudra
// que l'appelant le précise avec du window.mathjax3Base ou mtgOptions.mathjax3Base
const mathJax3Uri = 'es5/tex-svg.js'
const mathJaxConfig = {
tex: {
inlineMath: [
['$', '$'],
['\\(', '\\)']
],
// packages: {'[+]': ['noerrors', 'color']}
packages: { '[+]': ['color', 'colortbl'] }
},
svg: {
// cf http://docs.mathjax.org/en/latest/options/output/svg.html#the-configuration-block
mtextInheritFont: false,
mtextFont: 'Roboto,"Noto Sans Arabic",sans-serif' // Deuxième police pour gérer l'arabe
},
options: {
ignoreHtmlClass: 'tex2jax_ignore',
processHtmlClass: 'tex2jax_process'
},
loader: {
// la conversion donnait ça
// load: ['input/tex', 'output/svg']
// mais ça marchait pas, c'est bcp mieux avec
load: ['[tex]/noerrors', '[tex]/color', '[tex]/colortbl']
},
// on ne veut pas de typeset du dom complet dès le chargement
// (comportement par défaut de es5/tex-svg.js)
startup: {
typeset: false
}
}
// si on fait deux appels très rapprochés à loadMathJax,
// on peut se retrouver dans le cas où le 2e retourne Promise.resolve() alors que MathJax n'est pas encore ready
let mathJaxLoadingPromise
/**
* Charge mathjax dans le <head> de la page courante (appelé seulement par addLatex)
* @param {string} [mathjax3Base] Un éventuel chemin vers le dossier de MathJax3 (qui devra contenir es5/tex-svg.js), sans slash de fin
* @returns {Promise<undefined>}
*/
function loadMathJax (mathjax3Base) {
// si on a déjà été appelé y'a rien à faire (c'est peut-être encore en cours ou déjà résolu)
if (mathJaxLoadingPromise) return mathJaxLoadingPromise
// faut le charger
mathJaxLoadingPromise = new Promise((resolve, reject) => {
// Depuis le 18/3/2025 on impose la fonte 'Roboto' sur tous les conteneurs de svg mtg32
// si qqun d'autre a déjà chargé MathJax (iep dans un nœud j3p précédent par ex)
// ça ne devrait pas être la peine de le refaire, mais c'est vraiment compliqué de s'assurer
// qu'il a les bons packages avec la bonne config.
// affecter `MathJax.config = mathJaxConfig` puis appeler `MathJax.startup.getComponents()`
// fonctionne, sauf s'il manque des packages (dans ce cas il faudrait ajouter du
// `\require(lePackage)` avant le code latex qui l'utilise)
// Cf commit f1c029df pour une version avec ce fonctionnement
// (ça fonctionnait pour les packages déjà chargé,
// mais l'ajout du package colortbl n'était pas pris en charge,
// ça donnait du `Undefined control sequence \columncolor`
// à la place d'afficher les commandes inconnues)
// => on recharge toujours
let base = mathjax3Base || getMathjaxBase()
if (!base.endsWith('/')) base += '/'
const mathJax3Url = base + mathJax3Uri
if (typeof MathJax === 'object') {
// si y'a déjà un script on le vire, sinon ça va pas forcément recharger
for (const elt of document.getElementsByTagName('script')) {
if (elt.src === mathJax3Url) {
elt.remove()
}
}
}
// faut charger MathJax
// on ajoute la résolution de la promesse quand il sera prêt
// cf http://docs.mathjax.org/en/latest/web/configuration.html#performing-actions-during-startup
const ready = () => {
// on vire le timeout
clearTimeout(timeout)
MathJax.startup.defaultReady()
MathJax.startup.promise.then(() => {
resolve()
})
} // ready
// on ne veut pas modifier notre objet mathJaxConfig
window.MathJax = {
...mathJaxConfig,
startup: { ...mathJaxConfig.startup, ready },
}
// chargement mathjax
const eltScript = document.createElement('script')
eltScript.type = 'text/javascript'
// faut préciser ça sinon ff peut râler (il doit y avoir un bout de code mathjax qui veut lire les cookies)
eltScript.crossOrigin = 'anonymous'
eltScript.src = mathJax3Url
const head = document.getElementsByTagName('head')[0]
// Modifs Yves pour résoudre le pb de chargement de MathJax en dev
eltScript.id = 'MathJax-script'
eltScript.async = true
// Fin essai Yves
head.appendChild(eltScript)
// on ajoute un timeout de chargement
const timeout = setTimeout(() => {
const error = Error(`Mathjax non chargé après ${loadDelay}s d’attente`)
// on ajoute ça pour que celui qui chopera cette erreur puisse l'afficher à l'utilisateur (et éventuellement éviter que ça remonte jusqu'à bugsnag)
error.userFriendly = true
reject(error)
}, loadDelay * 1000)
})
return mathJaxLoadingPromise
} // loadMathJax