Closed SoozaV closed 1 year ago
There was recently a question about using better-react-mathjax inside a SimpleMDE editor which ended successfully: https://github.com/fast-reflexes/better-react-mathjax/issues/35
I can try it out with tinymce and I'll let you know!
It wasn't too hard. Here is a code sandbox: https://codesandbox.io/s/better-react-mathjax-38-npbq6f
Since the content of TinyMCE is really displayed in an iFrame, we can't rely on the usual typesetting mechanism. The idea then is to do the typesetting manually instead. Because manually typesetting every time the content changes in the editor causes problems in the input / output (if we immediately convert MathJax entities on the fly, it will cause formatting issues and inputting is messed, try it yourself), my suggestion is to add a button which controls when the content is being typeset:
https://user-images.githubusercontent.com/2438128/215072932-bd9f5bb1-0ff7-4710-8dc8-cd9a4df11455.mov
The resulting code is:
import React, { useContext, useRef, useState, useEffect } from "react";
import { Editor } from "@tinymce/tinymce-react";
import { MathJaxBaseContext, MathJaxContext } from "better-react-mathjax";
const MathJaxEnabledEditor = () => {
const mj = useRef(null);
const mjContext = useContext(MathJaxBaseContext);
const [content, setContent] = useState(`<p>Initial text!</p>`);
useEffect(() => {
mjContext.promise.then((mathJaxObject) => {
mathJaxObject.startup.promise.then(() => {
mj.current = mathJaxObject;
});
});
}, []);
const typeset = () => {
setContent((previousContent) => {
if (mj.current) {
const container = document.createElement("div");
container.innerHTML = previousContent;
mj.current.typesetClear([container]);
mj.current.typeset([container]);
return container.innerHTML;
} else return previousContent;
});
};
return (
<Editor
value={content}
onEditorChange={(event) => setContent(event)}
init={{
setup: (editor) => {
editor.ui.registry.addButton("typeset", {
text: "Typeset",
onAction: typeset
});
},
height: 500,
menubar: false,
plugins: [
"advlist",
"autolink",
"lists",
"link",
"image",
"charmap",
"preview",
"anchor",
"searchreplace",
"visualblocks",
"code",
"fullscreen",
"insertdatetime",
"media",
"table",
"code",
"help",
"wordcount"
],
valid_elements: "*[*]",
toolbar:
"undo redo | typeset | blocks | " +
"bold italic forecolor | alignleft aligncenter " +
"alignright alignjustify | bullist numlist outdent indent | " +
"removeformat | help",
content_style:
"body { font-family:Helvetica,Arial,sans-serif; font-size:14px }"
}}
/>
);
};
export default function App() {
return (
<MathJaxContext
config={{
tex: {
inlineMath: [["$", "$"]]
}
}}
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"
>
<MathJaxEnabledEditor />
</MathJaxContext>
);
}
The strategy is to extract the MathJax object itself from better-react-mathjax
and then do typesetting manually.
The following steps are noteworthy:
MathJaxContext
. We can then use useContext
to extract MathJaxBaseContext
in our editor component.setup
property of the editor's init
property.init
property of the editor.valid_elements
in the init
property), otherwise the MathJax generated stuff will be removed by TinyMCE. You can either allow all elements or only those you want plus the elements that are added by MathJax. In the example, all elements are allowed.content
state. Avoid this by one of the way mentioned in the MathJax issue (here we explicitly import the tex-chtml.js
source but you can also configure MathJax in the way described to avoid the problem).Hope this solves your problems, it should work for Latex, AsciiMath and MathML just like normal.
Let me know how it goes :)
Thanks for your time and response @fast-reflexes, it looks really good (: I have a couple of questions:
\( LaTeX_math )\
. Because if I use something like: Cost: $10.°°. $ \fracc{10}{2}=5$ some other text
the result is incorrect.Thanks again dude. Regards!
You're welcome!
Yes you can pick any delimiters in Latex and AsciiMath but not in MathML:
No, that's not possible with the current setup since once you have typeset you have converted the input into a different format. In order to do what you ask for you would have to have two separate frames, one input frame and one output frame which shows the typeset (and stylized) result. There is not simple way to go from typeset content to MathJax input text either (afaik) so you can't really "untypeset" either.
You could perhaps experiment with attaching an attribute with the original input to the outermost element resulting from MathJax typesetting and then create some on-click handler that would replace the created element with the input code again when the element is clicked on. Or simply implement an untypeset button yourself by giving each created MathJax output a unique identifier and then store a mapping between these ids and the MathJax input so that you can easily replace every created MathJax output with its original input text. Don't think it's undoable but it requires some fiddling on your end.
The simplest way is to go for the two-frame solution with raw input text in one window and resulting output in the other.
I'd like to add better-react-mathjax to my project using
@tinymce/tinymce-react
editor, is there a proper way to achieve this? I tried using@dimakorotkov/tinymce-mathjax
plugin for tiny-mce but it only accepts LaTeX syntax.Regards.