@jupyterlab/mathjax-extension 4.7.0-alpha.0 → 4.7.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -4,11 +4,36 @@
4
4
  */
5
5
  import type { JupyterFrontEndPlugin } from '@jupyterlab/application';
6
6
  import { ILatexTypesetter } from '@jupyterlab/rendermime';
7
+ import type { IRenderMime } from '@jupyterlab/rendermime';
7
8
  import type { MathDocument } from 'mathjax-full/js/core/MathDocument';
8
9
  /**
9
10
  * The MathJax Typesetter.
10
11
  */
11
12
  export declare class MathJaxTypesetter implements ILatexTypesetter {
13
+ /**
14
+ * Construct a new MathJax typesetter.
15
+ *
16
+ * @param options - Options describing how math is recognized in the source
17
+ * text (see {@link MathJaxTypesetter.IOptions}).
18
+ */
19
+ constructor(options?: MathJaxTypesetter.IOptions);
20
+ /**
21
+ * The options describing how math is recognized in the source text.
22
+ *
23
+ * Exposed so that the Markdown pre-processor (`removeMath`) and this
24
+ * typesetter agree on whether a single `$` introduces inline math.
25
+ */
26
+ readonly mathParseOptions: IRenderMime.ILatexTypesetter.IMathParseOptions;
27
+ /**
28
+ * Create a new MathJax typesetter with the given parse options.
29
+ *
30
+ * Options which are not given are inherited from this typesetter; this
31
+ * typesetter is left unchanged. The underlying MathDocument is shared with
32
+ * any other typesetter using the same options, so this is cheap to call.
33
+ *
34
+ * @param options - The parse options to apply.
35
+ */
36
+ withParseOptions(options: IRenderMime.ILatexTypesetter.IMathParseOptions): MathJaxTypesetter;
12
37
  protected _ensureInitialized(): Promise<void>;
13
38
  /**
14
39
  * Get an instance of the MathDocument object.
@@ -21,6 +46,16 @@ export declare class MathJaxTypesetter implements ILatexTypesetter {
21
46
  protected _initialized: boolean;
22
47
  protected _mathDocument: MathDocument<any, any, any>;
23
48
  }
49
+ /**
50
+ * A namespace for `MathJaxTypesetter` statics.
51
+ */
52
+ export declare namespace MathJaxTypesetter {
53
+ /**
54
+ * Options for constructing a {@link MathJaxTypesetter}.
55
+ */
56
+ interface IOptions extends IRenderMime.ILatexTypesetter.IMathParseOptions {
57
+ }
58
+ }
24
59
  /**
25
60
  * The MathJax extension.
26
61
  */
package/lib/index.js CHANGED
@@ -5,7 +5,6 @@
5
5
  * @packageDocumentation
6
6
  * @module mathjax-extension
7
7
  */
8
- import { PromiseDelegate } from '@lumino/coreutils';
9
8
  import { ILatexTypesetter } from '@jupyterlab/rendermime';
10
9
  import { ITranslator, nullTranslator } from '@jupyterlab/translation';
11
10
  var CommandIDs;
@@ -23,12 +22,36 @@ var CommandIDs;
23
22
  * The MathJax Typesetter.
24
23
  */
25
24
  export class MathJaxTypesetter {
26
- constructor() {
25
+ /**
26
+ * Construct a new MathJax typesetter.
27
+ *
28
+ * @param options - Options describing how math is recognized in the source
29
+ * text (see {@link MathJaxTypesetter.IOptions}).
30
+ */
31
+ constructor(options = {}) {
32
+ var _a;
27
33
  this._initialized = false;
34
+ this.mathParseOptions = {
35
+ dollarInlineMath: (_a = options.dollarInlineMath) !== null && _a !== void 0 ? _a : true
36
+ };
37
+ }
38
+ /**
39
+ * Create a new MathJax typesetter with the given parse options.
40
+ *
41
+ * Options which are not given are inherited from this typesetter; this
42
+ * typesetter is left unchanged. The underlying MathDocument is shared with
43
+ * any other typesetter using the same options, so this is cheap to call.
44
+ *
45
+ * @param options - The parse options to apply.
46
+ */
47
+ withParseOptions(options) {
48
+ return new MathJaxTypesetter(Private.mergeParseOptions(this.mathParseOptions, options));
28
49
  }
29
50
  async _ensureInitialized() {
30
51
  if (!this._initialized) {
31
- this._mathDocument = await Private.ensureMathDocument();
52
+ this._mathDocument = await Private.ensureMathDocument(this.mathParseOptions.dollarInlineMath === false
53
+ ? Private.INLINE_MATH_WITHOUT_DOLLAR
54
+ : Private.DEFAULT_INLINE_MATH);
32
55
  this._initialized = true;
33
56
  }
34
57
  }
@@ -51,8 +74,15 @@ export class MathJaxTypesetter {
51
74
  return;
52
75
  }
53
76
  this._mathDocument.options.elements = [node];
77
+ // `clear()` empties the document's math list before rendering, so that
78
+ // memory retained per math expression (most notably the compiled internal
79
+ // MathML tree) is bounded by the last typeset call rather than growing
80
+ // with the total amount of math on the page.
81
+ // This is also why we need to store the sources manually -
82
+ // we cannot extract them from MathJax state after `clear()`.
54
83
  this._mathDocument.clear().render();
55
84
  delete this._mathDocument.options.elements;
85
+ Private.recordTexSources(this._mathDocument);
56
86
  Private.hardenAnchorLinks(node);
57
87
  }
58
88
  }
@@ -69,6 +99,16 @@ const mathJaxPlugin = {
69
99
  const typesetter = new MathJaxTypesetter();
70
100
  app.commands.addCommand(CommandIDs.copy, {
71
101
  execute: async () => {
102
+ // Find the math expression the context menu was opened on; this works
103
+ // across all typesetter instances (e.g. ones configured with
104
+ // different delimiters), unlike the fallback below which reflects
105
+ // whichever expression the default typesetter processed last.
106
+ const root = app.contextMenuHitTest(node => node.classList.contains('MathJax'));
107
+ const tex = root ? Private.getTexSource(root) : undefined;
108
+ if (tex !== undefined) {
109
+ await navigator.clipboard.writeText(tex);
110
+ return;
111
+ }
72
112
  const md = await typesetter.mathDocument();
73
113
  const oJax = md.outputJax;
74
114
  await navigator.clipboard.writeText(oJax.math.math);
@@ -83,15 +123,20 @@ const mathJaxPlugin = {
83
123
  });
84
124
  app.commands.addCommand(CommandIDs.scale, {
85
125
  execute: async (args) => {
86
- const md = await typesetter.mathDocument();
87
126
  const scale = args['scale'] || 1.0;
88
- md.outputJax.options.scale = scale;
89
- md.rerender();
90
- // Harden only the re-rendered anchors
91
- for (const math of md.math) {
92
- const root = math.typesetRoot;
93
- if (root) {
94
- Private.hardenAnchorLinks(root);
127
+ // Scale all documents so that every typesetter instance (e.g. ones
128
+ // configured with different delimiters) is affected alike; remember
129
+ // the scale so that documents created later inherit it too.
130
+ Private.setScale(scale);
131
+ for (const md of await Private.getMathDocuments()) {
132
+ md.outputJax.options.scale = scale;
133
+ md.rerender();
134
+ // Harden only the re-rendered anchors
135
+ for (const math of md.math) {
136
+ const root = math.typesetRoot;
137
+ if (root) {
138
+ Private.hardenAnchorLinks(root);
139
+ }
95
140
  }
96
141
  }
97
142
  },
@@ -119,52 +164,166 @@ export default mathJaxPlugin;
119
164
  */
120
165
  var Private;
121
166
  (function (Private) {
167
+ /**
168
+ * The default delimiters for inline math.
169
+ */
170
+ Private.DEFAULT_INLINE_MATH = [
171
+ ['$', '$'],
172
+ ['\\(', '\\)']
173
+ ];
174
+ /**
175
+ * Merge parse options, where an `undefined` value in `overrides` means
176
+ * "keep the current value" rather than "reset to the default".
177
+ */
178
+ function mergeParseOptions(base, overrides) {
179
+ const merged = { ...base };
180
+ for (const [key, value] of Object.entries(overrides)) {
181
+ if (value !== undefined) {
182
+ merged[key] = value;
183
+ }
184
+ }
185
+ return merged;
186
+ }
187
+ Private.mergeParseOptions = mergeParseOptions;
188
+ /**
189
+ * The inline math delimiters with the single `$` pair removed, so that `$`
190
+ * is rendered literally.
191
+ */
192
+ Private.INLINE_MATH_WITHOUT_DOLLAR = [
193
+ ['\\(', '\\)']
194
+ ];
195
+ /**
196
+ * Load the MathJax modules and register the document handler.
197
+ *
198
+ * The heavy dynamic imports and the (global, one-time) handler registration
199
+ * are shared across all typesetters; only the per-instance document is built
200
+ * separately in {@link createMathDocument}. The returned bundle's type is
201
+ * inferred so no MathJax types need to be imported explicitly.
202
+ */
203
+ async function loadModules() {
204
+ void import('mathjax-full/js/input/tex/require/RequireConfiguration');
205
+ const [{ mathjax }, { CHTML }, { TeX }, { TeXFont }, { AllPackages }, { SafeHandler }, { HTMLHandler }, { browserAdaptor }, { AssistiveMmlHandler }] = await Promise.all([
206
+ import('mathjax-full/js/mathjax'),
207
+ import('mathjax-full/js/output/chtml'),
208
+ import('mathjax-full/js/input/tex'),
209
+ import('mathjax-full/js/output/chtml/fonts/tex'),
210
+ import('mathjax-full/js/input/tex/AllPackages'),
211
+ import('mathjax-full/js/ui/safe/SafeHandler'),
212
+ import('mathjax-full/js/handlers/html/HTMLHandler'),
213
+ import('mathjax-full/js/adaptors/browserAdaptor'),
214
+ import('mathjax-full/js/a11y/assistive-mml')
215
+ ]);
216
+ mathjax.handlers.register(AssistiveMmlHandler(SafeHandler(new HTMLHandler(browserAdaptor()))));
217
+ return { mathjax, CHTML, TeX, TeXFont, AllPackages };
218
+ }
122
219
  let _loading = null;
123
- async function ensureMathDocument() {
220
+ /**
221
+ * Ensure the MathJax modules are loaded exactly once per page.
222
+ */
223
+ function ensureMathModules() {
124
224
  if (!_loading) {
125
- _loading = new PromiseDelegate();
126
- void import('mathjax-full/js/input/tex/require/RequireConfiguration');
127
- const [{ mathjax }, { CHTML }, { TeX }, { TeXFont }, { AllPackages }, { SafeHandler }, { HTMLHandler }, { browserAdaptor }, { AssistiveMmlHandler }] = await Promise.all([
128
- import('mathjax-full/js/mathjax'),
129
- import('mathjax-full/js/output/chtml'),
130
- import('mathjax-full/js/input/tex'),
131
- import('mathjax-full/js/output/chtml/fonts/tex'),
132
- import('mathjax-full/js/input/tex/AllPackages'),
133
- import('mathjax-full/js/ui/safe/SafeHandler'),
134
- import('mathjax-full/js/handlers/html/HTMLHandler'),
135
- import('mathjax-full/js/adaptors/browserAdaptor'),
136
- import('mathjax-full/js/a11y/assistive-mml')
137
- ]);
138
- mathjax.handlers.register(AssistiveMmlHandler(SafeHandler(new HTMLHandler(browserAdaptor()))));
139
- class EmptyFont extends TeXFont {
140
- }
141
- EmptyFont.defaultFonts = {};
142
- const chtml = new CHTML({
143
- // Override dynamically generated fonts in favor of our font css
144
- font: new EmptyFont()
145
- });
146
- const tex = new TeX({
147
- packages: AllPackages.concat('require'),
148
- inlineMath: [
149
- ['$', '$'],
150
- ['\\(', '\\)']
151
- ],
152
- displayMath: [
153
- ['$$', '$$'],
154
- ['\\[', '\\]']
155
- ],
156
- processEscapes: true,
157
- processEnvironments: true
158
- });
159
- const mathDocument = mathjax.document(window.document, {
160
- InputJax: tex,
161
- OutputJax: chtml
162
- });
163
- _loading.resolve(mathDocument);
225
+ _loading = loadModules();
164
226
  }
165
- return _loading.promise;
227
+ return _loading;
228
+ }
229
+ Private.ensureMathModules = ensureMathModules;
230
+ const _documents = new Map();
231
+ /**
232
+ * Get (or lazily create) the MathDocument for the given inline delimiters.
233
+ *
234
+ * Building a MathDocument costs on the order of ~5 ms and retains memory for
235
+ * the lifetime of the page. Caching one document per distinct delimiter
236
+ * configuration keeps that bounded, so constructing many typesetters with
237
+ * the same configuration (for example one per markdown cell across a large
238
+ * notebook) reuses a single document instead of multiplying the time and
239
+ * memory cost.
240
+ */
241
+ function ensureMathDocument(inlineMath) {
242
+ const key = JSON.stringify(inlineMath);
243
+ let document = _documents.get(key);
244
+ if (!document) {
245
+ document = createMathDocument(inlineMath);
246
+ _documents.set(key, document);
247
+ }
248
+ return document;
166
249
  }
167
250
  Private.ensureMathDocument = ensureMathDocument;
251
+ /**
252
+ * Get all MathDocuments created so far, so that document-wide commands
253
+ * (e.g. scaling) can operate across every delimiter configuration in use.
254
+ */
255
+ function getMathDocuments() {
256
+ return Promise.all(_documents.values());
257
+ }
258
+ Private.getMathDocuments = getMathDocuments;
259
+ let _scale = null;
260
+ /**
261
+ * Remember the requested scale factor, so that MathDocuments created later
262
+ * (e.g. on first use of a typesetter with a different delimiter
263
+ * configuration) start at the user's chosen scale rather than the default.
264
+ */
265
+ function setScale(scale) {
266
+ _scale = scale;
267
+ }
268
+ Private.setScale = setScale;
269
+ const _texSourceByRoot = new WeakMap();
270
+ /**
271
+ * Record the TeX source of each math expression typeset by `document`,
272
+ * keyed by its rendered container element.
273
+ *
274
+ * A MathDocument only retains the math items from its most recent
275
+ * `render()` call (each `typeset()` starts with `clear()`), so the source
276
+ * of earlier expressions must be captured here for the copy command to
277
+ * find the expression that was actually clicked. Unlike retaining the math
278
+ * items themselves, this only keeps the source string, and the `WeakMap`
279
+ * lets it be reclaimed as soon as the rendered node is garbage-collected.
280
+ */
281
+ function recordTexSources(document) {
282
+ for (const item of document.math) {
283
+ if (item.typesetRoot) {
284
+ _texSourceByRoot.set(item.typesetRoot, item.math);
285
+ }
286
+ }
287
+ }
288
+ Private.recordTexSources = recordTexSources;
289
+ /**
290
+ * Get the TeX source of the math expression rendered in `root`
291
+ * (a `mjx-container` element), if known.
292
+ */
293
+ function getTexSource(root) {
294
+ return _texSourceByRoot.get(root);
295
+ }
296
+ Private.getTexSource = getTexSource;
297
+ /**
298
+ * Build a MathDocument configured with the given inline delimiters.
299
+ */
300
+ async function createMathDocument(inlineMath) {
301
+ const { mathjax, CHTML, TeX, TeXFont, AllPackages } = await ensureMathModules();
302
+ class EmptyFont extends TeXFont {
303
+ }
304
+ EmptyFont.defaultFonts = {};
305
+ const chtml = new CHTML({
306
+ // Override dynamically generated fonts in favor of our font css
307
+ font: new EmptyFont()
308
+ });
309
+ if (_scale !== null) {
310
+ chtml.options.scale = _scale;
311
+ }
312
+ const tex = new TeX({
313
+ packages: AllPackages.concat('require'),
314
+ inlineMath,
315
+ displayMath: [
316
+ ['$$', '$$'],
317
+ ['\\[', '\\]']
318
+ ],
319
+ processEscapes: true,
320
+ processEnvironments: true
321
+ });
322
+ return mathjax.document(window.document, {
323
+ InputJax: tex,
324
+ OutputJax: chtml
325
+ });
326
+ }
168
327
  /**
169
328
  * Utility function to harden anchor links in a given element
170
329
  */
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,2DAA2D;AAC3D,uDAAuD;AACvD;;;GAGG;AAOH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAI1D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAItE,IAAU,UAAU,CASnB;AATD,WAAU,UAAU;IAClB;;OAEG;IACU,eAAI,GAAG,mBAAmB,CAAC;IACxC;;OAEG;IACU,gBAAK,GAAG,eAAe,CAAC;AACvC,CAAC,EATS,UAAU,KAAV,UAAU,QASnB;AAQD;;GAEG;AACH,MAAM,OAAO,iBAAiB;IAC5B;;;;;OAKG;IACH,YAAY,UAAsC,EAAE;;QA0E1C,iBAAY,GAAY,KAAK,CAAC;QAzEtC,IAAI,CAAC,gBAAgB,GAAG;YACtB,gBAAgB,EAAE,MAAA,OAAO,CAAC,gBAAgB,mCAAI,IAAI;SACnD,CAAC;IACJ,CAAC;IAUD;;;;;;;;OAQG;IACH,gBAAgB,CACd,OAAuD;QAEvD,OAAO,IAAI,iBAAiB,CAC1B,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAC1D,CAAC;IACJ,CAAC;IAES,KAAK,CAAC,kBAAkB;QAChC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,GAAG,MAAM,OAAO,CAAC,kBAAkB,CACnD,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,KAAK,KAAK;gBAC9C,CAAC,CAAC,OAAO,CAAC,0BAA0B;gBACpC,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAChC,CAAC;YACF,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,IAAiB;QAC7B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACjB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,uEAAuE;QACvE,0EAA0E;QAC1E,uEAAuE;QACvE,6CAA6C;QAC7C,2DAA2D;QAC3D,6DAA6D;QAC7D,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC3C,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC7C,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;CAIF;AAeD;;GAEG;AACH,MAAM,aAAa,GAA4C;IAC7D,EAAE,EAAE,sCAAsC;IAC1C,WAAW,EAAE,yDAAyD;IACtE,QAAQ,EAAE,gBAAgB;IAC1B,QAAQ,EAAE,CAAC,WAAW,CAAC;IACvB,QAAQ,EAAE,CAAC,GAAoB,EAAE,UAA8B,EAAE,EAAE;QACjE,MAAM,KAAK,GAAG,CAAC,UAAU,aAAV,UAAU,cAAV,UAAU,GAAI,cAAc,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAE3C,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE;YACvC,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,sEAAsE;gBACtE,6DAA6D;gBAC7D,kEAAkE;gBAClE,8DAA8D;gBAC9D,MAAM,IAAI,GAAG,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CACzC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CACnC,CAAC;gBACF,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC1D,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;oBACtB,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACzC,OAAO;gBACT,CAAC;gBACD,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC,YAAY,EAAE,CAAC;gBAC3C,MAAM,IAAI,GAAQ,EAAE,CAAC,SAAS,CAAC;gBAC/B,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtD,CAAC;YACD,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC;YACrC,WAAW,EAAE;gBACX,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,EAAE;iBACf;aACF;SACF,CAAC,CAAC;QAEH,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE;YACxC,OAAO,EAAE,KAAK,EAAE,IAAuB,EAAE,EAAE;gBACzC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC;gBACnC,mEAAmE;gBACnE,oEAAoE;gBACpE,4DAA4D;gBAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACxB,KAAK,MAAM,EAAE,IAAI,MAAM,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;oBAClD,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;oBACnC,EAAE,CAAC,QAAQ,EAAE,CAAC;oBAEd,sCAAsC;oBACtC,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;wBAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAiC,CAAC;wBACpD,IAAI,IAAI,EAAE,CAAC;4BACT,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;wBAClC,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,KAAK,EAAE,IAAI,CAAC,EAAE,CACZ,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC;gBAC1B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YAC3D,WAAW,EAAE;gBACX,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;4BACd,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,wCAAwC,CAAC;yBAChE;qBACF;iBACF;aACF;SACF,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,SAAS,EAAE,IAAI;CAChB,CAAC;AAEF,eAAe,aAAa,CAAC;AAE7B;;GAEG;AACH,IAAU,OAAO,CA4NhB;AA5ND,WAAU,OAAO;IACf;;OAEG;IACU,2BAAmB,GAAuB;QACrD,CAAC,GAAG,EAAE,GAAG,CAAC;QACV,CAAC,KAAK,EAAE,KAAK,CAAC;KACf,CAAC;IAEF;;;OAGG;IACH,SAAgB,iBAAiB,CAC/B,IAAoD,EACpD,SAAyD;QAEzD,MAAM,MAAM,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;QACpD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACrD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACtB,CAAC;QACH,CAAC;QACD,OAAO,MAAwD,CAAC;IAClE,CAAC;IAXe,yBAAiB,oBAWhC,CAAA;IAED;;;OAGG;IACU,kCAA0B,GAAuB;QAC5D,CAAC,KAAK,EAAE,KAAK,CAAC;KACf,CAAC;IAEF;;;;;;;OAOG;IACH,KAAK,UAAU,WAAW;QACxB,KAAK,MAAM,CAAC,wDAAwD,CAAC,CAAC;QAEtE,MAAM,CACJ,EAAE,OAAO,EAAE,EACX,EAAE,KAAK,EAAE,EACT,EAAE,GAAG,EAAE,EACP,EAAE,OAAO,EAAE,EACX,EAAE,WAAW,EAAE,EACf,EAAE,WAAW,EAAE,EACf,EAAE,WAAW,EAAE,EACf,EAAE,cAAc,EAAE,EAClB,EAAE,mBAAmB,EAAE,CACxB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACpB,MAAM,CAAC,yBAAyB,CAAC;YACjC,MAAM,CAAC,8BAA8B,CAAC;YACtC,MAAM,CAAC,2BAA2B,CAAC;YACnC,MAAM,CAAC,wCAAwC,CAAC;YAChD,MAAM,CAAC,uCAAuC,CAAC;YAC/C,MAAM,CAAC,qCAAqC,CAAC;YAC7C,MAAM,CAAC,2CAA2C,CAAC;YACnD,MAAM,CAAC,yCAAyC,CAAC;YACjD,MAAM,CAAC,oCAAoC,CAAC;SAC7C,CAAC,CAAC;QAEH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CACvB,mBAAmB,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CACpE,CAAC;QAEF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IACvD,CAAC;IAED,IAAI,QAAQ,GAA0C,IAAI,CAAC;IAE3D;;OAEG;IACH,SAAgB,iBAAiB;QAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC3B,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IALe,yBAAiB,oBAKhC,CAAA;IAED,MAAM,UAAU,GAAG,IAAI,GAAG,EAAgD,CAAC;IAE3E;;;;;;;;;OASG;IACH,SAAgB,kBAAkB,CAChC,UAA8B;QAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACvC,IAAI,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;YAC1C,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAVe,0BAAkB,qBAUjC,CAAA;IAED;;;OAGG;IACH,SAAgB,gBAAgB;QAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1C,CAAC;IAFe,wBAAgB,mBAE/B,CAAA;IAED,IAAI,MAAM,GAAkB,IAAI,CAAC;IAEjC;;;;OAIG;IACH,SAAgB,QAAQ,CAAC,KAAa;QACpC,MAAM,GAAG,KAAK,CAAC;IACjB,CAAC;IAFe,gBAAQ,WAEvB,CAAA;IAED,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAAmB,CAAC;IAExD;;;;;;;;;;OAUG;IACH,SAAgB,gBAAgB,CAC9B,QAAqC;QAErC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;IACH,CAAC;IARe,wBAAgB,mBAQ/B,CAAA;IAED;;;OAGG;IACH,SAAgB,YAAY,CAAC,IAAa;QACxC,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAFe,oBAAY,eAE3B,CAAA;IAED;;OAEG;IACH,KAAK,UAAU,kBAAkB,CAC/B,UAA8B;QAE9B,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,GACjD,MAAM,iBAAiB,EAAE,CAAC;QAE5B,MAAM,SAAU,SAAQ,OAAO;;QACZ,sBAAY,GAAG,EAAS,CAAC;QAG5C,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;YACtB,gEAAgE;YAChE,IAAI,EAAE,IAAI,SAAS,EAAE;SACtB,CAAC,CAAC;QACH,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,KAAK,CAAC,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC;QAC/B,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC;YAClB,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC;YACvC,UAAU;YACV,WAAW,EAAE;gBACX,CAAC,IAAI,EAAE,IAAI,CAAC;gBACZ,CAAC,KAAK,EAAE,KAAK,CAAC;aACf;YACD,cAAc,EAAE,IAAI;YACpB,mBAAmB,EAAE,IAAI;SAC1B,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE;YACvC,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,KAAK;SACjB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,SAAgB,iBAAiB,CAAC,OAAoB;QACpD,MAAM,OAAO,GAAG,OAAO,CAAC,gBAAgB,CAAoB,YAAY,CAAC,CAAC;QAC1E,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;YACvB,4CAA4C;YAC5C,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAErE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACpC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC7B,CAAC;YAED,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEjC,6CAA6C;YAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC;YAC3B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAlBe,yBAAiB,oBAkBhC,CAAA;AACH,CAAC,EA5NS,OAAO,KAAP,OAAO,QA4NhB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyterlab/mathjax-extension",
3
- "version": "4.7.0-alpha.0",
3
+ "version": "4.7.0-alpha.2",
4
4
  "description": "A JupyterLab extension providing MathJax Typesetting",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -48,14 +48,13 @@
48
48
  "watch": "tsc -b --watch"
49
49
  },
50
50
  "dependencies": {
51
- "@jupyterlab/application": "^4.7.0-alpha.0",
52
- "@jupyterlab/rendermime": "^4.7.0-alpha.0",
53
- "@jupyterlab/translation": "^4.7.0-alpha.0",
54
- "@lumino/coreutils": "^2.2.2",
51
+ "@jupyterlab/application": "^4.7.0-alpha.2",
52
+ "@jupyterlab/rendermime": "^4.7.0-alpha.2",
53
+ "@jupyterlab/translation": "^4.7.0-alpha.2",
55
54
  "mathjax-full": "^3.2.2"
56
55
  },
57
56
  "devDependencies": {
58
- "@jupyterlab/testing": "^4.7.0-alpha.0",
57
+ "@jupyterlab/testing": "^4.7.0-alpha.2",
59
58
  "@types/jest": "^29.2.0",
60
59
  "jest": "^29.2.0",
61
60
  "rimraf": "~5.0.5",
package/src/index.ts CHANGED
@@ -6,8 +6,6 @@
6
6
  * @module mathjax-extension
7
7
  */
8
8
 
9
- import { PromiseDelegate } from '@lumino/coreutils';
10
-
11
9
  import type {
12
10
  JupyterFrontEnd,
13
11
  JupyterFrontEndPlugin
@@ -15,6 +13,8 @@ import type {
15
13
 
16
14
  import { ILatexTypesetter } from '@jupyterlab/rendermime';
17
15
 
16
+ import type { IRenderMime } from '@jupyterlab/rendermime';
17
+
18
18
  import { ITranslator, nullTranslator } from '@jupyterlab/translation';
19
19
 
20
20
  import type { MathDocument } from 'mathjax-full/js/core/MathDocument';
@@ -40,9 +40,50 @@ namespace CommandArgs {
40
40
  * The MathJax Typesetter.
41
41
  */
42
42
  export class MathJaxTypesetter implements ILatexTypesetter {
43
+ /**
44
+ * Construct a new MathJax typesetter.
45
+ *
46
+ * @param options - Options describing how math is recognized in the source
47
+ * text (see {@link MathJaxTypesetter.IOptions}).
48
+ */
49
+ constructor(options: MathJaxTypesetter.IOptions = {}) {
50
+ this.mathParseOptions = {
51
+ dollarInlineMath: options.dollarInlineMath ?? true
52
+ };
53
+ }
54
+
55
+ /**
56
+ * The options describing how math is recognized in the source text.
57
+ *
58
+ * Exposed so that the Markdown pre-processor (`removeMath`) and this
59
+ * typesetter agree on whether a single `$` introduces inline math.
60
+ */
61
+ readonly mathParseOptions: IRenderMime.ILatexTypesetter.IMathParseOptions;
62
+
63
+ /**
64
+ * Create a new MathJax typesetter with the given parse options.
65
+ *
66
+ * Options which are not given are inherited from this typesetter; this
67
+ * typesetter is left unchanged. The underlying MathDocument is shared with
68
+ * any other typesetter using the same options, so this is cheap to call.
69
+ *
70
+ * @param options - The parse options to apply.
71
+ */
72
+ withParseOptions(
73
+ options: IRenderMime.ILatexTypesetter.IMathParseOptions
74
+ ): MathJaxTypesetter {
75
+ return new MathJaxTypesetter(
76
+ Private.mergeParseOptions(this.mathParseOptions, options)
77
+ );
78
+ }
79
+
43
80
  protected async _ensureInitialized() {
44
81
  if (!this._initialized) {
45
- this._mathDocument = await Private.ensureMathDocument();
82
+ this._mathDocument = await Private.ensureMathDocument(
83
+ this.mathParseOptions.dollarInlineMath === false
84
+ ? Private.INLINE_MATH_WITHOUT_DOLLAR
85
+ : Private.DEFAULT_INLINE_MATH
86
+ );
46
87
  this._initialized = true;
47
88
  }
48
89
  }
@@ -67,8 +108,15 @@ export class MathJaxTypesetter implements ILatexTypesetter {
67
108
  }
68
109
 
69
110
  this._mathDocument.options.elements = [node];
111
+ // `clear()` empties the document's math list before rendering, so that
112
+ // memory retained per math expression (most notably the compiled internal
113
+ // MathML tree) is bounded by the last typeset call rather than growing
114
+ // with the total amount of math on the page.
115
+ // This is also why we need to store the sources manually -
116
+ // we cannot extract them from MathJax state after `clear()`.
70
117
  this._mathDocument.clear().render();
71
118
  delete this._mathDocument.options.elements;
119
+ Private.recordTexSources(this._mathDocument);
72
120
  Private.hardenAnchorLinks(node);
73
121
  }
74
122
 
@@ -76,6 +124,19 @@ export class MathJaxTypesetter implements ILatexTypesetter {
76
124
  protected _mathDocument: MathDocument<any, any, any>;
77
125
  }
78
126
 
127
+ /**
128
+ * A namespace for `MathJaxTypesetter` statics.
129
+ */
130
+ export namespace MathJaxTypesetter {
131
+ // Extends the provider-agnostic math-parsing options; MathJax-specific
132
+ // options can be added here later in backward-compatible fashion.
133
+ /**
134
+ * Options for constructing a {@link MathJaxTypesetter}.
135
+ */
136
+ export interface IOptions
137
+ extends IRenderMime.ILatexTypesetter.IMathParseOptions {}
138
+ }
139
+
79
140
  /**
80
141
  * The MathJax extension.
81
142
  */
@@ -90,6 +151,18 @@ const mathJaxPlugin: JupyterFrontEndPlugin<ILatexTypesetter> = {
90
151
 
91
152
  app.commands.addCommand(CommandIDs.copy, {
92
153
  execute: async () => {
154
+ // Find the math expression the context menu was opened on; this works
155
+ // across all typesetter instances (e.g. ones configured with
156
+ // different delimiters), unlike the fallback below which reflects
157
+ // whichever expression the default typesetter processed last.
158
+ const root = app.contextMenuHitTest(node =>
159
+ node.classList.contains('MathJax')
160
+ );
161
+ const tex = root ? Private.getTexSource(root) : undefined;
162
+ if (tex !== undefined) {
163
+ await navigator.clipboard.writeText(tex);
164
+ return;
165
+ }
93
166
  const md = await typesetter.mathDocument();
94
167
  const oJax: any = md.outputJax;
95
168
  await navigator.clipboard.writeText(oJax.math.math);
@@ -105,16 +178,21 @@ const mathJaxPlugin: JupyterFrontEndPlugin<ILatexTypesetter> = {
105
178
 
106
179
  app.commands.addCommand(CommandIDs.scale, {
107
180
  execute: async (args: CommandArgs.scale) => {
108
- const md = await typesetter.mathDocument();
109
181
  const scale = args['scale'] || 1.0;
110
- md.outputJax.options.scale = scale;
111
- md.rerender();
112
-
113
- // Harden only the re-rendered anchors
114
- for (const math of md.math) {
115
- const root = math.typesetRoot as HTMLElement | null;
116
- if (root) {
117
- Private.hardenAnchorLinks(root);
182
+ // Scale all documents so that every typesetter instance (e.g. ones
183
+ // configured with different delimiters) is affected alike; remember
184
+ // the scale so that documents created later inherit it too.
185
+ Private.setScale(scale);
186
+ for (const md of await Private.getMathDocuments()) {
187
+ md.outputJax.options.scale = scale;
188
+ md.rerender();
189
+
190
+ // Harden only the re-rendered anchors
191
+ for (const math of md.math) {
192
+ const root = math.typesetRoot as HTMLElement | null;
193
+ if (root) {
194
+ Private.hardenAnchorLinks(root);
195
+ }
118
196
  }
119
197
  }
120
198
  },
@@ -145,74 +223,201 @@ export default mathJaxPlugin;
145
223
  * A namespace for module-private functionality.
146
224
  */
147
225
  namespace Private {
148
- let _loading: PromiseDelegate<MathDocument<any, any, any>> | null = null;
226
+ /**
227
+ * The default delimiters for inline math.
228
+ */
229
+ export const DEFAULT_INLINE_MATH: [string, string][] = [
230
+ ['$', '$'],
231
+ ['\\(', '\\)']
232
+ ];
233
+
234
+ /**
235
+ * Merge parse options, where an `undefined` value in `overrides` means
236
+ * "keep the current value" rather than "reset to the default".
237
+ */
238
+ export function mergeParseOptions(
239
+ base: IRenderMime.ILatexTypesetter.IMathParseOptions,
240
+ overrides: IRenderMime.ILatexTypesetter.IMathParseOptions
241
+ ): IRenderMime.ILatexTypesetter.IMathParseOptions {
242
+ const merged: Record<string, unknown> = { ...base };
243
+ for (const [key, value] of Object.entries(overrides)) {
244
+ if (value !== undefined) {
245
+ merged[key] = value;
246
+ }
247
+ }
248
+ return merged as IRenderMime.ILatexTypesetter.IMathParseOptions;
249
+ }
250
+
251
+ /**
252
+ * The inline math delimiters with the single `$` pair removed, so that `$`
253
+ * is rendered literally.
254
+ */
255
+ export const INLINE_MATH_WITHOUT_DOLLAR: [string, string][] = [
256
+ ['\\(', '\\)']
257
+ ];
258
+
259
+ /**
260
+ * Load the MathJax modules and register the document handler.
261
+ *
262
+ * The heavy dynamic imports and the (global, one-time) handler registration
263
+ * are shared across all typesetters; only the per-instance document is built
264
+ * separately in {@link createMathDocument}. The returned bundle's type is
265
+ * inferred so no MathJax types need to be imported explicitly.
266
+ */
267
+ async function loadModules() {
268
+ void import('mathjax-full/js/input/tex/require/RequireConfiguration');
269
+
270
+ const [
271
+ { mathjax },
272
+ { CHTML },
273
+ { TeX },
274
+ { TeXFont },
275
+ { AllPackages },
276
+ { SafeHandler },
277
+ { HTMLHandler },
278
+ { browserAdaptor },
279
+ { AssistiveMmlHandler }
280
+ ] = await Promise.all([
281
+ import('mathjax-full/js/mathjax'),
282
+ import('mathjax-full/js/output/chtml'),
283
+ import('mathjax-full/js/input/tex'),
284
+ import('mathjax-full/js/output/chtml/fonts/tex'),
285
+ import('mathjax-full/js/input/tex/AllPackages'),
286
+ import('mathjax-full/js/ui/safe/SafeHandler'),
287
+ import('mathjax-full/js/handlers/html/HTMLHandler'),
288
+ import('mathjax-full/js/adaptors/browserAdaptor'),
289
+ import('mathjax-full/js/a11y/assistive-mml')
290
+ ]);
291
+
292
+ mathjax.handlers.register(
293
+ AssistiveMmlHandler(SafeHandler(new HTMLHandler(browserAdaptor())))
294
+ );
295
+
296
+ return { mathjax, CHTML, TeX, TeXFont, AllPackages };
297
+ }
149
298
 
150
- export async function ensureMathDocument(): Promise<
151
- MathDocument<any, any, any>
152
- > {
299
+ let _loading: ReturnType<typeof loadModules> | null = null;
300
+
301
+ /**
302
+ * Ensure the MathJax modules are loaded exactly once per page.
303
+ */
304
+ export function ensureMathModules(): ReturnType<typeof loadModules> {
153
305
  if (!_loading) {
154
- _loading = new PromiseDelegate();
155
-
156
- void import('mathjax-full/js/input/tex/require/RequireConfiguration');
157
-
158
- const [
159
- { mathjax },
160
- { CHTML },
161
- { TeX },
162
- { TeXFont },
163
- { AllPackages },
164
- { SafeHandler },
165
- { HTMLHandler },
166
- { browserAdaptor },
167
- { AssistiveMmlHandler }
168
- ] = await Promise.all([
169
- import('mathjax-full/js/mathjax'),
170
- import('mathjax-full/js/output/chtml'),
171
- import('mathjax-full/js/input/tex'),
172
- import('mathjax-full/js/output/chtml/fonts/tex'),
173
- import('mathjax-full/js/input/tex/AllPackages'),
174
- import('mathjax-full/js/ui/safe/SafeHandler'),
175
- import('mathjax-full/js/handlers/html/HTMLHandler'),
176
- import('mathjax-full/js/adaptors/browserAdaptor'),
177
- import('mathjax-full/js/a11y/assistive-mml')
178
- ]);
179
-
180
- mathjax.handlers.register(
181
- AssistiveMmlHandler(SafeHandler(new HTMLHandler(browserAdaptor())))
182
- );
306
+ _loading = loadModules();
307
+ }
308
+ return _loading;
309
+ }
310
+
311
+ const _documents = new Map<string, Promise<MathDocument<any, any, any>>>();
312
+
313
+ /**
314
+ * Get (or lazily create) the MathDocument for the given inline delimiters.
315
+ *
316
+ * Building a MathDocument costs on the order of ~5 ms and retains memory for
317
+ * the lifetime of the page. Caching one document per distinct delimiter
318
+ * configuration keeps that bounded, so constructing many typesetters with
319
+ * the same configuration (for example one per markdown cell across a large
320
+ * notebook) reuses a single document instead of multiplying the time and
321
+ * memory cost.
322
+ */
323
+ export function ensureMathDocument(
324
+ inlineMath: [string, string][]
325
+ ): Promise<MathDocument<any, any, any>> {
326
+ const key = JSON.stringify(inlineMath);
327
+ let document = _documents.get(key);
328
+ if (!document) {
329
+ document = createMathDocument(inlineMath);
330
+ _documents.set(key, document);
331
+ }
332
+ return document;
333
+ }
334
+
335
+ /**
336
+ * Get all MathDocuments created so far, so that document-wide commands
337
+ * (e.g. scaling) can operate across every delimiter configuration in use.
338
+ */
339
+ export function getMathDocuments(): Promise<MathDocument<any, any, any>[]> {
340
+ return Promise.all(_documents.values());
341
+ }
342
+
343
+ let _scale: number | null = null;
344
+
345
+ /**
346
+ * Remember the requested scale factor, so that MathDocuments created later
347
+ * (e.g. on first use of a typesetter with a different delimiter
348
+ * configuration) start at the user's chosen scale rather than the default.
349
+ */
350
+ export function setScale(scale: number): void {
351
+ _scale = scale;
352
+ }
353
+
354
+ const _texSourceByRoot = new WeakMap<Element, string>();
183
355
 
184
- class EmptyFont extends TeXFont {
185
- protected static defaultFonts = {} as any;
356
+ /**
357
+ * Record the TeX source of each math expression typeset by `document`,
358
+ * keyed by its rendered container element.
359
+ *
360
+ * A MathDocument only retains the math items from its most recent
361
+ * `render()` call (each `typeset()` starts with `clear()`), so the source
362
+ * of earlier expressions must be captured here for the copy command to
363
+ * find the expression that was actually clicked. Unlike retaining the math
364
+ * items themselves, this only keeps the source string, and the `WeakMap`
365
+ * lets it be reclaimed as soon as the rendered node is garbage-collected.
366
+ */
367
+ export function recordTexSources(
368
+ document: MathDocument<any, any, any>
369
+ ): void {
370
+ for (const item of document.math) {
371
+ if (item.typesetRoot) {
372
+ _texSourceByRoot.set(item.typesetRoot, item.math);
186
373
  }
374
+ }
375
+ }
187
376
 
188
- const chtml = new CHTML({
189
- // Override dynamically generated fonts in favor of our font css
190
- font: new EmptyFont()
191
- });
192
-
193
- const tex = new TeX({
194
- packages: AllPackages.concat('require'),
195
- inlineMath: [
196
- ['$', '$'],
197
- ['\\(', '\\)']
198
- ],
199
- displayMath: [
200
- ['$$', '$$'],
201
- ['\\[', '\\]']
202
- ],
203
- processEscapes: true,
204
- processEnvironments: true
205
- });
206
-
207
- const mathDocument = mathjax.document(window.document, {
208
- InputJax: tex,
209
- OutputJax: chtml
210
- });
211
-
212
- _loading.resolve(mathDocument);
377
+ /**
378
+ * Get the TeX source of the math expression rendered in `root`
379
+ * (a `mjx-container` element), if known.
380
+ */
381
+ export function getTexSource(root: Element): string | undefined {
382
+ return _texSourceByRoot.get(root);
383
+ }
384
+
385
+ /**
386
+ * Build a MathDocument configured with the given inline delimiters.
387
+ */
388
+ async function createMathDocument(
389
+ inlineMath: [string, string][]
390
+ ): Promise<MathDocument<any, any, any>> {
391
+ const { mathjax, CHTML, TeX, TeXFont, AllPackages } =
392
+ await ensureMathModules();
393
+
394
+ class EmptyFont extends TeXFont {
395
+ protected static defaultFonts = {} as any;
213
396
  }
214
397
 
215
- return _loading.promise;
398
+ const chtml = new CHTML({
399
+ // Override dynamically generated fonts in favor of our font css
400
+ font: new EmptyFont()
401
+ });
402
+ if (_scale !== null) {
403
+ chtml.options.scale = _scale;
404
+ }
405
+
406
+ const tex = new TeX({
407
+ packages: AllPackages.concat('require'),
408
+ inlineMath,
409
+ displayMath: [
410
+ ['$$', '$$'],
411
+ ['\\[', '\\]']
412
+ ],
413
+ processEscapes: true,
414
+ processEnvironments: true
415
+ });
416
+
417
+ return mathjax.document(window.document, {
418
+ InputJax: tex,
419
+ OutputJax: chtml
420
+ });
216
421
  }
217
422
 
218
423
  /**