Quill is proposed with a native module for inserting formulas. This module is based on KaTeX which is great, light and fast. But you may want some extra features like rendering SGV equations. This page proposes to create a new Quill module for inserting MathJax equations.
Here is a preview of the result:
To use MathJax, you need to include the MathJax library with something like:
<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>
Here is the HTML:
<button id="delta">Show delta in console</button>
<button id="mathjax">Add MathJax</button>
<div id="editor-container"></div>
The first button is for displaying the Delta content in the console to check if the formula is correctly added in the JSON. The second button is for adding a MathJax formula.
Let's start by configuring the Quill editor:
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' }]
]
},
});
Please see to the Quill documentation for more details.
Let's now catch the button's events. First the button for displaying the Delta content in the console:
// Display the current delta content of the editor in the console
document.getElementById('delta').onclick = () => {
console.log ( quill.getContents() );
}
And now the MathJax button:
// 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);
}
The MathJax button displays an input dialog box for entering the LaTeX formula. Then, it get and remove the current selection before inserting the MathJax equation followed by a space. The space is optional, it's a trick to avoid weird behaviors in Mozilla Firefox with the cursor.
The MathJax module extends the class Embed. The module is composed of 3 methods:
create(value) build and return the new node;value(domNode returns the data-value attribute, probably for generating the Delta content;tex2svg(latex) returns the LaTeX rendered into a SVG formula. Note that the method tex2svg(latex) is a trick to overcome this MathJax bug.
It should become unecessary in the next MathJax release (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 = "" + this.tex2svg(value) + "";
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);
Here is the result:
Any improvements are welcome...