temml 0.11.6 → 0.11.8

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.
@@ -2,48 +2,62 @@ import defineFunction, { normalizeArgument } from "../defineFunction"
2
2
  import mathMLTree from "../mathMLTree"
3
3
  import stretchy from "../stretchy"
4
4
  import * as mml from "../buildMathML"
5
- import utils from "../utils"
6
5
 
6
+ // Identify letters to which we'll attach a combining accent character
7
7
  const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳"
8
- const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ"
9
- + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭"
10
- const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota",
11
- "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi",
12
- "\\omega", "\\imath", "\\jmath"])
13
- const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta",
14
- "\\lambda", "\\theta", "\\psi"])
8
+
9
+ // From the KaTeX font metrics, identify letters whose accents need a italic correction.
10
+ const smallNudge = "DHKLUcegorsuvxyzΠΥΨαδηιμνοτυχϵ"
11
+ const mediumNudge = "BCEGIMNOPQRSTXZlpqtwΓΘΞΣΦΩβεζθξρςφψϑϕϱ"
12
+ const largeNudge = "AFJdfΔΛ"
15
13
 
16
14
  const mathmlBuilder = (group, style) => {
17
15
  const accentNode = group.isStretchy
18
16
  ? stretchy.accentNode(group)
19
17
  : new mathMLTree.MathNode("mo", [mml.makeText(group.label, group.mode)]);
20
-
21
- if (group.label === "\\vec") {
22
- accentNode.style.transform = "scale(0.75) translate(10%, 30%)"
23
- } else {
24
- accentNode.style.mathStyle = "normal"
25
- accentNode.style.mathDepth = "0"
26
- if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) {
27
- let shift = ""
28
- const ch = group.base.text
29
- if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift" }
30
- if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift" }
31
- if (shift) { accentNode.classes.push(shift) }
32
- }
33
- }
34
18
  if (!group.isStretchy) {
35
- accentNode.setAttribute("stretchy", "false")
19
+ accentNode.setAttribute("stretchy", "false") // Keep Firefox from stretching \check
36
20
  }
37
-
38
- const node = new mathMLTree.MathNode((group.label === "\\c" ? "munder" : "mover"),
39
- [mml.buildGroup(group.base, style), accentNode]
40
- );
41
-
21
+ if (group.label !== "\\vec") {
22
+ accentNode.style.mathDepth = "0" // not scriptstyle
23
+ // Don't use attribute accent="true" because MathML Core eliminates a needed space.
24
+ }
25
+ const tag = group.label === "\\c" ? "munder" : "mover"
26
+ const needsWbkVertShift = needsWebkitVerticalShift.has(group.label)
27
+ if (tag === "mover" && group.mode === "math" && (!group.isStretchy) && group.base.text
28
+ && group.base.text.length === 1) {
29
+ const text = group.base.text
30
+ const isVec = group.label === "\\vec"
31
+ const vecPostfix = isVec === "\\vec" ? "-vec" : ""
32
+ if (isVec) {
33
+ accentNode.classes.push("tml-vec") // Firefox sizing of \vec arrow
34
+ }
35
+ const wbkPostfix = isVec ? "-vec" : needsWbkVertShift ? "-acc" : ""
36
+ if (smallNudge.indexOf(text) > -1) {
37
+ accentNode.classes.push(`chr-sml${vecPostfix}`)
38
+ accentNode.classes.push(`wbk-sml${wbkPostfix}`)
39
+ } else if (mediumNudge.indexOf(text) > -1) {
40
+ accentNode.classes.push(`chr-med${vecPostfix}`)
41
+ accentNode.classes.push(`wbk-med${wbkPostfix}`)
42
+ } else if (largeNudge.indexOf(text) > -1) {
43
+ accentNode.classes.push(`chr-lrg${vecPostfix}`)
44
+ accentNode.classes.push(`wbk-lrg${wbkPostfix}`)
45
+ } else if (isVec) {
46
+ accentNode.classes.push(`wbk-vec`)
47
+ } else if (needsWbkVertShift) {
48
+ accentNode.classes.push(`wbk-acc`)
49
+ }
50
+ } else if (needsWbkVertShift) {
51
+ // text-mode accents
52
+ accentNode.classes.push("wbk-acc")
53
+ }
54
+ const node = new mathMLTree.MathNode(tag, [mml.buildGroup(group.base, style), accentNode]);
42
55
  return node;
