Skip to content

WeBWorK: refactor LaTeX macros - #3147

Open
Alex-Jordan wants to merge 2 commits into
PreTeXtBook:masterfrom
Alex-Jordan:mathjax-in-mathjax
Open

WeBWorK: refactor LaTeX macros#3147
Alex-Jordan wants to merge 2 commits into
PreTeXtBook:masterfrom
Alex-Jordan:mathjax-in-mathjax

Conversation

@Alex-Jordan

Copy link
Copy Markdown
Contributor

Before this change, PreTeXt produces PG problems where LaTeX macros are defined within the math block in which they are used. This may mean they are loaded repeatedly in an exercise. This adds clutter to the PG that PTX produces, but has been necessary for the embedded problems to use an author's macros (or \amp) in a WW exercise. All because the WW exercise is loaded inside an iframe. Also the PG problem files can't really be used in a WW problem set because hardcopy production will fail (because of the duplicate macro definitions).

The first change here is to stop writing LaTeX macro definitions in the .pg. Instead, for live embedding, the pretext-webwork.js extracts them from the ambient page's MathJax variable and then inserts them in the iframe's srcdoc.

And then what about the .pg files if they make their way onto an actual WW server? Well now the macros are written into the project's PG macros file, and all problems load that macro file. Custom LaTeX macros work in vanilla WeBWorK (both HTML and hardcopy rendering).

And then, most of the affected files here are the repo's webwork representations and pg files where LaTeX macros are now absent, and the project's PG macros file is included in the load.

Finally, for the three WW-using examples (showcase, minimal, and sample chapter) the PG macros file is updated to include the LaTeX macros. Since the macros are multiline expressions, I used perl's heredoc construction (<<'EOF') which looks a little awkward. For WW HTML output, the macros are put into a hidden div at the start of rendering. For WW PDF hardcopy output, we only want them loaded once, even if a problem set uses lots of problems from this project. So there is a dummy \ptxmacros command defined. We check if this has already been defined before trying to define all the custom macros.

Since the js is changed here, you will have to run jsbuild when testing this.

If this is approved, then 99% of the need for $b-human-readable in extract-pg.xsl is gone. And there can be a net cutting of 78 lines from that file. I could add that here as a second commit, or just wait and make a separate PR later.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Something is wrong with this. I think it is because I left out changes that I thought had only to do with my last paragraph. I'm converting to draft until I work it out.

@Alex-Jordan
Alex-Jordan marked this pull request as draft August 16, 2026 19:35
@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

OK, tested, working, and force pushed. I had uncommitted changes that mostly should come after this to eradicate human-readable.

@rbeezer

rbeezer commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Looking good. A few boo-boos coming from Claude Code. With those patched up (and a force-push) we should be good. Can you put code changes on one commit, and all the re-generated stuff onto a separate commit? Thanks.

@rbeezer

rbeezer commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

This is the right direction. Moving the macros out of every math block and into the project's PG macro file is a clear improvement, and the \ifdefined\ptxmacros construction is a tidy answer to the duplicate-definition problem in hardcopy.

I checked the regeneration rather than assume it: running -c pg-macros from this branch reproduces all three committed .pl files byte-identically — showcase, minimal, and sample-chapter. Commit message and whitespace are clean, and js/dist being absent is correct for a contributor; that is a maintainer step.

Two things in the four new lines of JavaScript, both of which I confirmed in a browser rather than reasoned about.

window.parent.MathJax throws when the page is embedded

for (const item of window.parent.MathJax.startup.document.math)

pretext-webwork.js runs in the PreTeXt page itself — the page that holds the macros — so this wants to be window.MathJax. It works at present only because for a page that is not embedded, window.parent === window.

PreTeXt offers an "embed this page" feature that produces <iframe src="https://…/page.html"> for use on another site. I built that arrangement locally, two origins on separate ports, and ran this exact access from the embedded page:

DOMException: Failed to read a named property 'MathJax' from 'Window':
Blocked a frame with origin "http://127.0.0.1:8802" from access...

Nothing tests for the property before reading it, and the read sits inside handleWW, so the exception ends the function and the WeBWorK exercise does not render at all. The same happens, less dramatically, on any host page that simply has no MathJax. Worth checking for its presence before use whichever window it reads from.

