UNPKG

4.21 kBJavaScriptView Raw
1// @flow
2import defineFunction, {ordargument} from "../defineFunction";
3import buildCommon from "../buildCommon";
4import mathMLTree from "../mathMLTree";
5import {SymbolNode} from "../domTree";
6
7import * as html from "../buildHTML";
8import * as mml from "../buildMathML";
9
10// \operatorname
11// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
12defineFunction({
13 type: "operatorname",
14 names: ["\\operatorname"],
15 props: {
16 numArgs: 1,
17 },
18 handler: ({parser}, args) => {
19 const body = args[0];
20 return {
21 type: "operatorname",
22 mode: parser.mode,
23 body: ordargument(body),
24 };
25 },
26
27 htmlBuilder: (group, options) => {
28 if (group.body.length > 0) {
29 const body = group.body.map(child => {
30 // $FlowFixMe: Check if the node has a string `text` property.
31 const childText = child.text;
32 if (typeof childText === "string") {
33 return {
34 type: "textord",
35 mode: child.mode,
36 text: childText,
37 };
38 } else {
39 return child;
40 }
41 });
42
43 // Consolidate function names into symbol characters.
44 const expression = html.buildExpression(
45 body, options.withFont("mathrm"), true);
46
47 for (let i = 0; i < expression.length; i++) {
48 const child = expression[i];
49 if (child instanceof SymbolNode) {
50 // Per amsopn package,
51 // change minus to hyphen and \ast to asterisk
52 child.text = child.text.replace(/\u2212/, "-")
53 .replace(/\u2217/, "*");
54 }
55 }
56 return buildCommon.makeSpan(["mop"], expression, options);
57 } else {
58 return buildCommon.makeSpan(["mop"], [], options);
59 }
60 },
61
62 mathmlBuilder: (group, options) => {
63 // The steps taken here are similar to the html version.
64 let expression = mml.buildExpression(
65 group.body, options.withFont("mathrm"));
66
67 // Is expression a string or has it something like a fraction?
68 let isAllString = true; // default
69 for (let i = 0; i < expression.length; i++) {
70 const node = expression[i];
71 if (node instanceof mathMLTree.SpaceNode) {
72 // Do nothing
73 } else if (node instanceof mathMLTree.MathNode) {
74 switch (node.type) {
75 case "mi":
76 case "mn":
77 case "ms":
78 case "mspace":
79 case "mtext":
80 break; // Do nothing yet.
81 case "mo": {
82 const child = node.children[0];
83 if (node.children.length === 1 &&
84 child instanceof mathMLTree.TextNode) {
85 child.text =
86 child.text.replace(/\u2212/, "-")
87 .replace(/\u2217/, "*");
88 } else {
89 isAllString = false;
90 }
91 break;
92 }
93 default:
94 isAllString = false;
95 }
96 } else {
97 isAllString = false;
98 }
99 }
100
101 if (isAllString) {
102 // Write a single TextNode instead of multiple nested tags.
103 const word = expression.map(node => node.toText()).join("");
104 expression = [new mathMLTree.TextNode(word)];
105 }
106
107 const identifier = new mathMLTree.MathNode("mi", expression);
108 identifier.setAttribute("mathvariant", "normal");
109
110 // \u2061 is the same as &ApplyFunction;
111 // ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp
112 const operator = new mathMLTree.MathNode("mo",
113 [mml.makeText("\u2061", "text")]);
114
115 return mathMLTree.newDocumentFragment([identifier, operator]);
116 },
117});