diff --git a/src/buildHTML.js b/src/buildHTML.js index b54d6a85..401012ff 100644 --- a/src/buildHTML.js +++ b/src/buildHTML.js @@ -571,12 +571,6 @@ export const groupTypes = { return makeSpan(["mrel", "x-arrow"], [vlist], options); }, - mclass(group, options) { - const elements = buildExpression(group.value.value, options, true); - - return makeSpan([group.value.mclass], elements, options); - }, - raisebox(group, options) { const body = groupTypes.sizing({value: { value: [{ diff --git a/src/buildMathML.js b/src/buildMathML.js index a828e4f7..aecbbea0 100644 --- a/src/buildMathML.js +++ b/src/buildMathML.js @@ -275,11 +275,6 @@ groupTypes.xArrow = function(group, options) { return node; }; -groupTypes.mclass = function(group, options) { - const inner = buildExpression(group.value.value, options); - return new mathMLTree.MathNode("mstyle", inner); -}; - groupTypes.raisebox = function(group, options) { const node = new mathMLTree.MathNode( "mpadded", [buildGroup(group.value.body, options)]); diff --git a/src/functions.js b/src/functions.js index f9c7c808..4360025a 100644 --- a/src/functions.js +++ b/src/functions.js @@ -1,7 +1,6 @@ // @flow /** Include this to ensure that all functions are defined. */ import ParseError from "./ParseError"; -import ParseNode from "./ParseNode"; import { default as _defineFunction, ordargument, @@ -51,70 +50,7 @@ import "./functions/kern"; import "./functions/phantom"; -// Math class commands except \mathop -defineFunction("mclass", [ - "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen", - "\\mathclose", "\\mathpunct", "\\mathinner", -], { - numArgs: 1, -}, function(context, args) { - const body = args[0]; - return { - type: "mclass", - mclass: "m" + context.funcName.substr(5), - value: ordargument(body), - }; -}); - -// Build a relation or stacked op by placing one symbol on top of another -defineFunction("mclass", ["\\stackrel", "\\overset", "\\underset"], { - numArgs: 2, -}, function(context, args) { - const baseArg = args[1]; - const shiftedArg = args[0]; - - let mclass = "mrel"; // default. May change below. - if (context.funcName !== "\\stackrel") { - // LaTeX applies \binrel spacing to \overset and \underset. - // \binrel spacing varies with (bin|rel|ord) of the atom in the argument. - // We'll do the same. - let atomType = ""; - if (baseArg.type === "ordgroup") { - atomType = baseArg.value[0].type; - } else { - atomType = baseArg.type; - } - if (/^(bin|rel)$/.test(atomType)) { - mclass = "m" + atomType; - } else { - // This may capture some instances in which the baseArg is more than - // just a single symbol. Say a \overset inside an \overset. - // TODO: A more comprehensive way to determine the baseArg type. - mclass = "mord"; - } - } - - const baseOp = new ParseNode("op", { - type: "op", - limits: true, - alwaysHandleSupSub: true, - symbol: false, - suppressBaseShift: context.funcName !== "\\stackrel", - value: ordargument(baseArg), - }, baseArg.mode); - - const supsub = new ParseNode("supsub", { - base: baseOp, - sup: context.funcName === "\\underset" ? null : shiftedArg, - sub: context.funcName === "\\underset" ? shiftedArg : null, - }, shiftedArg.mode); - - return { - type: "mclass", - mclass: mclass, - value: [supsub], - }; -}); +import "./functions/mclass"; import "./functions/mod"; diff --git a/src/functions/mclass.js b/src/functions/mclass.js new file mode 100644 index 00000000..3b5eb23d --- /dev/null +++ b/src/functions/mclass.js @@ -0,0 +1,100 @@ +// @flow +import defineFunction, {ordargument} from "../defineFunction"; +import buildCommon from "../buildCommon"; +import mathMLTree from "../mathMLTree"; +import ParseNode from "../ParseNode"; + +import * as html from "../buildHTML"; +import * as mml from "../buildMathML"; + +const makeSpan = buildCommon.makeSpan; + +function htmlBuilder(group, options) { + const elements = html.buildExpression(group.value.value, options, true); + return makeSpan([group.value.mclass], elements, options); +} + +function mathmlBuilder(group, options) { + const inner = mml.buildExpression(group.value.value, options); + return new mathMLTree.MathNode("mstyle", inner); +} + +// Math class commands except \mathop +defineFunction({ + type: "mclass", + names: [ + "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen", + "\\mathclose", "\\mathpunct", "\\mathinner", + ], + props: { + numArgs: 1, + }, + handler(context, args) { + const body = args[0]; + return { + type: "mclass", + mclass: "m" + context.funcName.substr(5), + value: ordargument(body), + }; + }, + htmlBuilder, + mathmlBuilder, +}); + +// Build a relation or stacked op by placing one symbol on top of another +defineFunction({ + type: "mclass", + names: ["\\stackrel", "\\overset", "\\underset"], + props: { + numArgs: 2, + }, + handler(context, args) { + const baseArg = args[1]; + const shiftedArg = args[0]; + + let mclass = "mrel"; // default. May change below. + if (context.funcName !== "\\stackrel") { + // LaTeX applies \binrel spacing to \overset and \underset. \binrel + // spacing varies with (bin|rel|ord) of the atom in the argument. + // We'll do the same. + let atomType = ""; + if (baseArg.type === "ordgroup") { + atomType = baseArg.value[0].type; + } else { + atomType = baseArg.type; + } + if (/^(bin|rel)$/.test(atomType)) { + mclass = "m" + atomType; + } else { + // This may capture some instances in which the baseArg is more + // than just a single symbol. Say a \overset inside an \overset. + // TODO: A more comprehensive way to determine the baseArg type. + mclass = "mord"; + } + } + + const baseOp = new ParseNode("op", { + type: "op", + limits: true, + alwaysHandleSupSub: true, + symbol: false, + suppressBaseShift: context.funcName !== "\\stackrel", + value: ordargument(baseArg), + }, baseArg.mode); + + const supsub = new ParseNode("supsub", { + base: baseOp, + sup: context.funcName === "\\underset" ? null : shiftedArg, + sub: context.funcName === "\\underset" ? shiftedArg : null, + }, shiftedArg.mode); + + return { + type: "mclass", + mclass: mclass, + value: [supsub], + }; + }, + htmlBuilder, + mathmlBuilder, +}); +