@@ -9,16 +9,25 @@ pre- and post-filters associated with MathJax's input and output jax.
9
9
These are prioritized lists of functions that run either before or
10
10
after the jax processes a :data: `MathItem `, and they can be used to
11
11
pre-process or post-process MathJax's compiling and typesetting
12
- functions. Input jax have both pre- and post-filters, but output jax
13
- have only post-filters; pre-filtering can be done by an input jax
14
- post-filter, if needed .
12
+ functions. Input and output jax have both pre- and post-filters, and
13
+ the MathML input jax has an extra set of filters for the parsed MathML
14
+ as well .
15
15
16
- To add a pre- or post-filter to an input jax use
16
+ When using :ref: `Mathjax Components framework <web-components >`, you
17
+ can use the MathJax configuration object to specify input and output
18
+ jax filters. The :data: `preFilter ` and :data: `postFilter `
19
+ configuration options in the :data: `tex `, :data: `mathml `,
20
+ :data: `output `, :data: `chtml `, or :data: `svg ` blocks allow you to
21
+ specify arrays of filters (or filters together with their priorities).
22
+ See the :ref: `configuring-mathjax ` section for details.
23
+
24
+ When using direct access to the MathJax modules in node applications,
25
+ to add a pre- or post-filter to an input jax use
17
26
18
27
.. js :function :: InputJax .preFilters .add (fn, priority)
19
28
InputJax .postFilters .add (fn, priority)
20
29
21
- :param (arg) => boolean|void: The filter function to be called.
30
+ :param (arg)=> boolean|void: The filter function to be called.
22
31
The :data: `arg ` argument is an object
23
32
with three keys: :data: `math `,
24
33
:data: `document `, and :data: `data `.
@@ -35,7 +44,8 @@ To add a pre- or post-filter to an input jax use
35
44
functions anywhere in the filter list.
36
45
37
46
For the TeX input jax, the :data: `data ` item is the
38
- :data: `ParseOptions ` object for the input jax.
47
+ :data: `ParseOptions ` object for the input jax, which holds
48
+ configuration data about the TeX input jax.
39
49
40
50
For the MathML input jax, the pre-filter only runs in the case that
41
51
the MathML is a serialized MathML string, as it is when converting a
@@ -54,14 +64,15 @@ input jax converts the MathML into MathJax's internal format. The
54
64
The AsciiMath input jax does not currently execute any pre- or
55
65
post-filters.
56
66
57
- For an output jax, the post-filters can be added via
67
+ For an output jax, the pre- and post-filters can be added via
58
68
59
- .. js :function :: OutputJax .postFilters .add (fn, priority)
69
+ .. js :function :: OutputJax .preFilters .add (fn, priority)
70
+ OutputJax .postFilters .add (fn, priority)
60
71
61
72
with arguments as above. In this case, the :data: `data ` is the
62
73
``mjx-container `` node in which the output DOM elements have been
63
74
placed. This will become the :data: `MathItem.typesetRoot ` value, but
64
- it has not yet been set when the post- filters run.
75
+ it has not yet been set when the filters run.
65
76
66
77
In an application that is using MathJax Components, the input jax can
67
78
be obtained from :data: `MathJax.startup.document.inputJax.tex ` or
@@ -74,6 +85,7 @@ to them; if not, then they can be obtained from the
74
85
:js:meth: `mathjax.document() ` by using that in place of
75
86
:data: `MathJax.startup.document ` above.
76
87
88
+
77
89
-----
78
90
79
91
.. _filter-number-space :
@@ -90,20 +102,17 @@ displayed as ``12345``.
90
102
91
103
MathJax = {
92
104
tex: {
93
- numberPattern: / ^ (?:[0-9 ] + (?:(?: + | \{ ,\} )[0-9 ] + )* (?:\. [0-9 ] * )? | \. [0-9 ] + )/
94
- },
95
- startup: {
96
- ready () {
97
- MathJax .startup .defaultReady ();
98
- MathJax .startup .document .inputJax .tex .postFilters .add (({data}) => {
105
+ numberPattern: / ^ (?:[0-9 ] + (?:(?: + | \{ ,\} )[0-9 ] + )* (?:\. [0-9 ] * )? | \. [0-9 ] + )/ ,
106
+ postFilters: [
107
+ ({data}) => {
99
108
for (const mn of data .getList (' mn' )) {
100
109
const textNode = mn .childNodes [0 ];
101
110
textNode .text = textNode .text .replace (/ / g , ' ' );
102
111
}
103
- });
104
- }
105
- }
106
- }
112
+ }
113
+ ],
114
+ },
115
+ };
107
116
108
117
We set the :data: `numberPattern ` option to allow spaces within the
109
118
number, and then use a post-filter to remove the spaces from the text
@@ -123,18 +132,15 @@ to better quality output.
123
132
.. code-block :: js
124
133
125
134
MathJax = {
126
- startup: {
127
- ready () {
128
- MathJax .startup .defaultReady ();
129
- MathJax .startup .document .inputJax .tex .preFilters .add (
130
- ({math}) => {
131
- math .math = math .math .replace (/ [\uFF01 -\uFF5E ] / g ,
132
- (c ) => String .fromCodePoint (c .codePointAt (0 ) - 0xFF00 + 0x20 ));
133
- }
134
- );
135
- }
135
+ tex: {
136
+ preFilters: [
137
+ ({math}) => {
138
+ math .math = math .math .replace (/ [\uFF01 -\uFF5E ] / g ,
139
+ (c ) => String .fromCodePoint (c .codePointAt (0 ) - 0xFF00 + 0x20 ));
140
+ }
141
+ ]
136
142
}
137
- }
143
+ };
138
144
139
145
This uses a pre-filter to replace characters in the full-width range
140
146
by an equivalent one in the usual ASCII character range. This will
@@ -155,31 +161,25 @@ and subscripts.
155
161
.. code-block :: js
156
162
157
163
MathJax = {
158
- startup: {
159
- ready () {
160
- //
161
- // Do usual setup
162
- //
163
- MathJax .startup .defaultReady ();
164
- //
165
- // The pseudoscript numbers 0 through 9, and a pattern for plus-or-minus a number
166
- //
167
- const scripts = ' \u2070\u00B9\u00B2\u00B3\u2074\u2075\u2076\u2077\u2078\u2079 ' ;
168
- const scriptRE = / ([\u207A\u207B ] )? ([\u2070\u00B9\u00B2\u00B3 \u2074 -\u2079 ] + )/ g ;
169
- //
170
- // Add a TeX prefilter to convert pseudoscript numbers to actual superscripts
171
- //
172
- MathJax .startup .document .inputJax .tex .preFilters .add (({math}) => {
173
- math .math = math .math .replace (scriptRE, (match , pm , n ) => {
174
- const N = n .split (' ' ).map (c => scripts .indexOf (c)); // convert digits
164
+ //
165
+ // The pseudoscript numbers 0 through 9, and a pattern for plus-or-minus a number
166
+ //
167
+ scripts: ' \u2070\u00B9\u00B2\u00B3\u2074\u2075\u2076\u2077\u2078\u2079 ' ,
168
+ scriptRE: / ([\u207A\u207B ] )? ([\u2070\u00B9\u00B2\u00B3 \u2074 -\u2079 ] + )/ g ,
169
+
170
+ tex: {
171
+ preFilters: [
172
+ ({math}) => {
173
+ math .math = math .math .replace (MathJax .config .scriptRE , (match , pm , n ) => {
174
+ const N = n .split (' ' ).map (c => MathJax .config .scripts .indexOf (c)); // convert digits
175
175
pm === ' \u207A ' && N .unshift (' +' ); // add plus, if given
176
176
pm === ' \u207B ' && N .unshift (' -' ); // add minus, if given
177
177
return ' ^{' + N .join (' ' ) + ' }' ; // make it an actual power
178
178
});
179
- });
180
- }
179
+ }
180
+ ]
181
181
}
182
- }
182
+ };
183
183
184
184
This uses a TeX input jax pre-filter to scan the TeX expression for
185
185
Unicode superscript numerals, with optional plus or minus signs, and
@@ -204,22 +204,21 @@ those measurements to `px` units instead.
204
204
.. code-block :: js
205
205
206
206
MathJax = {
207
- startup: {
208
- ready () {
209
- MathJax .startup .defaultReady ();
210
- const fixed = MathJax .startup .document .outputJax .fixed ;
211
- MathJax .startup .document .outputJax .postFilters .add (({data}) => {
207
+ svg: {
208
+ postFilters: [
209
+ ({data}) => {
210
+ const fixed = MathJax .startup .document .outputJax .fixed ;
212
211
const svg = data .querySelector (' svg' );
213
212
if (svg? .hasAttribute (' viewBox' )) {
214
213
const [ , , w , h ] = svg .getAttribute (' viewBox' ).split (/ / );
215
- const em = document .outputJax .pxPerEm / 1000 ;
214
+ const em = MathJax . startup . document .outputJax .pxPerEm / 1000 ;
216
215
svg .setAttribute (' width' , fixed (w * em) + ' px' );
217
216
svg .setAttribute (' height' , fixed (h * em) + ' px' );
218
217
}
219
- });
220
- }
218
+ }
219
+ ]
221
220
}
222
- }
221
+ };
223
222
224
223
We use an output jax post- filter to modify the ` ` svg` ` element' s
225
224
attributes, taking advantage of the output jax' s : meth: ` fixed()`
@@ -239,18 +238,18 @@ This configuration implements a substitute for the v2 `autobold` extension.
239
238
.. code - block:: js
240
239
241
240
MathJax = {
242
- startup: {
243
- ready () {
244
- MathJax .startup .defaultReady ();
245
- MathJax .startup .document .inputJax .tex .preFilters .add (({math}) => {
241
+ tex: {
242
+ preFilters: [
243
+ ({math}) => {
246
244
const styles = window .getComputedStyle (math .start .node .parentNode );
247
- if (styles .fontWeight >= 700 ) {
245
+ if (styles .fontWeight >= 700 && ! math . inputData . bolded ) {
248
246
math .math = ' \\ boldsymbol{' + math .math + ' }' ;
247
+ math .inputData .bolded = true ;
249
248
}
250
- });
251
- }
249
+ }
250
+ ]
252
251
}
253
- }
252
+ };
254
253
255
254
It uses a TeX input jax pre- filter that tests if the parent element of
256
255
the math string has CSS with ` ` font- weight` ` of 700 or more (the
@@ -259,6 +258,12 @@ usual ``bold`` value), and if so, it wraps the TeX code in
259
258
expression itself includes bold notation, that does not become extra
260
259
bold, so may not be distinguishable from the rest of the expression.
261
260
261
+ We track the fact that bolding has been added using the
262
+ : data: ` inputData` object of the : data: ` math` object . That way, if the
263
+ expression needs to be reparsed (e .g ., for a ` ` \require` ` command, or
264
+ other dynamic data being loaded), we won' t add ``\b oldsymbol`` more
265
+ than once.
266
+
262
267
-----
263
268
264
269
.. _filter-mathvariant:
@@ -330,6 +335,23 @@ browsers that implement MathML-Core.
330
335
0x6F : 0x2134 ,
331
336
}, ' \uFE00 ' ],
332
337
' -tex-bold-calligraphic' : [0 , 0x1D4D0 , 0x1D4EA , 0 , 0 , {}, ' \uFE00 ' ],
338
+ ' -tex-mathit' : [0 , 0x1D434 , 0x1D44E , 0x1D6E2 , 0x1D6FC , {0x68 : 0x210E }],
339
+ };
340
+ //
341
+ // Styles to use for characters that can't be translated.
342
+ //
343
+ const variantStyles = {
344
+ bold: ' font-weight: bold' ,
345
+ italic: ' font-style: italic' ,
346
+ ' bold-italic' : ' font-weight; bold; font-style: italic' ,
347
+ ' script' : ' font-family: cursive' ,
348
+ ' bold-script' : ' font-family: cursive; font-weight: bold' ,
349
+ ' sans-serif' : ' font-family: sans-serif' ,
350
+ ' bold-sans-serif' : ' font-family: sans-serif; font-weight: bold' ,
351
+ ' sans-serif-italic' : ' font-family: sans-serif; font-style: italic' ,
352
+ ' sans-serif-bold-italic' : ' font-family: sans-serif; font-weight: bold; font-style: italic' ,
353
+ ' monospace' : ' font-family: monospace' ,
354
+ ' -tex-mathit' : ' font-style: italic' ,
333
355
};
334
356
//
335
357
// The filter function
@@ -362,11 +384,20 @@ browsers that implement MathML-Core.
362
384
//
363
385
// Convert the text of the child nodes
364
386
//
387
+ let converted = true ;
365
388
for (const child of node .childNodes ) {
366
389
if (child .isKind (' text' )) {
367
- convertText(child, start, remap, modifier);
390
+ converted &= convertText (child, start, remap, modifier);
368
391
}
369
392
}
393
+ //
394
+ // If not all characters were converted, add styles, if possible,
395
+ // but not when it would already be in italics.
396
+ //
397
+ if (! converted &&
398
+ ! ([' italic' , ' -tex-mathit' ].includes (variant) && text .length === 1 && node .isKind (' mi' ))) {
399
+ addStyles (node, variant);
400
+ }
370
401
});
371
402
}
372
403
//
@@ -380,6 +411,7 @@ browsers that implement MathML-Core.
380
411
//
381
412
// Loop through the characters in the text
382
413
//
414
+ let converted = 0 ;
383
415
for (let i = 0 ; i < text .length ; i++ ) {
384
416
let C = text[i].codePointAt (0 );
385
417
//
@@ -395,9 +427,11 @@ browsers that implement MathML-Core.
395
427
//
396
428
if (map[C ]) {
397
429
text[i] = String .fromCodePoint (map[C ] - m + start[j]) + modifier;
430
+ converted++ ;
398
431
break ;
399
432
} else if (remap[C ] || C <= M ) {
400
433
text[i] = String .fromCodePoint (remap[C ] || C - m + start[j]) + modifier;
434
+ converted++ ;
401
435
break ;
402
436
}
403
437
}
@@ -406,17 +440,34 @@ browsers that implement MathML-Core.
406
440
// Put back the modified text content
407
441
//
408
442
node .setText (text .join (' ' ));
443
+ //
444
+ // Return true if all characters were converted, false otherwise.
445
+ //
446
+ return converted === text .length ;
409
447
}
410
448
//
411
- // Add the input post-filters
449
+ // Add styles when conversion isn't possible.
450
+ //
451
+ function addStyles (node , variant ) {
452
+ let styles = variantStyles[variant];
453
+ if (styles) {
454
+ if (node .attributes .hasExplicit (styles)) {
455
+ styles = node .attributes .get (' style' ) + ' ' + styles;
456
+ }
457
+ node .attributes .set (' style' , styles);
458
+ }
459
+ }
460
+
461
+ //
462
+ // Add the post-filters to all input jax
412
463
//
413
464
MathJax .startup .defaultReady ();
414
465
for (jax of MathJax .startup .document .inputJax ) {
415
466
jax .postFilters .add (({data}) => unicodeVariants (data .root || data));
416
467
}
417
468
}
418
469
}
419
- }
470
+ };
420
471
421
472
This example adds a post- filter to each of the input jax that are
422
473
loaded (so it will work with both the MathML input as well as TeX
@@ -425,12 +476,16 @@ elements with :attr:`mathvariant` attributes, and then converts the
425
476
content of the child text nodes of those token nodes to use the proper
426
477
Unicode values for any alphabetic, numeric, or Greek characters that
427
478
can be represented using the Mathematical Alphanumeric and Letterlike
428
- Symbols blocks.
479
+ Symbols blocks . If any characters can' t be converted to something in
480
+ these blocks, we use a :attr:`style` attribute, when possible, to
481
+ simulate the proper output.
429
482
430
483
The :data:`ranges` variable gives the character ranges that will be
431
- converted, and the :data:`variants` object gives the data needed to
432
- make those ranges to the various Mathematical Alphanumerics characters
433
- for the different :attr:`mathvariant` values.
484
+ converted, the :data:`variants` object gives the data needed to make
485
+ those ranges to the various Mathematical Alphanumerics characters for
486
+ the different :attr:`mathvariant` values, and the
487
+ :data:`variantStyles` object to hold the styles that need to be
488
+ applied for each variant.
434
489
435
490
The special ``-tex-calligraphic`` and ``-tex-bold-calligraphic``
436
491
variants are used internally in MathJax to produce the Chancery
@@ -444,7 +499,9 @@ for the TeX calligraphic variants. You may wish to add U+FE01 to the
444
499
script variants to explicitly request the Roundhand versions as well.
445
500
Note, however, that not all fonts support these variant specifiers, so
446
501
you may get the same characters in both cases, and which you get will
447
- depend on the font.
502
+ depend on the font. Some browsers may also show unknown character
503
+ glyphs for these select codes when they don' t understand how to
504
+ process them.
448
505
449
506
450
507
| ---- - |
0 commit comments