The injected span's attributes are malformed

'<span type="class="process-math" style="display:none;">'

Parsing that with DOMParser gives three attributes — type="class=", process-math"="" and style="display:none;" — and an empty classList. The intended class="process-math" never arrives; the stray type=" looks like a slip of the fingers.

It very likely works today, because MathJax applies processHtmlClass only inside a region marked with ignoreHtmlClass, and the iframe configuration sets no such class, so the span is typeset regardless. But that is luck rather than design — the same configuration names process-math a few lines above, at options.processHtmlClass — and if an ignore class ever appears, the macros stop reaching the iframe silently, with math simply rendering wrong.

A question about ordering

MathJax.startup.document.math fills only once MathJax has found the page's math. If handleWW can run before that has happened, latexmacros comes back empty and the macros silently never reach the iframe. How is the ordering assured?

(The includes('\\newcommand') test is broader than the intent, but a \newcommand anywhere other than the macro block would be a misuse of PreTeXt in the first place, so this is theoretical.)

Smaller notes

  • not(normalize-space(@mathjax-name)) = '' in the new $latex-packages has its closing parenthesis one place early: it compares a boolean against a string, and XPath converts '' to false, so it happens to give the right answer. It is copied from pretext-html.xsl and pretext-markdown.xsl, so it is inherited rather than introduced — but this makes a third instance of an expression that reads as the opposite of what it does.
  • The sample-chapter.ptx change from } % comments get stripped to }% comments get stripped is cosmetic. I generated the macro file both ways; the only difference is a trailing space on that line in the .pl, harmless to MathJax and to LaTeX. The original spacing is arguably the more realistic author input for a line whose own comment advertises that comments get stripped.
  • The new $latex-macros shadows the one in pretext-common.xsl and omits \lt/\gt, exactly as its comment explains. I checked whether that reaches the other template this stylesheet applies: it does not, since latex-image-preamble reads $docinfo/latex-image-preamble directly, and nothing else imports this stylesheet. Contained and deliberate.

The branch is 15 commits behind master and will want a rebase.

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

@rbeezer

rbeezer commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

You must not have liked something about the MathJax introspection idea on #2761. Curious about what that was?

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

Thanks, I will update this soon, maybe late tonight.

You must not have liked something about the MathJax introspection idea on #2761. Curious about what that was?

There are two items at this comment. And what is happening here in this PR is my understanding of the second item. That's the one I would call "MathJax introspection" since it looks into the active MathJax JSON. I went with that one simply because I understood that one first, before I grokked what option 1 was saying. But option 1 could work too. It plants the original macro definitions into the window's variables, separately from MathJax (but has MathJax do the planting). Should I switch? I don't mind switching if you have a preference.

@rbeezer

rbeezer commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the reply. No need to switch, its your call. Especially since this is contained to MathJax stuff.

Just trying to stay in the know about what decisions we make any why. Carry on.

@Alex-Jordan

Copy link
Copy Markdown
Contributor Author

OK, force pushed. Ready to review again.

  1. I changed to Claude's first suggestion. So PTX_MACROS is now a variable in a pretext page's window. Possibly useful to something else someday.
  2. Fixed the first two big things Claude found in the above review.
  3. The ordering concern is still there, I think, but I don't see it as realistic that a user would activate a WeBWorK exercise before Mathjax has even done its startup. Probably switching to Claude's first suggestion has made this even less likely.
  4. In "Smaller notes", I corrected the first item as far as this PR goes. It is indeed a mistake copied from some other place, and perhaps you would like to separately correct those other two instances.
  5. I reverted the change to sample-chapter.xml where } % comments get stripped was being changed to }% comments get stripped. The reason I had that is because in the new .pl files, the trailing space after the } was showing up. Perhaps (and perhaps not) you would like to look into the latex-macro-first-percent template in -common. Maybe (and maybe not) it should not only strip the first % and content that follows, but also whitespace preceding the %. But then maybe not if only whitespace precedes the %. The more I write about it, the less worthwhile it seems. And the trailing spaces that result are just things to live with.
  6. I'm not 100% sure that I understand Claude's 3rd "Smaller note" but I think it is just confirming that it wondered about an issue, looked into it, and found there is no issue.

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