Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MathJax 4: startup.promise resolves before DOM has time to update #3131

Open
salbeira opened this issue Nov 14, 2023 · 7 comments
Open

MathJax 4: startup.promise resolves before DOM has time to update #3131

salbeira opened this issue Nov 14, 2023 · 7 comments

Comments

@salbeira
Copy link

salbeira commented Nov 14, 2023

Issue Summary

Using startup.promise.then() to do post-typesetting adjustments to DOM elements, we mentioned that in MathJax 4 our document.querySelector()s of mjx elements retrieve no elements. Sometimes though, after several random reloads trying to find our error, we actually do get them. This lead us to believe that the promise resolves before the elements are added to the DOM or rather that the promise resolves before the DOM has had time to mention the update, as turning our post-typeset callbacks into renderActions actually tells us that the elements we are interested in are indeed part of the DOM. It feels like the querySelectors should be able to find the items, but they do not. It looks like the promise resolving our callback happens before the actual typeset is complete.

Steps to Reproduce:

  1. Add a callback to typeset.promise via then()
  2. Call something akin to document.querySelectorAll('mjx-container svg g[data-mml-node="mtable"]:first-of-type > g[data-mml-node="mtr"]')
  3. Get no results. Sometimes.

Technical details:

  • MathJax Version: 4.0
  • Client OS: Any (tested on Windows and Mac)
  • Browser: Chrome, Firefox version 119

I am using a MathJax configuration that is irrelevant to the issue.

and loading MathJax via

<script src="/self/hosted/mathjax4/tex-svg.js"></script>

Supporting information:

Here you have a minimal page you can test the issue with:

<!DOCTYPE html>
<html>
  <head>
    <title>Math Test</title>
    <script>

function turnRed() {
  console.log("Turn Red"); // called from startup.promise ... nothing happens
  for(const row of document.querySelectorAll('g[data-mml-node="mtable"] > g[data-mml-node="mtr"]')) {
    row.style.color = "red";
  }
}

window.MathJax = {
  startup: {
    ready: () => {
      window.MathJax.startup.defaultReady();
      window.MathJax.startup.promise.then(() => {
        turnRed();
      });
    }
  }
}
    </script>
    <script defer type="text/javascript" id="MathJax-script" defer src="/support/vendor/mathjax/tex-svg.js"></script>
  </head>
  <body>
    <h1>MathJax Testpage</h1>
    <button onclick="turnRed()">Turn Red</button>
    <span>$$\begin{eqnarray*}
  a &=& b \\
  a^2 &=& ab \\
  2a^2 &=& a^2 + ab \\
  2a^2-2ab &=& a^2 - ab \\
  2a(a-b) &=& a (a-b) \\
  2a &=& a \\
  2 &=& 1
  \end{eqnarray*}$$</span>
  </body>
</html>

What I expect to happen?

turnRed gets called after typesetting and turn each row of the equation red

What happens?

Nothing happens after typesetting. Pressing the "Turn Red" button after the page loaded and a bit of time passed does work though. Changing the callback from turnRed(); to setTimeout(turnRed, 1); also works.

@dpvc
Copy link
Member

dpvc commented Nov 14, 2023

When I substitute https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js for the source for MathJax in your example document, it works as expected for me (the math turns red without any other action.) This is in Firefox, Chrome, and Safari on MacOS.

Can you try that URL to see if that works for you?

@salbeira
Copy link
Author

salbeira commented Nov 14, 2023

Yes it works with Mathjax 3. It does not work in Mathjax 4.

Try with https://cdn.jsdelivr.net/npm/[email protected]/tex-svg.js. It does not work.

@dpvc
Copy link
Member

dpvc commented Nov 15, 2023

OOPS, sorry. Working on answering too many different issues!

It turns out that this is the same issue as #3130: the MathJax.startup.defaultPageReady() function mishandles one of the promises, and that leads to the MathJax.startup.promise being resolved too early. One solution would be to use

window.MathJax = {
  startup: {
    ready: () => {
      window.MathJax.startup.defaultReady();
      window.MathJax.startup.promise.then(() => {
        turnRed();
      });
    },
    pageReady() {
      const CONFIG = MathJax.config.startup;
      const output = MathJax.config.output;
      return (CONFIG.loadAllFontFiles && output.font ? output.font.loadDynamicFiles() : Promise.resolve())
        .then(CONFIG.typeset && MathJax.typesetPromise ?
              () => MathJax.startup.typesetPromise(CONFIG.elements) : Promise.resolve());
    }
  }
};

as the configuration (this in-lines the correct `defaultPageReady()` function). I've already made a PR for the correction that resolve this.

@salbeira
Copy link
Author

Thanks for the update. I guess we will just wait until you fixed this in an actual release instead of working around it ourselves just to remove the workaround at the next best moment.

@dpvc
Copy link
Member

dpvc commented Nov 15, 2023

OK, very good. We should have beta.5 soon and hope to have the official 4.0 release by the end of the year.

@salbeira
Copy link
Author

salbeira commented Feb 5, 2024

Is there any update on the roadmap? We are inclined to go with the workaround and stick with beta.4. Our goal is to decide upon a mathjax version before the end of the month.

@dpvc
Copy link
Member

dpvc commented Feb 6, 2024

As you can see, the release didn't happen as we had hoped. The updates to the expression explorer (that would lead to the beta.5 release) have taken longer than expected, and have push everything back. It is likely to still be several months before the official 4.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants