Skip to content

HTML: Move MathJax packages and macros to its configuration - #2761

Closed
Alex-Jordan wants to merge 1 commit into
PreTeXtBook:masterfrom
Alex-Jordan:mathjax-macros
Closed

HTML: Move MathJax packages and macros to its configuration#2761
Alex-Jordan wants to merge 1 commit into
PreTeXtBook:masterfrom
Alex-Jordan:mathjax-macros

Conversation

@Alex-Jordan

Copy link
Copy Markdown
Contributor

We have long put author-demanded packages (cancel, etc) in a \require{} inside a block of math content. And long placed author-defined macros in the same block of math content.

This change moves all of that into the actual configuration block for MathJax. This was motivated by certain changes I'd like to make for WeBWorK, but just seems like the actual appropriate way to do all this. I don't believe it was possible with MJ2, so we did what we did. And held onto it. But with my testing of the sample article with both MJ3 and MJ4, this works.

This warrants lots of testing. I'll try other projects, other browsers, other devices, etc. But I wanted to post it here to see if there is interest in even more people testing. Marking this as draft until I can report more testing.

@rbeezer

rbeezer commented Jan 7, 2026

Copy link
Copy Markdown
Collaborator

I've looked at this closely. I can't check too much further right now, but I think we are unable to alter the MathJax configuration for Jupyter notebooks?

Can you test there? Yes, the conversion has been neglected, but no, it has not been abandoned. And there are reasons to move its necessary maintanence up in priority.

@rbeezer

rbeezer commented Jan 7, 2026

Copy link
Copy Markdown
Collaborator

I built the sample article with the Jupyter conversion stylesheet. (Requires using xsltproc.)

Section 7, "Mathematics" has its problems, but the cancel package is working.

JupyterLite looks like it may a good place to test viewing notebooks.

https://jupyterlite.github.io/demo/lab/index.html

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Does Section 7 have its problems with or without this change? Or only with this change?

The cancel extension is probably not what we should test with, because it is automatically included when the autoload extension is used. Any combined components configuration of MJ that includes TeX input jax loads autoload. So for example PTX uses tex-svg.js, tex-mml-chtml.js, or tex-chtml.js, and these all load cancel already.

I took a short look at Jupyter and how it seems to load MJ. It seems to use the mathjax-full combined component (available with MJ3, but not MJ4). Which I assume also loads autoload.

Is it up for consideration to keep things the same for Jupyter notebooks, while making a change like this for HTML? I can appreciate not wanting divergent MathJax details to maintain. It seems that the Jupyter MJ config is what it is though, and in one sense it's already divergent from the config used in PTX HTML. It would be a matter of still getting extensions to work in Jupyter.

I won't be fast with this, too many local issues with our term having started. But I think I'll post some sort of record of what I test as I go.

@rbeezer

rbeezer commented Jan 7, 2026 via email

Copy link
Copy Markdown
Collaborator

@rbeezer

rbeezer commented Jan 8, 2026 via email

Copy link
Copy Markdown
Collaborator

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Only one thing from -html was used in the jupyter conversion: the variable that glues all the packages together, each wrapped in \require(). So I moved it directly to the one place it is used in the jupyter conversion.

Tested again, and:

  • sample article Mathematics page is working
  • sample article Mathematics page is working with debug.mathjax4 yes
  • jupyter notebook works to the same degree, with or without this change (where it is not working is that if the SA source uses & instead of \amp, then that becomes & for Jupyter, and you end up seeing "amp;")

I noticed an MJ4 issue I will either post about, or post a fix for. It's an issue that is independent from this PR.

@Alex-Jordan
Alex-Jordan marked this pull request as ready for review February 16, 2026 04:50
@rbeezer

rbeezer commented Mar 31, 2026

Copy link
Copy Markdown
Collaborator

Looks like there needs to be a little more care with how broadly this is used.

Claude AI says:

Hard blockers — three files not updated

  1. xsl/pretext-runestone.xsl line 527 still references $latex-packages-mathjax, which this PR deletes. Any Runestone build using docinfo/math-package will fail or silently omit the content.
  2. xsl/support/extract-math.xsl line 135 has the same reference. SVG, MathML, Nemeth, and speech math extraction for projects using math packages will fail.
  3. xsl/pretext-smc.xsl line 351 calls <xsl:call-template name="latex-macros"/>, which this PR removes. SageMathCloud output breaks entirely.

