@pie-lib/math-input-mathlive 1.1.4 → 1.1.5-beta.1
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/README.md +14 -5
- package/lib/fonts/embedded.js +120 -0
- package/lib/fonts/index.js +81 -0
- package/lib/fonts/index.js.map +1 -0
- package/lib/keypad/index.js +15 -17
- package/lib/keypad/index.js.map +1 -1
- package/lib/keys/geometry.js +7 -4
- package/lib/keys/geometry.js.map +1 -1
- package/lib/keys/misc.js +9 -2
- package/lib/keys/misc.js.map +1 -1
- package/lib/latex-bridge.js +48 -3
- package/lib/latex-bridge.js.map +1 -1
- package/lib/mathlive-instance.js +186 -15
- package/lib/mathlive-instance.js.map +1 -1
- package/lib/mf/common-styles.js +74 -10
- package/lib/mf/common-styles.js.map +1 -1
- package/lib/mf/index.js +6 -0
- package/lib/mf/index.js.map +1 -1
- package/lib/mf/input.js +29 -5
- package/lib/mf/input.js.map +1 -1
- package/lib/mf/static.js +105 -7
- package/lib/mf/static.js.map +1 -1
- package/package.json +3 -4
- package/scripts/generate-embedded-fonts.js +94 -0
- package/src/fonts/embedded.js +116 -0
- package/src/fonts/index.js +71 -0
- package/src/keypad/index.jsx +15 -14
- package/src/keys/geometry.js +7 -2
- package/src/keys/misc.js +8 -2
- package/src/latex-bridge.js +52 -3
- package/src/mathlive-instance.js +201 -14
- package/src/mf/common-styles.js +78 -8
- package/src/mf/index.js +2 -0
- package/src/mf/input.jsx +37 -5
- package/src/mf/static.jsx +121 -6
- package/CHANGELOG.md +0 -30
- package/LICENSE.md +0 -5
- package/src/__tests__/drop-in-compat.test.jsx +0 -112
- package/src/__tests__/index.test.jsx +0 -109
- package/src/__tests__/input-imperative.test.jsx +0 -144
- package/src/__tests__/keypad-label.test.jsx +0 -57
- package/src/__tests__/latex-bridge.test.js +0 -230
- package/src/__tests__/mathlive-instance.test.js +0 -181
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { withVisibleEmptySlots as latexForDisplay } from '../latex-bridge';
|
|
2
|
-
import { keyToAction } from '../latex-bridge';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Keys use empty groups to show a command's shape (`\frac{}{}`, `x^{}`).
|
|
6
|
-
* MathLive renders `{}` as nothing, so labels need a visible stand-in - but the
|
|
7
|
-
* value that gets *inserted* must stay untouched.
|
|
8
|
-
*/
|
|
9
|
-
describe('keypad label display normalisation', () => {
|
|
10
|
-
it('gives empty groups a visible glyph', () => {
|
|
11
|
-
const out = latexForDisplay('\\frac{}{}');
|
|
12
|
-
|
|
13
|
-
expect(out).not.toEqual('\\frac{}{}');
|
|
14
|
-
expect(out).toContain('25AB'); // white small square
|
|
15
|
-
expect(out).toContain('pie-empty');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('handles every empty-group key shape', () => {
|
|
19
|
-
[
|
|
20
|
-
'\\frac{}{}',
|
|
21
|
-
'\\overline{}',
|
|
22
|
-
'x^{}',
|
|
23
|
-
'x_{}',
|
|
24
|
-
'\\sqrt{}',
|
|
25
|
-
'\\sqrt[{}]{}',
|
|
26
|
-
'\\abs{}',
|
|
27
|
-
'\\log_{}',
|
|
28
|
-
'\\longdiv{}',
|
|
29
|
-
].forEach((latex) => {
|
|
30
|
-
expect(latexForDisplay(latex)).not.toContain('{}');
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('treats a whitespace-only group as empty', () => {
|
|
35
|
-
// e.g. \frac{x}{ }
|
|
36
|
-
expect(latexForDisplay('\\frac{x}{ }')).toContain('pie-empty');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('leaves latex without empty groups alone', () => {
|
|
40
|
-
['\\pi', '\\sin', 'x^2', '\\overline{AB}'].forEach((latex) => {
|
|
41
|
-
expect(latexForDisplay(latex)).toEqual(latex);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('handles nullish input', () => {
|
|
46
|
-
expect(latexForDisplay(undefined)).toEqual('');
|
|
47
|
-
expect(latexForDisplay('')).toEqual('');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('does NOT affect what gets inserted into the field', () => {
|
|
51
|
-
// the action must use the key's own latex, never the display form
|
|
52
|
-
const key = { name: 'frac', latex: '\\frac{}{}' };
|
|
53
|
-
|
|
54
|
-
expect(keyToAction(key).value).toEqual('\\frac{}{}');
|
|
55
|
-
expect(keyToAction(key).value).not.toContain('pie-empty');
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
toMathLive,
|
|
3
|
-
fromMathLive,
|
|
4
|
-
fieldIds,
|
|
5
|
-
keyToAction,
|
|
6
|
-
toNativeCommands,
|
|
7
|
-
NEWLINE_EMBED,
|
|
8
|
-
DEFAULT_FIELD_ID,
|
|
9
|
-
} from '../latex-bridge';
|
|
10
|
-
|
|
11
|
-
describe('latex-bridge', () => {
|
|
12
|
-
describe('toMathLive', () => {
|
|
13
|
-
it('passes plain latex through', () => {
|
|
14
|
-
expect(toMathLive('\\frac{1}{2}')).toEqual('\\frac{1}{2}');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('handles empty/nullish', () => {
|
|
18
|
-
expect(toMathLive('')).toEqual('');
|
|
19
|
-
expect(toMathLive(undefined)).toEqual('');
|
|
20
|
-
expect(toMathLive(null)).toEqual('');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('converts a newLine embed to a multiline environment', () => {
|
|
24
|
-
expect(toMathLive(`a${NEWLINE_EMBED}b`)).toEqual('\\displaylines{a \\\\ b}');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('converts multiple newLine embeds', () => {
|
|
28
|
-
expect(toMathLive(`a${NEWLINE_EMBED}b${NEWLINE_EMBED}c`)).toEqual('\\displaylines{a \\\\ b \\\\ c}');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('converts MathQuill answer blocks to placeholders', () => {
|
|
32
|
-
expect(toMathLive('x=\\MathQuillMathField[r1]{}')).toEqual('x=\\placeholder[r1]{}');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('preserves answer block content', () => {
|
|
36
|
-
expect(toMathLive('\\MathQuillMathField[r2]{7}')).toEqual('\\placeholder[r2]{7}');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('defaults an unnamed answer block id', () => {
|
|
40
|
-
expect(toMathLive('\\MathQuillMathField[]{}')).toEqual(`\\placeholder[${DEFAULT_FIELD_ID}]{}`);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('handles answer blocks and newlines together', () => {
|
|
44
|
-
expect(toMathLive(`\\MathQuillMathField[r1]{}${NEWLINE_EMBED}x`)).toEqual(
|
|
45
|
-
'\\displaylines{\\placeholder[r1]{} \\\\ x}',
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe('fromMathLive', () => {
|
|
51
|
-
it('passes plain latex through', () => {
|
|
52
|
-
expect(fromMathLive('\\frac{1}{2}')).toEqual('\\frac{1}{2}');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('unwraps displaylines back to newLine embeds', () => {
|
|
56
|
-
expect(fromMathLive('\\displaylines{a \\\\ b}')).toEqual(`a${NEWLINE_EMBED}b`);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('converts placeholders back to MathQuill answer blocks', () => {
|
|
60
|
-
expect(fromMathLive('x=\\placeholder[r1]{}')).toEqual('x=\\MathQuillMathField[r1]{}');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('round-trips a newline document', () => {
|
|
64
|
-
const stored = `a${NEWLINE_EMBED}b${NEWLINE_EMBED}c`;
|
|
65
|
-
|
|
66
|
-
expect(fromMathLive(toMathLive(stored))).toEqual(stored);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('round-trips an answer-block document', () => {
|
|
70
|
-
const stored = 'x=\\MathQuillMathField[r1]{}+\\MathQuillMathField[r2]{3}';
|
|
71
|
-
|
|
72
|
-
expect(fromMathLive(toMathLive(stored))).toEqual(stored);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// MathLive serialises empty slots as \placeholder{}, which MathJax (used by
|
|
76
|
-
// @pie-lib/math-rendering for prompts/previews) renders as red error text.
|
|
77
|
-
it('strips unnamed placeholders that MathLive adds', () => {
|
|
78
|
-
expect(fromMathLive('\\longdiv{\\placeholder{}}')).toEqual('\\longdiv{}');
|
|
79
|
-
expect(fromMathLive('\\frac{\\placeholder{}}{\\placeholder{}}')).toEqual('\\frac{}{}');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('keeps content inside an unnamed placeholder', () => {
|
|
83
|
-
expect(fromMathLive('\\sqrt{\\placeholder{7}}')).toEqual('\\sqrt{7}');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('handles a bare \\placeholder with no argument', () => {
|
|
87
|
-
expect(fromMathLive('\\longdiv{\\placeholder}')).toEqual('\\longdiv{}');
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('never leaks the token \\placeholder', () => {
|
|
91
|
-
['\\longdiv{\\placeholder{}}', '\\frac{\\placeholder{}}{x}', '\\placeholder{}'].forEach((l) => {
|
|
92
|
-
expect(fromMathLive(l)).not.toContain('\\placeholder');
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('still maps NAMED placeholders to answer blocks', () => {
|
|
97
|
-
// named ones are answer blocks and must survive
|
|
98
|
-
expect(fromMathLive('\\placeholder[r1]{}')).toEqual('\\MathQuillMathField[r1]{}');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('round-trips answer blocks combined with newlines', () => {
|
|
102
|
-
const stored = `\\MathQuillMathField[r1]{}${NEWLINE_EMBED}y`;
|
|
103
|
-
|
|
104
|
-
expect(fromMathLive(toMathLive(stored))).toEqual(stored);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// A MathLive macro serialises from the arguments it was created with, so text
|
|
109
|
-
// typed inside its expansion never comes back out of getValue('latex').
|
|
110
|
-
// Argument-taking pie commands must therefore become native constructs before
|
|
111
|
-
// they reach a mathfield.
|
|
112
|
-
describe('toNativeCommands', () => {
|
|
113
|
-
it('expands \\longdiv to native \\enclose', () => {
|
|
114
|
-
expect(toNativeCommands('\\longdiv{1234}')).toEqual('\\enclose{longdiv}{1234}');
|
|
115
|
-
expect(toNativeCommands('\\longdiv{}')).toEqual('\\enclose{longdiv}{}');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('expands \\overarc to native \\overparen', () => {
|
|
119
|
-
expect(toNativeCommands('\\overarc{AB}')).toEqual('\\overparen{AB}');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('expands \\abs to native \\left|..\\right|', () => {
|
|
123
|
-
expect(toNativeCommands('\\abs{x}')).toEqual('\\left|x\\right|');
|
|
124
|
-
expect(toNativeCommands('\\abs{}')).toEqual('\\left|\\right|');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('handles nested braces inside \\abs', () => {
|
|
128
|
-
expect(toNativeCommands('\\abs{\\frac{1}{2}}')).toEqual('\\left|\\frac{1}{2}\\right|');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('handles several occurrences', () => {
|
|
132
|
-
expect(toNativeCommands('\\abs{a}+\\abs{b}')).toEqual('\\left|a\\right|+\\left|b\\right|');
|
|
133
|
-
expect(toNativeCommands('\\longdiv{1}\\longdiv{2}')).toEqual('\\enclose{longdiv}{1}\\enclose{longdiv}{2}');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('leaves other latex untouched', () => {
|
|
137
|
-
['\\frac{1}{2}', '\\pi', '\\sqrt{x}', '\\overline{AB}'].forEach((l) => {
|
|
138
|
-
expect(toNativeCommands(l)).toEqual(l);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('handles nullish input', () => {
|
|
143
|
-
expect(toNativeCommands(undefined)).toEqual('');
|
|
144
|
-
expect(toNativeCommands('')).toEqual('');
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('is applied by toMathLive', () => {
|
|
148
|
-
expect(toMathLive('\\longdiv{5}')).toEqual('\\enclose{longdiv}{5}');
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('does not leave a pie macro in what reaches the field', () => {
|
|
152
|
-
['\\longdiv{7}', '\\abs{7}', '\\overarc{7}'].forEach((l) => {
|
|
153
|
-
const out = toMathLive(l);
|
|
154
|
-
|
|
155
|
-
expect(out).not.toMatch(/\\longdiv|\\abs|\\overarc/);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
describe('fieldIds', () => {
|
|
161
|
-
it('returns ids in document order', () => {
|
|
162
|
-
expect(fieldIds('\\MathQuillMathField[r1]{}+\\MathQuillMathField[r2]{}')).toEqual(['r1', 'r2']);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('returns [] when there are none', () => {
|
|
166
|
-
expect(fieldIds('x+y')).toEqual([]);
|
|
167
|
-
expect(fieldIds(undefined)).toEqual([]);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('is repeatable (regex lastIndex is reset)', () => {
|
|
171
|
-
const latex = '\\MathQuillMathField[r1]{}';
|
|
172
|
-
|
|
173
|
-
expect(fieldIds(latex)).toEqual(['r1']);
|
|
174
|
-
expect(fieldIds(latex)).toEqual(['r1']);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
describe('keyToAction', () => {
|
|
179
|
-
it('prefers latex when there is no command', () => {
|
|
180
|
-
expect(keyToAction({ latex: '\\pi', write: 'p' })).toEqual({ type: 'insert', value: '\\pi' });
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('uses write', () => {
|
|
184
|
-
expect(keyToAction({ write: 'x' })).toEqual({ type: 'insert', value: 'x' });
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('expands commands that take arguments into placeholders', () => {
|
|
188
|
-
expect(keyToAction({ command: '\\frac' })).toEqual({ type: 'insert', value: '\\frac{#?}{#?}' });
|
|
189
|
-
expect(keyToAction({ command: '\\sqrt' })).toEqual({ type: 'insert', value: '\\sqrt{#?}' });
|
|
190
|
-
expect(keyToAction({ command: '^' })).toEqual({ type: 'insert', value: '^{#?}' });
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('passes argument-less commands through', () => {
|
|
194
|
-
expect(keyToAction({ command: '\\pi' })).toEqual({ type: 'insert', value: '\\pi' });
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('concatenates array commands (MathQuill cmd() applied them in sequence)', () => {
|
|
198
|
-
// Measured Angle
|
|
199
|
-
expect(keyToAction({ command: ['m', '\\angle'] })).toEqual({ type: 'insert', value: 'm\\angle' });
|
|
200
|
-
// log base n - the `_` part must still expand to a placeholder
|
|
201
|
-
expect(keyToAction({ command: ['\\log', '_'] })).toEqual({ type: 'insert', value: '\\log_{#?}' });
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('always returns a string value for insert actions', () => {
|
|
205
|
-
[{ command: ['m', '\\angle'] }, { command: '\\frac' }, { write: 'x' }, { latex: '\\pi' }].forEach((k) => {
|
|
206
|
-
expect(typeof keyToAction(k).value).toBe('string');
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('maps keystrokes to MathLive selectors', () => {
|
|
211
|
-
expect(keyToAction({ keystroke: 'Left' })).toEqual({ type: 'command', value: 'moveToPreviousChar' });
|
|
212
|
-
expect(keyToAction({ keystroke: 'Right' })).toEqual({ type: 'command', value: 'moveToNextChar' });
|
|
213
|
-
expect(keyToAction({ keystroke: 'Backspace' })).toEqual({ type: 'command', value: 'deleteBackward' });
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('returns undefined for unknown/empty input', () => {
|
|
217
|
-
expect(keyToAction(undefined)).toBeUndefined();
|
|
218
|
-
expect(keyToAction({})).toBeUndefined();
|
|
219
|
-
expect(keyToAction({ keystroke: 'Nope' })).toBeUndefined();
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
it('latex wins over command only when command is absent', () => {
|
|
223
|
-
// a key with both should use the command path (matches MathInput.keypadPress)
|
|
224
|
-
expect(keyToAction({ latex: '\\frac{}{}', command: '\\frac' })).toEqual({
|
|
225
|
-
type: 'insert',
|
|
226
|
-
value: '\\frac{#?}{#?}',
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
});
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
describe('mathlive-instance', () => {
|
|
2
|
-
let instance;
|
|
3
|
-
|
|
4
|
-
beforeEach(() => {
|
|
5
|
-
jest.resetModules();
|
|
6
|
-
// eslint-disable-next-line global-require
|
|
7
|
-
instance = require('../mathlive-instance');
|
|
8
|
-
instance.__resetEmbeds();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
describe('registerEmbed', () => {
|
|
12
|
-
it('registers a known embed and exposes it as a macro', () => {
|
|
13
|
-
instance.registerEmbed('answerBlock', () => ({
|
|
14
|
-
htmlString: '<div class="answerBlock"></div>',
|
|
15
|
-
latex: () => '\\embed{answerBlock}[]',
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
expect(instance.registeredEmbeds()).toEqual(['answerBlock']);
|
|
19
|
-
// The macro tags output with data-embed so CSS can target it, replacing
|
|
20
|
-
// MathQuill's htmlString hook.
|
|
21
|
-
expect(instance.getMacros().answerBlock).toEqual('\\htmlData{embed=answerBlock}{\\placeholder{}}');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('registers newLine as a harmless macro (it is handled by latex-bridge)', () => {
|
|
25
|
-
instance.registerEmbed('newLine', () => ({ latex: () => '\\embed{newLine}[]' }));
|
|
26
|
-
|
|
27
|
-
expect(instance.getMacros().newLine).toEqual('\\htmlData{embed=newLine}{}');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('falls back to a placeholder for an unknown embed', () => {
|
|
31
|
-
instance.registerEmbed('somethingCustom', () => ({ htmlString: '<b>x</b>' }));
|
|
32
|
-
|
|
33
|
-
expect(instance.getMacros().somethingCustom).toEqual('\\htmlData{embed=somethingCustom}{\\placeholder{}}');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('honours an explicit mathliveLatex from the factory', () => {
|
|
37
|
-
instance.registerEmbed('custom', () => ({ mathliveLatex: '\\alpha' }));
|
|
38
|
-
|
|
39
|
-
expect(instance.getMacros().custom).toEqual('\\htmlData{embed=custom}{\\alpha}');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('does not throw when the factory throws', () => {
|
|
43
|
-
expect(() =>
|
|
44
|
-
instance.registerEmbed('bad', () => {
|
|
45
|
-
throw new Error('boom');
|
|
46
|
-
}),
|
|
47
|
-
).not.toThrow();
|
|
48
|
-
|
|
49
|
-
expect(instance.registeredEmbeds()).toEqual(['bad']);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('ignores bad arguments', () => {
|
|
53
|
-
instance.registerEmbed(undefined, () => ({}));
|
|
54
|
-
instance.registerEmbed('noFactory', undefined);
|
|
55
|
-
|
|
56
|
-
expect(instance.registeredEmbeds()).toEqual([]);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('always includes the pie macro set', () => {
|
|
60
|
-
const macros = instance.getMacros();
|
|
61
|
-
|
|
62
|
-
expect(macros.parallelogram).toBeDefined();
|
|
63
|
-
expect(macros.longdiv).toBeDefined();
|
|
64
|
-
expect(macros.napprox).toEqual('\\not\\approx');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Argument-taking macros exist only so previously authored latex parses.
|
|
68
|
-
// Editing never goes through them: MathLive serialises a macro from its
|
|
69
|
-
// original arguments, so typed content never comes back out.
|
|
70
|
-
it('argument-taking macros are plain parse-only definitions', () => {
|
|
71
|
-
['longdiv', 'overarc', 'abs'].forEach((name) => {
|
|
72
|
-
expect(typeof instance.PIE_MACROS[name]).toBe('string');
|
|
73
|
-
expect(instance.PIE_MACROS[name]).toContain('#1');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('argument-less symbols stay atomic', () => {
|
|
78
|
-
['perpendicular', 'square', 'degree', 'napprox', 'parallelogram'].forEach((name) => {
|
|
79
|
-
expect(typeof instance.PIE_MACROS[name]).toBe('string');
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('longdiv matches the MathJax macro used by math-rendering', () => {
|
|
84
|
-
expect(instance.PIE_MACROS.longdiv).toEqual('\\enclose{longdiv}{#1}');
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe('applyStaticMath', () => {
|
|
89
|
-
it('returns undefined without an element', () => {
|
|
90
|
-
expect(instance.applyStaticMath(null, 'x')).toBeUndefined();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('defers (returns undefined) when MathLive has not loaded', () => {
|
|
94
|
-
const el = document.createElement('div');
|
|
95
|
-
|
|
96
|
-
expect(instance.applyStaticMath(el, 'x')).toBeUndefined();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('renders synchronously once MathLive is available', () => {
|
|
100
|
-
const el = document.createElement('div');
|
|
101
|
-
|
|
102
|
-
instance.__setMathLiveForTest({ convertLatexToMarkup: (l) => `<span>${l}</span>` });
|
|
103
|
-
|
|
104
|
-
expect(instance.applyStaticMath(el, '\\pi')).toBe(el);
|
|
105
|
-
expect(el.innerHTML).toEqual('<span>\\pi</span>');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('falls back to the element textContent when no latex is passed', () => {
|
|
109
|
-
const el = document.createElement('div');
|
|
110
|
-
|
|
111
|
-
el.textContent = '\\theta';
|
|
112
|
-
instance.__setMathLiveForTest({ convertLatexToMarkup: (l) => `<i>${l}</i>` });
|
|
113
|
-
instance.applyStaticMath(el);
|
|
114
|
-
|
|
115
|
-
expect(el.innerHTML).toEqual('<i>\\theta</i>');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('bridges stored latex (newLine embed) before rendering', () => {
|
|
119
|
-
const el = document.createElement('div');
|
|
120
|
-
|
|
121
|
-
instance.__setMathLiveForTest({ convertLatexToMarkup: (l) => l });
|
|
122
|
-
instance.applyStaticMath(el, 'a\\embed{newLine}[]b');
|
|
123
|
-
|
|
124
|
-
// \embed{newLine}[] must become a multiline environment
|
|
125
|
-
expect(el.innerHTML).toContain('displaylines');
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
describe('configureFonts', () => {
|
|
130
|
-
// MathLive's default fontsDirectory is the relative './fonts/', which it
|
|
131
|
-
// resolves against its own (empty, when bundled) script url and throws
|
|
132
|
-
// "Invalid base URL" from loadFonts. Paths must become absolute.
|
|
133
|
-
it('is exported and callable before MathLive loads', () => {
|
|
134
|
-
expect(typeof instance.configureFonts).toBe('function');
|
|
135
|
-
expect(() => instance.configureFonts('/mathlive-fonts')).not.toThrow();
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('accepts null to disable font loading', () => {
|
|
139
|
-
expect(() => instance.configureFonts(null)).not.toThrow();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('applies an absolute url to an already-loaded MathfieldElement', () => {
|
|
143
|
-
const MathfieldElement = {};
|
|
144
|
-
|
|
145
|
-
// simulate a loaded instance
|
|
146
|
-
instance.__setMathLiveForTest({ MathfieldElement });
|
|
147
|
-
instance.configureFonts('/mathlive-fonts');
|
|
148
|
-
|
|
149
|
-
expect(MathfieldElement.fontsDirectory).toEqual(`${document.baseURI.replace(/\/$/, '')}/mathlive-fonts`);
|
|
150
|
-
expect(MathfieldElement.fontsDirectory.startsWith('http')).toBe(true);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it('leaves a fully-qualified url untouched', () => {
|
|
154
|
-
const MathfieldElement = {};
|
|
155
|
-
|
|
156
|
-
instance.__setMathLiveForTest({ MathfieldElement });
|
|
157
|
-
instance.configureFonts('https://cdn.example.com/fonts');
|
|
158
|
-
|
|
159
|
-
expect(MathfieldElement.fontsDirectory).toEqual('https://cdn.example.com/fonts');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('passes null through rather than resolving it', () => {
|
|
163
|
-
const MathfieldElement = {};
|
|
164
|
-
|
|
165
|
-
instance.__setMathLiveForTest({ MathfieldElement });
|
|
166
|
-
instance.configureFonts(null);
|
|
167
|
-
|
|
168
|
-
expect(MathfieldElement.fontsDirectory).toBeNull();
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe('latexToMarkup', () => {
|
|
173
|
-
it('returns empty string when MathLive is not loaded', () => {
|
|
174
|
-
expect(instance.latexToMarkup('\\pi')).toEqual('');
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('returns empty string for empty latex', () => {
|
|
178
|
-
expect(instance.latexToMarkup('')).toEqual('');
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
});
|