Comment insérer une équation MathJax dans l'éditeur Quill ?

Introduction

Quill est proposé avec un module natif pour inserer des formules. Ce module utilise KaTeX pour afficher les équations. KaTeX est léger et rapide qe sui est très bien. Mais il est possible d'avoir besoin de fonctionnalités avancées comme générer les équations au format SVG. Cette page propose de créer un nouveau module pour Quill permettant d'insérer des équations MathJax.

Voici un apperçu du résultat :

MathJax

Pour utiliser MathJax, vous devez inclure la bibliothèque avec quelque chose comme :

<script type="text/javascript" id="MathJax-script" async
    src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.0.1/es5/latest?tex-mml-svg.js">
</script>

HTML

Voici le code HTML:

<button id="delta">Show delta in console</button>
<button id="mathjax">Add MathJax</button>
<div id="editor-container"></div>

le premier bouton sert à afficher le format Delta dans la console pour vérifier si la formule est correctement ajoutée dans le JSON. Le second bouton sert à ajouter une équation MathJax.

JavaScript: Quill

Commençons par configurer l'éditeur Quill :

var quill = new Quill('#editor-container', {
  placeholder: 'Click the MathJax button to insert a formula.',
  theme: 'snow',
  modules: {
    toolbar: [
        ['bold', 'italic', 'underline', 'strike'],
        ['link'],
        ['blockquote'],
        [{ 'list': 'ordered'}, { 'list': 'bullet' }],
        [{ 'script': 'sub'}, { 'script': 'super' }], 
        ['align', { 'align': 'center' }, { 'align': 'right' }, { 'align': 'justify' }]
    ]
  },
});

Référez-vous à la documentation de Quill pour plus de détails.

JavaScript: boutons

Interceptons maintenant les évenements liés aux boutons. Le premier bouton affiche le contenu du JSON Delta dans la console :

// Display the current delta content of the editor in the console
document.getElementById('delta').onclick = () => {
    console.log ( quill.getContents() );
}

Et maintenant le bouton pour l'équation MathJax :

// When the MathJax button is clicked, add a mathjax equation at the current selection
document.getElementById('mathjax').onclick = () => {
    var latex = prompt("Enter a LaTeX formula:", "e=mc^2");
    var range = quill.getSelection(true);
    quill.deleteText(range.index, range.length);
    quill.insertEmbed(range.index, 'mathjax', latex);
    quill.insertText(range.index + range.length + 1 , ' ');
    quill.setSelection(range.index + range.length + 1);
}

Le bouton MathJax affiche une boite de dialogue qui permet de saisir l'équation LaTeX. Ensuite, la fonction récupére et supprime la sélection courante avec d'y insérer l'équation MathJax suivie d'un espace. L'espace est optionnel, c'est une astuce pour éviter un comportement étrange du curseur dans Mozilla Firefox.

Le module MathJax

Le module MathJax hérite de la classe Embed. Le module est composé de trois méthodes :

Notons que la méthode tex2svg(latex) est une astuce pour palier à ce bug. Cette méthode pourra normalement être supprimée avec la prochaine release de MathJax (version 3.0.2).

// Import parchment and delta for creating custom module
const Parchment = Quill.imports.parchment;
const Delta = Quill.imports.delta;

// Extend the embed
class Mathjax extends Parchment.Embed {

    // Create node
    static create(value) 
    {
        const node = super.create(value);    
        if (typeof value === 'string') {
            node.innerHTML = "&#65279;" + this.tex2svg(value) + "&#65279;";
            node.contentEditable = 'false';
            node.setAttribute('data-value', value);         
        }
        return node;
    }

    // Return the attribute value (probably for Delta)
    static value(domNode) 
    {
        return domNode.getAttribute('data-value');
    }

    // Manually render a MathJax equation until version 3.0.2 is not released
    static tex2svg(latex)
    {
        // Create a hidden node and render the formula inside
        let MathJaxNode = document.createElement("DIV");
        MathJaxNode.style.visibility = "hidden";
        MathJaxNode.innerHTML = '\\(' + latex + '\\)';
        document.body.appendChild(MathJaxNode);
        MathJax.typeset();
        let svg = MathJaxNode.innerHTML;
        document.body.removeChild(MathJaxNode);
        return svg;
    }
    /*
    //  Never called ? See : https://stackoverflow.com/questions/60935100/html-method-in-quill-formula-js
    html() {
        const { mathjax } = this.value();
        return `<span>${mathjax}</span>`;
      }
     */
}

// Set module properties
Mathjax.blotName = 'mathjax';
Mathjax.className = 'ql-mathjax';
Mathjax.tagName = 'SPAN';

// Register the module
Quill.register(Mathjax);

Voici le résultat :

Toute proposition d'amélioration est la bienvenue ...

Voir aussi


Dernière mise à jour : 31/03/2020