43
56
  };
44
57
 
45
58
  const nonStretchyAccents = new Set([
46
59
  "\\acute",
60
+ "\\check",
47
61
  "\\grave",
48
62
  "\\ddot",
49
63
  "\\dddot",
@@ -58,7 +72,7 @@ const nonStretchyAccents = new Set([
58
72
  "\\mathring"
59
73
  ])
60
74
 
61
- const needWebkitShift = new Set([
75
+ const needsWebkitVerticalShift = new Set([
62
76
  "\\acute",
63
77
  "\\bar",
64
78
  "\\breve",
@@ -68,7 +82,7 @@ const needWebkitShift = new Set([
68
82
  "\\grave",
69
83
  "\\hat",
70
84
  "\\mathring",
71
- "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"
85
+ "\\`", "\\'", "\\^", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"
72
86
  ])
73
87
 
74
88
  const combiningChar = {
@@ -82,7 +96,8 @@ const combiningChar = {
82
96
  '\\"': "\u0308",
83
97
  "\\r": "\u030A",
84
98
  "\\H": "\u030B",
85
- "\\v": "\u030C"
99
+ "\\v": "\u030C",
100
+ "\\c": "\u0327"
86
101
  }
87
102
 
88
103
  // Accents
@@ -127,8 +142,8 @@ defineFunction({
127
142
  type: "accent",
128
143
  mode: context.parser.mode,
129
144
  label: context.funcName,
130
- isStretchy: isStretchy,
131
- base: base
145
+ isStretchy,
146
+ base
132
147
  };
133
148
  },
134
149
  mathmlBuilder
@@ -155,21 +170,25 @@ defineFunction({
155
170
  }
156
171
 
157
172
  if (mode === "text" && base.text && base.text.length === 1
158
- && context.funcName in combiningChar && smalls.indexOf(base.text) > -1) {
173
+ && context.funcName in combiningChar && smalls.indexOf(base.text) > -1) {
159
174
  // Return a combining accent character
160
175
  return {
161
176
  type: "textord",
162
177
  mode: "text",
163
178
  text: base.text + combiningChar[context.funcName]
164
179
  }
180
+ } else if (context.funcName === "\\c" && mode === "text" && base.text
181
+ && base.text.length === 1) {
182
+ // combining cedilla
183
+ return { type: "textord", mode: "text", text: base.text + "\u0327" }
165
184
  } else {
166
185
  // Build up the accent
167
186
  return {
168
187
  type: "accent",
169
- mode: mode,
188
+ mode,
170
189
  label: context.funcName,
171
190
  isStretchy: false,
172
- base: base
191
+ base
173
192
  }
174
193
  }
175
194
  },
@@ -114,12 +114,17 @@ defineFunction({
114
114
  "\\xlongequal",
115
115
  "\\xtwoheadrightarrow",
116
116
  "\\xtwoheadleftarrow",
117
- // The next 5 functions are here only to support mhchem
117
+ "\\xtofrom", // expfeil
118
+ "\\xleftrightharpoons", // mathtools
119
+ "\\xrightleftharpoons", // mathtools
120
+ // The next 7 functions are here only to support mhchem
118
121
  "\\yields",
119
122
  "\\yieldsLeft",
120
123
  "\\mesomerism",
121
124
  "\\longrightharpoonup",
122
125
  "\\longleftharpoondown",
126
+ "\\yieldsLeftRight",
127
+ "\\chemequilibrium",
123
128
  // The next 3 functions are here only to support the {CD} environment.
124
129
  "\\\\cdrightarrow",
125
130
  "\\\\cdleftarrow",
@@ -150,26 +155,15 @@ defineFunction({
150
155
  });
151
156
 
152
157
  const arrowComponent = {
153
- "\\xtofrom": ["\\xrightarrow", "\\xleftarrow"],
154
- "\\xleftrightharpoons": ["\\xleftharpoonup", "\\xrightharpoondown"],
155
- "\\xrightleftharpoons": ["\\xrightharpoonup", "\\xleftharpoondown"],
156
- "\\yieldsLeftRight": ["\\yields", "\\yieldsLeft"],
157
- // The next three all get the same harpoon glyphs. Only the lengths and paddings differ.
158
- "\\equilibrium": ["\\longrightharpoonup", "\\longleftharpoondown"],
159
158
  "\\equilibriumRight": ["\\longrightharpoonup", "\\eqleftharpoondown"],
160
159
  "\\equilibriumLeft": ["\\eqrightharpoonup", "\\longleftharpoondown"]
161
160
  }
162
161
 
163
- // Browsers are not good at stretching a glyph that contains a pair of stacked arrows such as ⇄.
164
- // So we stack a pair of single arrows.
162
+ // Math fonts do not have a single glyph for these two mhchem functions.
163
+ // So we stack a pair of single harpoons.
165
164
  defineFunction({
166
165
  type: "stackedArrow",
167
166
  names: [
168
- "\\xtofrom", // expfeil
169
- "\\xleftrightharpoons", // mathtools
170
- "\\xrightleftharpoons", // mathtools
171
- "\\yieldsLeftRight", // mhchem
172
- "\\equilibrium", // mhchem
173
167
  "\\equilibriumRight",
174
168
  "\\equilibriumLeft"
175
169
  ],
@@ -71,7 +71,8 @@ const mathmlBuilder = (group, style) => {
71
71
  case "\\boxed":
72
72
  // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
73
73
  node.setAttribute("notation", "box")
74
- node.classes.push("tml-box")
74
+ node.style.padding = "padding: 3pt 0 3pt 0"
75
+ node.style.border = "1px solid"
75
76
  node.setAttribute("scriptlevel", "0")
76
77
  node.setAttribute("displaystyle", "true")
77
78
  break
@@ -45,17 +45,24 @@ defineFunction({
45
45
  },
46
46
  mathmlBuilder(group, style) {
47
47
  const dimension = calculateSize(group.dimension, style);
48
- const ch = dimension.unit === "em" ? spaceCharacter(dimension.number) : "";
48
+ const ch = dimension.number > 0 && dimension.unit === "em"
49
+ ? spaceCharacter(dimension.number)
50
+ : "";
49
51
  if (group.mode === "text" && ch.length > 0) {
50
52
  const character = new mathMLTree.TextNode(ch);
51
53
  return new mathMLTree.MathNode("mtext", [character]);
52
54
  } else {
53
- const node = new mathMLTree.MathNode("mspace");
54
- node.setAttribute("width", dimension.number + dimension.unit);
55
- if (dimension.number < 0) {
55
+ if (dimension.number >= 0) {
56
+ const node = new mathMLTree.MathNode("mspace")
57
+ node.setAttribute("width", dimension.number + dimension.unit)
58
+ return node
59
+ } else {
60
+ // Don't use <mspace> or <mpadded> because
61
+ // WebKit recognizes negative left margin only on a <mrow> element
62
+ const node = new mathMLTree.MathNode("mrow")
56
63
  node.style.marginLeft = dimension.number + dimension.unit
64
+ return node
57
65
  }
58
- return node;
59
66
  }
60
67
  }
61
68
  });
@@ -145,7 +145,9 @@ export const binrelClass = (arg) => {
145
145
  // (by rendering separately and with {}s before and after, and measuring
146
146
  // the change in spacing). We'll do roughly the same by detecting the
147
147
  // atom type directly.
148
- const atom = arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg;
148
+ const atom = arg.type === "ordgroup" && arg.body.length && arg.body.length === 1
149
+ ? arg.body[0]
150
+ : arg;
149
151
  if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) {
150
152
  return "m" + atom.family;
151
153
  } else {
@@ -183,14 +185,25 @@ defineFunction({
183
185
  const baseArg = args[1];
184
186
  const shiftedArg = args[0];
185
187
 
188
+ let mclass
189
+ if (funcName !== "\\stackrel") {
190
+ // LaTeX applies \binrel spacing to \overset and \underset.
191
+ mclass = binrelClass(baseArg)
192
+ } else {
193
+ mclass = "mrel" // for \stackrel
194
+ }
195
+
196
+ const baseType = mclass === "mrel" || mclass === "mbin"
197
+ ? "op"
198
+ : "ordgroup"
199
+
186
200
  const baseOp = {
187
- type: "op",
201
+ type: baseType,
188
202
  mode: baseArg.mode,
189
203
  limits: true,
190
204
  alwaysHandleSupSub: true,
191
205
  parentIsSupSub: false,
192
206
  symbol: false,
193
- stack: true,
194
207
  suppressBaseShift: funcName !== "\\stackrel",
195
208
  body: ordargument(baseArg)
196
209
  };
@@ -198,6 +211,7 @@ defineFunction({
198
211
  return {
199
212
  type: "supsub",
200
213
  mode: shiftedArg.mode,
214
+ stack: true,
201
215
  base: baseOp,
202
216
  sup: funcName === "\\underset" ? null : shiftedArg,
203
217
  sub: funcName === "\\underset" ? shiftedArg : null
@@ -0,0 +1,68 @@
1
+ import defineFunction from "../defineFunction";
2
+ import mathMLTree from "../mathMLTree";
3
+ import ParseError from "../ParseError"
4
+
5
+ const numRegEx = /^[0-9]$/
6
+ const unicodeNumSubs = {
7
+ '0': '₀',
8
+ '1': '₁',
9
+ '2': '₂',
10
+ '3': '₃',
11
+ '4': '₄',
12
+ '5': '₅',
13
+ '6': '₆',
14
+ '7': '₇',
15
+ '8': '₈',
16
+ '9': '₉'
17
+ }
18
+ const unicodeNumSups = {
19
+ '0': '⁰',
20
+ '1': '¹',
21
+ '2': '²',
22
+ '3': '³',
23
+ '4': '⁴',
24
+ '5': '⁵',
25
+ '6': '⁶',
26
+ '7': '⁷',
27
+ '8': '⁸',
28
+ '9': '⁹'
29
+ }
30
+
31
+ defineFunction({
32
+ type: "sfrac",
33
+ names: ["\\sfrac"],
34
+ props: {
35
+ numArgs: 2,
36
+ allowedInText: true,
37
+ allowedInMath: true
38
+ },
39
+ handler({ parser }, args) {
40
+ let numerator = ""
41
+ for (const node of args[0].body) {
42
+ if (node.type !== "textord" || !numRegEx.test(node.text)) {
43
+ throw new ParseError("Numerator must be an integer.", node)
44
+ }
45
+ numerator += node.text
46
+ }
47
+ let denominator = ""
48
+ for (const node of args[1].body) {
49
+ if (node.type !== "textord" || !numRegEx.test(node.text)) {
50
+ throw new ParseError("Denominator must be an integer.", node)
51
+ }
52
+ denominator += node.text
53
+ }
54
+ return {
55
+ type: "sfrac",
56
+ mode: parser.mode,
57
+ numerator,
58
+ denominator
59
+ };
60
+ },
61
+ mathmlBuilder(group, style) {
62
+ const numerator = group.numerator.split('').map(c => unicodeNumSups[c]).join('')
63
+ const denominator = group.denominator.split('').map(c => unicodeNumSubs[c]).join('')
64
+ // Use a fraction slash.
65
+ const text = new mathMLTree.TextNode(numerator + "\u2044" + denominator, group.mode, style)
66
+ return new mathMLTree.MathNode("mn", [text], ["special-fraction"])
67
+ }
68
+ });
@@ -14,6 +14,11 @@ import * as mml from "../buildMathML"
14
14
  // Helpers
15
15
  const symbolRegEx = /^m(over|under|underover)$/
16
16
 
17
+ // From the KaTeX font metrics, identify letters that encroach on a superscript.
18
+ const smallPad = "DHKLUcegorsuvxyzΠΥΨαδηιμνοτυχϵ"
19
+ const mediumPad = "BCEFGIMNOPQRSTXZlpqtwΓΘΞΣΦΩβεζθξρςφψϑϕϱ"
20
+ const largePad = "AJdfΔΛ"
21
+
17
22
  // Super scripts and subscripts, whose precise placement can depend on other
18
23
  // functions that precede them.
19
24
  defineFunctionBuilders({
@@ -35,7 +40,7 @@ defineFunctionBuilders({
35
40
  }
36
41
  }
37
42
 
38
- if (group.base && !group.base.stack &&
43
+ if (group.base && !group.stack &&
39
44
  (group.base.type === "op" || group.base.type === "operatorname")) {
40
45
  group.base.parentIsSupSub = true
41
46
  appendApplyFunction = !group.base.symbol
@@ -43,7 +48,7 @@ defineFunctionBuilders({
43
48
  needsLeadingSpace = group.base.needsLeadingSpace
44
49
  }
45
50
 
46
- const children = group.base && group.base.stack
51
+ const children = group.stack && group.base.body.length === 1
47
52
  ? [mml.buildGroup(group.base.body[0], style)]
48
53
  : [mml.buildGroup(group.base, style)];
49
54
 
@@ -63,11 +68,16 @@ defineFunctionBuilders({
63
68
  if (group.sup) {
64
69
  const sup = mml.buildGroup(group.sup, childStyle)
65
70
  if (style.level === 3) { sup.setAttribute("scriptlevel", "2") }
66
- const testNode = sup.type === "mrow" ? sup.children[0] : sup
67
- if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime"))
68
- && group.base && group.base.text && "fF".indexOf(group.base.text) > -1) {
69
- // Chromium does not address italic correction on prime. Prevent f′ from overlapping.
70
- testNode.classes.push("prime-pad")
71
+ if (group.base && group.base.text && group.base.text.length === 1) {
72
+ // Make an italic correction on the superscript.
73
+ const text = group.base.text
74
+ if (smallPad.indexOf(text) > -1) {
75
+ sup.classes.push("tml-sml-pad")
76
+ } else if (mediumPad.indexOf(text) > -1) {
77
+ sup.classes.push("tml-med-pad")
78
+ } else if (largePad.indexOf(text) > -1) {
79
+ sup.classes.push("tml-lrg-pad")
80
+ }
71
81
  }
72
82
  children.push(sup)
73
83
  }
@@ -96,7 +106,9 @@ defineFunctionBuilders({
96
106
  }
97
107
  } else if (!group.sup) {
98
108
  const base = group.base;
99
- if (
109
+ if (group.stack) {
110
+ nodeType = "munder";
111
+ } else if (
100
112
  base &&
101
113
  base.type === "op" &&
102
114
  base.limits &&
package/src/functions.js CHANGED
@@ -24,7 +24,6 @@ import "./functions/font";
24
24
  import "./functions/genfrac";
25
25
  import "./functions/hbox";
26
26
  import "./functions/horizBrace";
27
- import "./functions/href";
28
27
  import "./functions/html";
29
28
  import "./functions/includegraphics";
30
29
  import "./functions/kern";
@@ -45,6 +44,7 @@ import "./functions/ref";
45
44
  import "./functions/reflect";
46
45
  import "./functions/relax";
47
46
  import "./functions/rule";
47
+ import "./functions/sfrac";
48
48
  import "./functions/sizing";
49
49
  import "./functions/smash";
50
50
  import "./functions/sqrt";
@@ -5,7 +5,7 @@
5
5
  * https://mit-license.org/
6
6
  */
7
7
 
8
- export const version = "0.11.06";
8
+ export const version = "0.11.08";
9
9
 
10
10
  export function postProcess(block) {
11
11
  const labelMap = {}
package/src/stretchy.js CHANGED
@@ -72,6 +72,9 @@ const stretchyCodePoint = {
72
72
  xtwoheadrightarrow: "\u21a0",
73
73
  xlongequal: "=",
74
74
  xrightleftarrows: "\u21c4",
75
+ xtofrom: "\u21c4",
76
+ xleftrightharpoons: "\u21cb",
77
+ xrightleftharpoons: "\u21cc",
75
78
  yields: "\u2192",
76
79
  yieldsLeft: "\u2190",
77
80
  mesomerism: "\u2194",
@@ -81,7 +84,9 @@ const stretchyCodePoint = {
81
84
  eqleftharpoondown: "\u21bd",
82
85
  "\\cdrightarrow": "\u2192",
83
86
  "\\cdleftarrow": "\u2190",
84
- "\\cdlongequal": "="
87
+ "\\cdlongequal": "=",
88
+ yieldsLeftRight: "\u21c4",
89
+ chemequilibrium: "\u21cc"
85
90
  }
86
91
 
87
92
  const mathMLnode = function(label) {
package/src/symbols.js CHANGED
@@ -894,7 +894,7 @@ defineSymbol(math, inner, "\u22ef", "\\@cdots", true);
894
894
  defineSymbol(math, inner, "\u22f1", "\\ddots", true);
895
895
  defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro
896
896
  defineSymbol(text, textord, "\u22ee", "\\varvdots");
897
- defineSymbol(math, accent, "\u02ca", "\\acute");
897
+ defineSymbol(math, accent, "\u00b4", "\\acute");
898
898
  defineSymbol(math, accent, "\u0060", "\\grave");
899
899
  defineSymbol(math, accent, "\u00a8", "\\ddot");
900
900
  defineSymbol(math, accent, "\u2026", "\\dddot");
@@ -920,7 +920,7 @@ defineSymbol(math, mathord, "\u00d8", "\\O", true);
920
920
  defineSymbol(text, accent, "\u02ca", "\\'"); // acute
921
921
  defineSymbol(text, accent, "\u02cb", "\\`"); // grave
922
922
  defineSymbol(text, accent, "\u02c6", "\\^"); // circumflex
923
- defineSymbol(text, accent, "\u02dc", "\\~"); // tilde
923
+ defineSymbol(text, accent, "\u007e", "\\~"); // tilde
924
924
  defineSymbol(text, accent, "\u02c9", "\\="); // macron
925
925
  defineSymbol(text, accent, "\u02d8", "\\u"); // breve
926
926
  defineSymbol(text, accent, "\u02d9", "\\."); // dot above
@@ -932,7 +932,7 @@ defineSymbol(text, accent, "\u02dd", "\\H"); // double acute
932
932
  defineSymbol(math, accent, "\u02ca", "\\'"); // acute
933
933
  defineSymbol(math, accent, "\u02cb", "\\`"); // grave
934
934
  defineSymbol(math, accent, "\u02c6", "\\^"); // circumflex
935
- defineSymbol(math, accent, "\u02dc", "\\~"); // tilde
935
+ defineSymbol(math, accent, "\u007e", "\\~"); // tilde
936
936
  defineSymbol(math, accent, "\u02c9", "\\="); // macron
937
937
  defineSymbol(math, accent, "\u02d8", "\\u"); // breve
938
938
  defineSymbol(math, accent, "\u02d9", "\\."); // dot above
@@ -1,88 +0,0 @@
1
- import defineFunction, { ordargument } from "../defineFunction";
2
- import { assertNodeType } from "../parseNode";
3
- import { MathNode } from "../mathMLTree";
4
- import { AnchorNode } from "../domTree";
5
- import * as mml from "../buildMathML";
6
- import ParseError from "../ParseError";
7
-
8
- defineFunction({
9
- type: "href",
10
- names: ["\\href"],
11
- props: {
12
- numArgs: 2,
13
- argTypes: ["url", "original"],
14
- allowedInText: true
15
- },
16
- handler: ({ parser, token }, args) => {
17
- const body = args[1];
18
- const href = assertNodeType(args[0], "url").url;
19
-
20
- if (
21
- !parser.settings.isTrusted({
22
- command: "\\href",
23
- url: href
24
- })
25
- ) {
26
- throw new ParseError(`Function "\\href" is not trusted`, token)
27
- }
28
-
29
- return {
30
- type: "href",
31
- mode: parser.mode,
32
- href,
33
- body: ordargument(body)
34
- };
35
- },
36
- mathmlBuilder: (group, style) => {
37
- const math = new MathNode("math", [mml.buildExpressionRow(group.body, style)])
38
- const anchorNode = new AnchorNode(group.href, [], [math])
39
- return anchorNode
40
- }
41
- });
42
-
43
- defineFunction({
44
- type: "href",
45
- names: ["\\url"],
46
- props: {
47
- numArgs: 1,
48
- argTypes: ["url"],
49
- allowedInText: true
50
- },
51
- handler: ({ parser, token }, args) => {
52
- const href = assertNodeType(args[0], "url").url;
53
-
54
- if (
55
- !parser.settings.isTrusted({
56
- command: "\\url",
57
- url: href
58
- })
59
- ) {
60
- throw new ParseError(`Function "\\url" is not trusted`, token)
61
- }
62
-
63
- const chars = [];
64
- for (let i = 0; i < href.length; i++) {
65
- let c = href[i];
66
- if (c === "~") {
67
- c = "\\textasciitilde";
68
- }
69
- chars.push({
70
- type: "textord",
71
- mode: "text",
72
- text: c
73
- });
74
- }
75
- const body = {
76
- type: "text",
77
- mode: parser.mode,
78
- font: "\\texttt",
79
- body: chars
80
- };
81
- return {
82
- type: "href",
83
- mode: parser.mode,
84
- href,
85
- body: ordargument(body)
86
- };
87
- }
88
- });