UNPKG

3.25 kBJavaScriptView Raw
1// @flow
2import buildCommon from "../buildCommon";
3import defineFunction from "../defineFunction";
4import mathMLTree from "../mathMLTree";
5
6import * as html from "../buildHTML";
7import * as mml from "../buildMathML";
8
9import type Options from "../Options";
10import type {AnyParseNode} from "../parseNode";
11import type {HtmlBuilder} from "../defineFunction";
12import type {documentFragment as HtmlDocumentFragment} from "../domTree";
13
14export function sizingGroup(
15 value: AnyParseNode[],
16 options: Options,
17 baseOptions: Options,
18): HtmlDocumentFragment {
19 const inner = html.buildExpression(value, options, false);
20 const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier;
21
22 // Add size-resetting classes to the inner list and set maxFontSize
23 // manually. Handle nested size changes.
24 for (let i = 0; i < inner.length; i++) {
25 const pos = inner[i].classes.indexOf("sizing");
26 if (pos < 0) {
27 Array.prototype.push.apply(inner[i].classes,
28 options.sizingClasses(baseOptions));
29 } else if (inner[i].classes[pos + 1] === "reset-size" + options.size) {
30 // This is a nested size change: e.g., inner[i] is the "b" in
31 // `\Huge a \small b`. Override the old size (the `reset-` class)
32 // but not the new size.
33 inner[i].classes[pos + 1] = "reset-size" + baseOptions.size;
34 }
35
36 inner[i].height *= multiplier;
37 inner[i].depth *= multiplier;
38 }
39
40 return buildCommon.makeFragment(inner);
41}
42
43const sizeFuncs = [
44 "\\tiny", "\\sixptsize", "\\scriptsize", "\\footnotesize", "\\small",
45 "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",
46];
47
48export const htmlBuilder: HtmlBuilder<"sizing"> = (group, options) => {
49 // Handle sizing operators like \Huge. Real TeX doesn't actually allow
50 // these functions inside of math expressions, so we do some special
51 // handling.
52 const newOptions = options.havingSize(group.size);
53 return sizingGroup(group.body, newOptions, options);
54};
55
56defineFunction({
57 type: "sizing",
58 names: sizeFuncs,
59 props: {
60 numArgs: 0,
61 allowedInText: true,
62 },
63 handler: ({breakOnTokenText, funcName, parser}, args) => {
64 const body = parser.parseExpression(false, breakOnTokenText);
65
66 return {
67 type: "sizing",
68 mode: parser.mode,
69 // Figure out what size to use based on the list of functions above
70 size: sizeFuncs.indexOf(funcName) + 1,
71 body,
72 };
73 },
74 htmlBuilder,
75 mathmlBuilder: (group, options) => {
76 const newOptions = options.havingSize(group.size);
77 const inner = mml.buildExpression(group.body, newOptions);
78
79 const node = new mathMLTree.MathNode("mstyle", inner);
80
81 // TODO(emily): This doesn't produce the correct size for nested size
82 // changes, because we don't keep state of what style we're currently
83 // in, so we can't reset the size to normal before changing it. Now
84 // that we're passing an options parameter we should be able to fix
85 // this.
86 node.setAttribute("mathsize", newOptions.sizeMultiplier + "em");
87
88 return node;
89 },
90});