There are also a couple of merge conflicts when I rebase on master. I know what it was that changed recently, but I can't be sure about how to resolve the conflicts. So I did not get very far in verifying the claims above. I did see that (1) seems correct in that the variable is not defined but is used. That should cause XSL to raise an error.

Sounds like it will be a while until you can get back to this. Maybe we will be on MJ 4 by then! Let's hope. I'm going to close this temporarily. You or I can re-open it when it can become active again.

@rbeezer rbeezer closed this Mar 31, 2026
@rbeezer rbeezer reopened this Jun 11, 2026
@rbeezer

rbeezer commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

We are on MathJax 4 now.

we are unable to alter the MathJax configuration for Jupyter notebooks?

I think you addressed this. But I have been working on teh Jupyter conversion and can verify that we still need \require there.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Closing and will pursue an alternate solution to the issue that originally provoked this.

@rbeezer

rbeezer commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

May have a solution. Hang tight.

@rbeezer

rbeezer commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

@Alex-Jordan — following up on "hang tight", since the iframe angle turns out not to need this change.

The question we chased: if macros live in a hidden math block rather than in the MathJax configuration, can something else on the page — an iframe in particular — still get at them? Short answer: yes, in their original form, without touching the configuration.

They are gone from the DOM after typesetting. Measured on a built sample-article page with MathJax 4.1.3: div#latex-macros ends up holding a single <mjx-container>, and textContent.trim() is empty. So anything that runs late finds nothing there, which is presumably the intuition behind moving them to configuration.

But MathJax keeps the source, and the page can keep it too. Two routes, both verified:

  1. Capture before typesetting, from startup.ready():

    window.MathJax = { startup: { ready() {
      window.PTX_MACROS = document.getElementById('latex-macros').textContent;
      MathJax.startup.defaultReady();
    }}};

    No MathJax internals, and the text arrives exactly as PreTeXt wrote it.

  2. Recover afterwards from the document's math list — every processed expression retains its source:

    for (const item of MathJax.startup.document.math)
      if (item.math.includes('\\newcommand')) return item.math;

    On the real sample article this returns the whole block, \require{cancel}\newcommand{\definiteintegral}..., 767 characters.

Installing them in an iframe is just typesetting them there — write the text into a hidden element in the iframe's document and typesetPromise() it. \newcommand definitions persist in that document's TeX state, so it is a one-time cost and everything typeset afterwards resolves. Handing them across by postMessage keeps this working for a sandboxed or cross-origin iframe; same-origin can reach in through contentDocument instead.

Three things worth knowing before anyone builds on this:

  • The two routes return different strings: the DOM gives \( ... \), while MathJax's stored source has the delimiters stripped — and undelimited text is not recognized as math, so the receiver has to put them back.
  • MathJax.startup.promise does not exist until the deferred MathJax script has loaded, so an ordinary body script throws on it. This bites in the iframe especially, since the parent's message can easily arrive first.
  • Unresolved macros do not raise a visible MathJax error; you get mangled text like \bvec +\vvec, \definiteintegral0⁢1⁢𝑥2⁢𝑥, so a broken frame can look merely ugly rather than obviously wrong.

None of this argues that macros-in-configuration is a bad idea on its own merits — it would certainly make retrieval trivial, since the config is just a readable object. It does mean an iframe wanting the author's macros is solvable today, with the current arrangement, and without the Runestone/extract-math/Jupyter complications this PR ran into.

A small self-contained demo of the whole thing — parent page, iframe, before-and-after — is coming; @rbeezer will follow with a link.

Claude Opus 5 (1M context), acting as a coding assistant for Rob Beezer

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

OK, I'll try these out. Thanks!

@rbeezer

rbeezer commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

More than you need. I can probably post source if it is necessary:

https://pretextbook.org/beta/20270728-macros/

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Closing in favor of #3147.

@Alex-Jordan
Alex-Jordan deleted the mathjax-macros branch August 17, 2026 23:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants