MathJax API Changes
There are several MathJax API changes in this release, though most should not be breaking changes, as described below.
New Promise-Based Functions
Some actions in MathJax require loading extra code from an extension,
which is an asynchronous action, as the browser must wait for the file
to be loaded before it can use it. In MathJax v3, such asynchronous
actions were mostly associated with loading TeX extension packages,
and that could be avoided by pre-loading the extensions that are
needed, so that typesetting could be performed synchronously. In v4,
with fonts that have much greater coverage than in v3, some font data
may need to be loaded asynchronously as well, and that means that
typesetting may be asynchronous even if all the needed TeX extensions
are pre-loaded. As a result, the MathJax.typesetPromise()
function is more likely to be needed, and MathJax.typeset()
will only work if no font data needs to be loaded. This is discussed
in more detail in the MathJax v4.0 and Promises section.
Because of this greater need to handle asynchronous file loading,
several new functions have been added to the MathDocument
class to provide promise-based versions of the corresponding
synchronous calls. These include
mathDocument.convertPromise(),
mathDocument.renderPromise(), and
mathDocument.rerenderPromise(), which wrap the
mathDocument.convert(), mathDocument.render(),
and mathDocument.rerender() methods in the needed
mathjax.handleRetriesFor() call and return its promise.
This makes it easier to perform these actions when font data or TeX
extensions need to be loaded than having to use
mathjax.handlerRetriesFor() yourself.
In the past, promise-based functions, like
MathJax.typesetPromise(),
MathJax.tex2chtmlPromise(), etc., could not be called while
another one was currently in effect. That is, you needed to wait for
the promise from one such call to resolve before you could do the next
call, and the documentation encouraged you to use
MathJax.startup.promise to help chain these calls together.
In v4, these functions now use an internal promise (associated with
the MathDocument) to prevent more than one from running
concurrently, so these calls chain automatically. In particular, you
should no longer use MathJax.startup.promise yourself to
serialize your calls to these functions.
You may wish to use the new MathDocument promise to
synchronize other code with MathJax’s typesetting operations without
having to keep track of the promises returned by the various
promise-based functions. For this reason, MathJax provides a new
mathDocument.whenReady() method of the MathDocument
class. It takes a function as its argument, and performs that action
when its internal promise is resolved; that is, when any previous
promise-based typesetting or conversion actions complete. You can
think of mathDocument.whenReady() as queuing your action to
be performed whenever MathJax has finished anything that has been
queued previously.
The function you pass to mathDocument.whenReady() can
return a promise (if it starts any asynchronous actions of its own,
for example), in which case that promise must be fulfilled before any
further mathDocument.whenReady() actions will be
performed. For example
const doc = mathjax.document('', {});
doc.whenReady(() => console.log('A'));
doc.whenReady(() => {
return new Promise((ok, fail) => {
setTimeout(() => {
console.log('B');
ok();
}, 1000);
});
});
doc.whenReady(() => console.log('C'));
would print A to the developer console, then a second later print
B followed by C.
Changes to Speech Generation
In v3, the speech generation was performed within the
a11y/semantic-enrich component along with the semantic
enrichment of the internal MathML representation of the mathematical
expressions that it processes. In v4, these two functions have been
separated from each other, and the speech-generation functionality is
performed in a new a11y/speech component. This is
included in all the combined components, but can be loaded
individually by including a11y/speech in the load array of
the loader block of your MathJax configuration.
The section on Technical Details already mentions the new
MathJax.done() function that is used to shut down the
web-worker or node worker-thread that is created for speech
production. There is a corresponding new
mathDocument.done() method for the MathDocument
class that can be used in applications that don’t use the MathJax
Component framework, but rather call on MathJax modules directly.
Named Access to Input Jax
A MathDocument’s inputJax array included any input jax that
you have loaded. E.g., in the tex-mml-svg.js combined component,
it would contain entries for both the TeX and MathML input jax.
Because this is an array, it was not obvious in v3 which of the two
entries was which (you would need to check each entry’s name
property to see if it is the one you want). In this release, the
inputJax array also includes properties that point to the
input jax by name. That is, mathDocument.inputJax.tex will
point to the TeX input jax, if any, and similarly for
mathDocument.inputJax.mathml.
Change to ES6 Modules
The fact that the webpacked components are now ES6 files (see the
section on MathJax ES6 Modules) means that MathJax will no longer
run in IE11, so you should no longer include the polyfill.io
script that was recommended in the documentation for IE11 support.
The es5 directory has been removed from the MathJax distribution,
so the /es5 should be removed from the URL used to access
MathJax’s components. In the mathjax npm package, the files from
the es5 directory are now in the main directory, and for
mathjax-full (now called @mathjax/src), they are in the
generic bundle directory.
Changes to Configuration Options
The tex.skipHtmlTags configuration property now includes
select and option tags, since pop-up menu items can only
contain textual content, not other HTML tags.
In addition to the new configuration options discussed in other sections, there are several additional options available in this release:
Two new settings in the
options.menuOptions.settingsconfiguration object:showSREandshowLatex, which control whether to include the data attributes generated by the speech-rule-engine or thedata-latexattributes in MathML and SVG output in the Show Math As and Copy to Clipboard menus.mathml.verify.checkMathvariants, which controls whether the MathML input jax will check thatmathvariantattribute values are valid math variants and report an error if not. Invalidmathvariantvalues can cause MathJax to crash under some circumstances, so the default value of this option istrue, but this may cause current expressions with invalid math variant values that used to render to now show those nodes as having errors.
The lineWidth property of the Metrics object (used to
store information about the font metrics of the container surrounding
an expression) has been removed, as the line-breaking algorithm ended
up using the containerWidth property directly. That affects
functions that accept metric data as their inputs (such as
mathDocument.convert() and MathJax.tex2chtml()),
as these will no longer accept lineWidth in the options passed
to them.
Some backward-compatibility code in v3 has been removed; e.g., when
the tex.multlineWidth configuration option was moved to
tex.ams.multlineWidth in an earlier version, there was code to move
the old value to the new location, but that code has been removed in
v4.
Changes to the Code Base
The MathJax code base has undergone a major cleanup effort for this
release, using eslint and prettier to format the code
consistently, and new life-cycle scripts to perform these actions have
been added to the package.json file. Other modernizations, like
moving from String.substr() to String.substring() were
also performed.
A number of object name changes are listed in the Breaking Changes in V4 section.
Finally, MathJax’s test suite has been expanded to include more than
3,000 tests. We have full coverage for the TeX input jax and the
ts/util directories, but more tests need to be written for other
sections of the code base. This is an ongoing project that will take
time to complete.