feat(mathjax): upgrade mathjax from v2 to v4 - #270
navinkarkera wants to merge 8 commits into
Conversation
|
Thanks for the pull request, @navinkarkera! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
60e1f68 to
56660c7
Compare
Migrate MathJax v2 Hub.Queue/Hub.getAllJax/Callback APIs to v3/v4 startup.promise/typesetPromise/typesetClear in Problem display.js, formula_equation_preview.js, and HtmlBlock init. - Problem.display.js: replace Hub.Queue(Typeset) with startup.promise.then(typesetPromise), Hub.getAllJax with startup.document.getMathItemsWithin, jax.root.toMathML with startup.toMML - Formula equation preview: replace Hub.signal.Interest/Queue/getAllJax with startup.promise.then(typesetClear; textContent; typesetPromise) - HtmlBlock: call typesetPromise on student_view load - Bump version to 0.17.1
Update display_spec.js and formula_equation_preview_spec.js MathJax mocks from v2 (Hub.Queue, Hub.getAllJax, Startup.signal.Interest, Callback.After, jax.root.toMathML) to v3/v4 (startup.promise synchronous mock, typesetClear, typesetPromise, startup.toMML, startup.document.getMathItemsWithin).
f271052 to
989ae32
Compare
|
@feanil @OmarIthawi Please review and merge this. |
|
@navinkarkera are the screenshots in the platform PR (openedx/openedx-platform#33555) is the same here? Why do we need two places to render the same equations? I understand this is an old decision, but it helps to know why. |
|
@OmarIthawi Some xblocks have been moved here from openedx-platform, including html and problem blocks that also render mathjax equations so we need to upgrade Mathjax configuration here. |
OmarIthawi
left a comment
There was a problem hiding this comment.
Thanks @navinkarkera. It's a pretty dense PR, reviewing it is hard but to be fair no objections from me here.
feanil
left a comment
There was a problem hiding this comment.
Did a quick Claud assisted review, just a couple of smaller issues but not to major.
| } | ||
| if (!mathSpan) { | ||
| mathSpan = document.createElement('span'); | ||
| mathSpan.className = 'mathjax-preview'; |
There was a problem hiding this comment.
ProblemBlockDisplay.css:1049-1051 styles this box with span.MathJax_CHTML, span.MathJax, span.MathJax_SVG, and line 1035 uses .MathJax_Display. v4 emits <mjx-container class="MathJax" jax="CHTML">, a custom element, so none of those match. MathJax_Display, MathJax_CHTML and MathJax_SVG appear zero times in the 4.1.2 bundle. The bordered grey box disappears from every formula-equation preview.
Both preview paths end with a mjx-container inside div.equation, this one and the <textline math="1"> path where display.js typesets into div#display_<id>.equation, so one selector covers both:
div.equation mjx-container[display="true"] { width: auto; }
div.equation mjx-container {
padding: 6px; min-width: 30px; border: 1px solid #e3e3e3;
border-radius: 4px; background: #f1f1f1; display: inline-block;
}display: inline-block moves onto that rule because div.equation span used to catch the v2 span wrappers and mjx-container is not a span.
| }; | ||
|
|
||
| // MathJax v3/v4 exposes readiness and typesetting through startup/typesetPromise. | ||
| const isMathJaxTypesetReady = () => typeof MathJax !== "undefined" && MathJax !== null |
There was a problem hiding this comment.
On a host still serving MathJax v2 these guards silently do nothing, so problem, html and discussion math stops rendering with nothing in the console.
Don't cut a release from this until openedx-platform#33555 has landed.
| || (/^\s*\\\[/.test(eqn) && /\\\]\s*$/.test(eqn)) | ||
| || (/^\s*\$\$/.test(eqn) && /\$\$\s*$/.test(eqn)) | ||
| || (/^\s*\$[^$]/.test(eqn) && /[^$]\$\s*$/.test(eqn)); | ||
| math.textContent = isTexDelimited ? eqn : `\`${eqn}\``; |
There was a problem hiding this comment.
This is the branch every existing <textline math="1"> problem takes, and it only renders if the host loaded input/asciimath. That jax is not in tex-mml-chtml.js, it is fetched on demand, so a host that omits it breaks every formula preview with no error. The risk section on this PR says the same thing.
Add a one-time console.warn when MathJax.startup is present but the AsciiMath input is not registered.
| expect(MathJax.typesetPromise).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("preserves backslash-delimited TeX without wrapping in AsciiMath backticks", function () { |
There was a problem hiding this comment.
Add the matching case for plain input. Nothing asserts that E=mc^2 becomes `E=mc^2`, and that is the branch all existing content goes through. The TeX branch is new behavior and has a test, the one carrying the back-compat does not.
| const dynEl = document.getElementById(`${element.id}_dynamath`); | ||
| if (dynEl) { dynEl.value = MathJax.startup.toMML(jax.root); } | ||
| } catch (exception) { | ||
| if (!exception.restart) { |
There was a problem hiding this comment.
exception.restart was a MathJax.Callback concept with no v4 equivalent, so this branch is dead. Drop the condition or drop the catch.
| return; | ||
| } | ||
| // Use getElementById so IDs with : or . do not break as CSS selectors. | ||
| const math = document.getElementById(`display_${elid}`) || document.getElementById(`${element.id}_preview`); |
There was a problem hiding this comment.
989ae32 removed formula-equation inputs from the keyup binding, so <id>_preview is unreachable here. Drop the fallback.
Summary
Upgrade MathJax from v2.7.5 → v4.1.2 across all XBlocks (problem, discussion, html). The v2
MathJax.Hub.Queue(...)/.Hub.Config()/.Hub.getAllJax()API is removed upstream. This PR ports all JS interactions to v4'sMathJax.typesetPromise()/MathJax.typesetClear()/MathJax.startup.promiseAPI.Co-authored by: GPT 5.5(xhigh)
Manual testing
See openedx/openedx-platform#33555
Risks
input/asciimathloaded. Its ownmathjax_include.jsis a guarded fallback (if (typeof MathJax === 'undefined')). If the host changes config without enabling AsciiMath input, formula preview (backtick-delimited syntax) breaks silently.noerrorspackage: Loaded in config; silently swallows MathJax rendering errors. Same behavior as v2, intentional.messageStyle: "none"not ported — v4 may show brief "Loading MathJax..." overlay. Cosmetic only.Merge checklist:
Check off if complete or not applicable: