temml 0.11.0 → 0.11.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 +1 -1
- package/dist/temml.cjs +3696 -3470
- package/dist/temml.js +2830 -2604
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +3696 -3470
- package/dist/temmlPostProcess.js +2 -1
- package/package.json +1 -1
- package/src/ParseError.js +1 -1
- package/src/environments/array.js +81 -34
- package/src/environments/borderTree.js +139 -0
- package/src/functions/bordermatrix.js +42 -0
- package/src/functions.js +1 -0
- package/src/postProcess.js +2 -1
- package/temml.js +1 -1
package/dist/temmlPostProcess.js
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
* https://mit-license.org/
|
12
12
|
*/
|
13
13
|
|
14
|
-
const version = "0.11.
|
14
|
+
const version = "0.11.01";
|
15
15
|
|
16
16
|
function postProcess(block) {
|
17
17
|
const labelMap = {};
|
@@ -72,6 +72,7 @@
|
|
72
72
|
mtext.appendChild(document.createTextNode(str));
|
73
73
|
const math = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math");
|
74
74
|
math.appendChild(mtext);
|
75
|
+
ref.textContent = '';
|
75
76
|
ref.appendChild(math);
|
76
77
|
});
|
77
78
|
}
|
package/package.json
CHANGED
package/src/ParseError.js
CHANGED
@@ -27,7 +27,7 @@ class ParseError {
|
|
27
27
|
if (start === input.length) {
|
28
28
|
error += " at end of input: ";
|
29
29
|
} else {
|
30
|
-
error += " at position " + (start + 1) + ": ";
|
30
|
+
error += " at position " + (start + 1) + ": \n";
|
31
31
|
}
|
32
32
|
|
33
33
|
// Underline token in question using combining underscores
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import defineEnvironment from "../defineEnvironment";
|
2
2
|
import { parseCD } from "./cd";
|
3
|
+
import { bordermatrixParseTree } from "./borderTree.js"
|
3
4
|
import defineFunction from "../defineFunction";
|
4
5
|
import mathMLTree from "../mathMLTree";
|
5
6
|
import { Span } from "../domTree"
|
@@ -103,6 +104,7 @@ function parseArray(
|
|
103
104
|
},
|
104
105
|
scriptLevel
|
105
106
|
) {
|
107
|
+
const endToken = envClasses && envClasses.includes("bordermatrix") ? "}" : "\\end"
|
106
108
|
parser.gullet.beginGroup();
|
107
109
|
if (!singleRow) {
|
108
110
|
// \cr is equivalent to \\ without the optional size argument (see below)
|
@@ -176,7 +178,7 @@ function parseArray(
|
|
176
178
|
}
|
177
179
|
}
|
178
180
|
parser.consume();
|
179
|
-
} else if (next ===
|
181
|
+
} else if (next === endToken) {
|
180
182
|
endRow()
|
181
183
|
// Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
182
184
|
// the last line is empty. However, AMS environments keep the
|
@@ -213,7 +215,7 @@ function parseArray(
|
|
213
215
|
body.push(row);
|
214
216
|
beginRow();
|
215
217
|
} else {
|
216
|
-
throw new ParseError("Expected & or \\\\ or \\cr or
|
218
|
+
throw new ParseError("Expected & or \\\\ or \\cr or " + endToken, parser.nextToken);
|
217
219
|
}
|
218
220
|
}
|
219
221
|
|
@@ -346,23 +348,44 @@ const mathmlBuilder = function(group, style) {
|
|
346
348
|
})
|
347
349
|
}
|
348
350
|
}
|
349
|
-
|
351
|
+
|
352
|
+
// Check for \hphantom \from \bordermatrix
|
353
|
+
let mustSquashRow = true
|
354
|
+
for (let j = 0; j < mtr.children.length; j++) {
|
355
|
+
const child = mtr.children[j].children[0];
|
356
|
+
if (!(child && child.type === "mpadded" && child.attributes.height === "0px")) {
|
357
|
+
mustSquashRow = false
|
358
|
+
break
|
359
|
+
}
|
360
|
+
}
|
361
|
+
if (mustSquashRow) {
|
362
|
+
// All the cell contents are \hphantom. Squash the padding.
|
363
|
+
for (let j = 0; j < mtr.children.length; j++) {
|
364
|
+
mtr.children[j].style.paddingTop = "0"
|
365
|
+
mtr.children[j].style.paddingBottom = "0"
|
366
|
+
}
|
367
|
+
}
|
368
|
+
|
369
|
+
tbl.push(mtr)
|
350
370
|
}
|
351
371
|
|
352
|
-
if (group.
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
for (let
|
359
|
-
|
360
|
-
|
361
|
-
tbl[i].children[j].style.paddingBottom = pad
|
362
|
-
}
|
372
|
+
if (group.arraystretch && group.arraystretch !== 1) {
|
373
|
+
// In LaTeX, \arraystretch is a factor applied to a 12pt strut height.
|
374
|
+
// It defines a baseline to baseline distance.
|
375
|
+
// Here, we do an approximation of that approach.
|
376
|
+
const pad = String(1.4 * group.arraystretch - 0.8) + "ex"
|
377
|
+
for (let i = 0; i < tbl.length; i++) {
|
378
|
+
for (let j = 0; j < tbl[i].children.length; j++) {
|
379
|
+
tbl[i].children[j].style.paddingTop = pad
|
380
|
+
tbl[i].children[j].style.paddingBottom = pad
|
363
381
|
}
|
364
382
|
}
|
365
|
-
|
383
|
+
}
|
384
|
+
|
385
|
+
let sidePadding
|
386
|
+
let sidePadUnit
|
387
|
+
if (group.envClasses.length > 0) {
|
388
|
+
sidePadding = group.envClasses.includes("abut")
|
366
389
|
? "0"
|
367
390
|
: group.envClasses.includes("cases")
|
368
391
|
? "0"
|
@@ -371,13 +394,14 @@ const mathmlBuilder = function(group, style) {
|
|
371
394
|
: group.envClasses.includes("cd")
|
372
395
|
? "0.25"
|
373
396
|
: "0.4" // default side padding
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
397
|
+
sidePadUnit = "em"
|
398
|
+
}
|
399
|
+
if (group.arraycolsep) {
|
400
|
+
const arraySidePad = calculateSize(group.arraycolsep, style)
|
401
|
+
sidePadding = arraySidePad.number.toFixed(4)
|
402
|
+
sidePadUnit = arraySidePad.unit
|
403
|
+
}
|
404
|
+
if (sidePadding) {
|
381
405
|
const numCols = tbl.length === 0 ? 0 : tbl[0].children.length
|
382
406
|
|
383
407
|
const sidePad = (j, hand) => {
|
@@ -399,7 +423,18 @@ const mathmlBuilder = function(group, style) {
|
|
399
423
|
tbl[i].children[j].style.paddingRight = `${sidePad(j, 1)}${sidePadUnit}`
|
400
424
|
}
|
401
425
|
}
|
426
|
+
}
|
427
|
+
if (group.envClasses.length === 0) {
|
428
|
+
// Set zero padding on side of the matrix
|
429
|
+
for (let i = 0; i < tbl.length; i++) {
|
430
|
+
tbl[i].children[0].style.paddingLeft = "0em"
|
431
|
+
if (tbl[i].children.length === tbl[0].children.length) {
|
432
|
+
tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em"
|
433
|
+
}
|
434
|
+
}
|
435
|
+
}
|
402
436
|
|
437
|
+
if (group.envClasses.length > 0) {
|
403
438
|
// Justification
|
404
439
|
const align = group.envClasses.includes("align") || group.envClasses.includes("alignat")
|
405
440
|
for (let i = 0; i < tbl.length; i++) {
|
@@ -425,14 +460,6 @@ const mathmlBuilder = function(group, style) {
|
|
425
460
|
}
|
426
461
|
}
|
427
462
|
}
|
428
|
-
} else {
|
429
|
-
// Set zero padding on side of the matrix
|
430
|
-
for (let i = 0; i < tbl.length; i++) {
|
431
|
-
tbl[i].children[0].style.paddingLeft = "0em"
|
432
|
-
if (tbl[i].children.length === tbl[0].children.length) {
|
433
|
-
tbl[i].children[tbl[i].children.length - 1].style.paddingRight = "0em"
|
434
|
-
}
|
435
|
-
}
|
436
463
|
}
|
437
464
|
|
438
465
|
let table = new mathMLTree.MathNode("mtable", tbl)
|
@@ -672,7 +699,7 @@ defineEnvironment({
|
|
672
699
|
mathmlBuilder
|
673
700
|
});
|
674
701
|
|
675
|
-
// The matrix environments of amsmath
|
702
|
+
// The matrix environments of amsmath build on the array environment
|
676
703
|
// of LaTeX, which is discussed above.
|
677
704
|
// The mathtools package adds starred versions of the same environments.
|
678
705
|
// These have an optional argument to choose left|center|right justification.
|
@@ -732,6 +759,10 @@ defineEnvironment({
|
|
732
759
|
const res = parseArray(context.parser, payload, "text")
|
733
760
|
res.cols = new Array(res.body[0].length).fill({ type: "align", align: colAlign })
|
734
761
|
const [arraystretch, arraycolsep] = arrayGaps(context.parser.gullet.macros)
|
762
|
+
res.arraystretch = arraystretch
|
763
|
+
if (arraycolsep && !(arraycolsep === 6 && arraycolsep === "pt")) {
|
764
|
+
res.arraycolsep = arraycolsep
|
765
|
+
}
|
735
766
|
return delimiters
|
736
767
|
? {
|
737
768
|
type: "leftright",
|
@@ -739,15 +770,31 @@ defineEnvironment({
|
|
739
770
|
body: [res],
|
740
771
|
left: delimiters[0],
|
741
772
|
right: delimiters[1],
|
742
|
-
rightColor: undefined
|
743
|
-
arraystretch,
|
744
|
-
arraycolsep
|
773
|
+
rightColor: undefined // \right uninfluenced by \color in array
|
745
774
|
}
|
746
775
|
: res;
|
747
776
|
},
|
748
777
|
mathmlBuilder
|
749
778
|
});
|
750
779
|
|
780
|
+
defineEnvironment({
|
781
|
+
type: "array",
|
782
|
+
names: ["bordermatrix"],
|
783
|
+
props: {
|
784
|
+
numArgs: 0
|
785
|
+
},
|
786
|
+
handler(context) {
|
787
|
+
const payload = { cols: [], envClasses: ["bordermatrix"] }
|
788
|
+
const res = parseArray(context.parser, payload, "text")
|
789
|
+
res.cols = new Array(res.body[0].length).fill({ type: "align", align: "c" })
|
790
|
+
res.envClasses = [];
|
791
|
+
res.arraystretch = 1
|
792
|
+
if (context.envName === "matrix") { return res}
|
793
|
+
return bordermatrixParseTree(res, context.delimiters)
|
794
|
+
},
|
795
|
+
mathmlBuilder
|
796
|
+
});
|
797
|
+
|
751
798
|
defineEnvironment({
|
752
799
|
type: "array",
|
753
800
|
names: ["smallmatrix"],
|
@@ -0,0 +1,139 @@
|
|
1
|
+
|
2
|
+
const ordGroup = (body) => {
|
3
|
+
return {
|
4
|
+
"type": "ordgroup",
|
5
|
+
"mode": "math",
|
6
|
+
"body": body,
|
7
|
+
"semisimple": true
|
8
|
+
}
|
9
|
+
}
|
10
|
+
|
11
|
+
const phantom = (body, type) => {
|
12
|
+
return {
|
13
|
+
"type": type,
|
14
|
+
"mode": "math",
|
15
|
+
"body": ordGroup(body)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
/*
|
20
|
+
* A helper for \bordermatrix.
|
21
|
+
* parseArray() has parsed the tokens as if the environment
|
22
|
+
* was \begin{matrix}. That parse tree is this function’s input.
|
23
|
+
* Here, we rearrange the parse tree to get one that will
|
24
|
+
* result in TeX \bordermatrix.
|
25
|
+
* The final result includes a {pmatrix}, which is the bottom
|
26
|
+
* half of a <mover> element. The top of the <mover> contains
|
27
|
+
* the \bordermatrix headings. The top section also contains the
|
28
|
+
* contents of the bottom {pmatrix}. Those elements are hidden via
|
29
|
+
* \hphantom, but they ensure that column widths are the same top and
|
30
|
+
* bottom.
|
31
|
+
*
|
32
|
+
* We also create a left {matrix} with a single column that contains
|
33
|
+
* elements shifted out of the matrix. The left {matrix} also
|
34
|
+
* contains \vphantom copies of the other {pmatrix} elements.
|
35
|
+
* As before, this ensures consistent row heights of left and main.
|
36
|
+
*/
|
37
|
+
|
38
|
+
export const bordermatrixParseTree = (matrix, delimiters) => {
|
39
|
+
const body = matrix.body
|
40
|
+
body[0].shift() // dispose of top left cell
|
41
|
+
|
42
|
+
// Create an array for the left column
|
43
|
+
const leftColumnBody = new Array(body.length - 1).fill().map(() => [])
|
44
|
+
for (let i = 1; i < body.length; i++) {
|
45
|
+
// The visible part of the cell
|
46
|
+
leftColumnBody[i - 1].push(body[i].shift())
|
47
|
+
// A vphantom with contents from the pmatrix, to set minimum cell height
|
48
|
+
const phantomBody = [];
|
49
|
+
for (let j = 0; j < body[i].length; j++) {
|
50
|
+
phantomBody.push(structuredClone(body[i][j]))
|
51
|
+
}
|
52
|
+
leftColumnBody[i - 1].push(phantom(phantomBody, "vphantom"))
|
53
|
+
}
|
54
|
+
|
55
|
+
// Create an array for the top row
|
56
|
+
const topRowBody = new Array(body.length).fill().map(() => [])
|
57
|
+
for (let j = 0; j < body[0].length; j++) {
|
58
|
+
topRowBody[0].push(structuredClone(body[0][j]))
|
59
|
+
}
|
60
|
+
// Copy the rest of the pmatrix, but squashed via \hphantom
|
61
|
+
for (let i = 1; i < body.length; i++) {
|
62
|
+
for (let j = 0; j < body[0].length; j++) {
|
63
|
+
topRowBody[i].push(phantom(structuredClone(body[i][j]).body, "hphantom"))
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
// Squash the top row of the main {pmatrix}
|
68
|
+
for (let j = 0; j < body[0].length; j++) {
|
69
|
+
body[0][j] = phantom(structuredClone(body[0][j]).body, "hphantom")
|
70
|
+
}
|
71
|
+
|
72
|
+
// Now wrap the arrays in the proper parse nodes.
|
73
|
+
|
74
|
+
const leftColumn = {
|
75
|
+
type: "array",
|
76
|
+
mode: "math",
|
77
|
+
body: leftColumnBody,
|
78
|
+
cols: [{ type: "align", align: "c" }],
|
79
|
+
rowGaps: new Array(leftColumnBody.length - 1).fill(null),
|
80
|
+
hLinesBeforeRow: new Array(leftColumnBody.length + 1).fill().map(() => []),
|
81
|
+
envClasses: [],
|
82
|
+
scriptLevel: "text",
|
83
|
+
arraystretch: 1,
|
84
|
+
labels: new Array(leftColumnBody.length).fill(""),
|
85
|
+
arraycolsep: { "number": 0.04, unit: "em" }
|
86
|
+
}
|
87
|
+
|
88
|
+
const topRow = {
|
89
|
+
type: "array",
|
90
|
+
mode: "math",
|
91
|
+
body: topRowBody,
|
92
|
+
cols: new Array(topRowBody.length).fill({ type: "align", align: "c" }),
|
93
|
+
rowGaps: new Array(topRowBody.length - 1).fill(null),
|
94
|
+
hLinesBeforeRow: new Array(topRowBody.length + 1).fill().map(() => []),
|
95
|
+
envClasses: [],
|
96
|
+
scriptLevel: "text",
|
97
|
+
arraystretch: 1,
|
98
|
+
labels: new Array(topRowBody.length).fill(""),
|
99
|
+
arraycolsep: null
|
100
|
+
}
|
101
|
+
|
102
|
+
const topWrapper = {
|
103
|
+
type: "styling",
|
104
|
+
mode: "math",
|
105
|
+
scriptLevel: "text", // Must set this explicitly.
|
106
|
+
body: [topRow] // Default level is "script".
|
107
|
+
}
|
108
|
+
|
109
|
+
const container = {
|
110
|
+
type: "leftright",
|
111
|
+
mode: "math",
|
112
|
+
body: [matrix],
|
113
|
+
left: delimiters ? delimiters[0] : "(",
|
114
|
+
right: delimiters ? delimiters[1] : ")",
|
115
|
+
rightColor: undefined
|
116
|
+
}
|
117
|
+
|
118
|
+
const base = {
|
119
|
+
type: "op", // The base of a TeX \overset
|
120
|
+
mode: "math",
|
121
|
+
limits: true,
|
122
|
+
alwaysHandleSupSub: true,
|
123
|
+
parentIsSupSub: true,
|
124
|
+
symbol: false,
|
125
|
+
stack: true,
|
126
|
+
suppressBaseShift: true,
|
127
|
+
body: [container]
|
128
|
+
}
|
129
|
+
|
130
|
+
const mover = {
|
131
|
+
type: "supsub", // We're using the MathML equivalent
|
132
|
+
mode: "math", // of TeX \overset.
|
133
|
+
base: base, // That keeps the {pmatrix} aligned with
|
134
|
+
sup: topWrapper, // the math centerline.
|
135
|
+
sub: null
|
136
|
+
}
|
137
|
+
|
138
|
+
return ordGroup([leftColumn, mover])
|
139
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import defineFunction from "../defineFunction"
|
2
|
+
import environments from "../environments"
|
3
|
+
|
4
|
+
// \bordermatrix from TeXbook pp 177 & 361
|
5
|
+
// Optional argument from Herbert Voß, Math mode, p 20
|
6
|
+
// Ref: https://tug.ctan.org/obsolete/info/math/voss/mathmode/Mathmode.pdf
|
7
|
+
|
8
|
+
defineFunction({
|
9
|
+
type: "bordermatrix",
|
10
|
+
names: ["\\bordermatrix", "\\matrix"],
|
11
|
+
props: {
|
12
|
+
numArgs: 0,
|
13
|
+
numOptionalArgs: 1
|
14
|
+
},
|
15
|
+
handler: ({ parser, funcName }, args, optArgs) => {
|
16
|
+
// Find out if the author has defined custom delimiters
|
17
|
+
let delimiters = ["(", ")"]
|
18
|
+
if (funcName === "\\bordermatrix" && optArgs[0] && optArgs[0].body) {
|
19
|
+
const body = optArgs[0].body
|
20
|
+
if (body.length === 2 && body[0].type === "atom" && body[1].type === "atom") {
|
21
|
+
if (body[0].family === "open" && body[1].family === "close") {
|
22
|
+
delimiters = [body[0].text, body[1].text]
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
// consume the opening brace
|
27
|
+
parser.consumeSpaces()
|
28
|
+
parser.consume()
|
29
|
+
|
30
|
+
// Pass control to the environment handler in array.js.
|
31
|
+
const env = environments["bordermatrix"];
|
32
|
+
const context = {
|
33
|
+
mode: parser.mode,
|
34
|
+
envName: funcName.slice(1),
|
35
|
+
delimiters,
|
36
|
+
parser
|
37
|
+
}
|
38
|
+
const result = env.handler(context)
|
39
|
+
parser.expect("}", true)
|
40
|
+
return result
|
41
|
+
}
|
42
|
+
});
|
package/src/functions.js
CHANGED
package/src/postProcess.js
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
* https://mit-license.org/
|
6
6
|
*/
|
7
7
|
|
8
|
-
export const version = "0.11.
|
8
|
+
export const version = "0.11.01";
|
9
9
|
|
10
10
|
export function postProcess(block) {
|
11
11
|
const labelMap = {}
|
@@ -66,6 +66,7 @@ export function postProcess(block) {
|
|
66
66
|
mtext.appendChild(document.createTextNode(str))
|
67
67
|
const math = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math")
|
68
68
|
math.appendChild(mtext)
|
69
|
+
ref.textContent = ''
|
69
70
|
ref.appendChild(math)
|
70
71
|
})
|
71
72
|
}
|
package/temml.js
CHANGED
@@ -104,7 +104,7 @@ const renderError = function(error, expression, options) {
|
|
104
104
|
if (options.throwOnError || !(error instanceof ParseError)) {
|
105
105
|
throw error;
|
106
106
|
}
|
107
|
-
const node = new Span(["temml-error"], [new TextNode(expression + "\n" + error.toString())]);
|
107
|
+
const node = new Span(["temml-error"], [new TextNode(expression + "\n\n" + error.toString())]);
|
108
108
|
node.style.color = options.errorColor
|
109
109
|
node.style.whiteSpace = "pre-line"
|
110
110
|
return node;
|