From 982e7be5978e4d609e7bc8b5499de29f6f5c8d75 Mon Sep 17 00:00:00 2001 From: Eddie Kohler Date: Sun, 27 Nov 2016 11:20:26 -0500 Subject: [PATCH] Calculate math classes from outputs, not inputs. It's important to get spacing right that the domTree classes reflect math atom types. So use those types exclusively, rather than repeating the type mapping twice (once when building spans, once in getTypeOfGroup). * Remove getTypeOfGroup. * Add getTypeOfDomTree (simpler). * Adjust supsub type calculation. * Adjust delimsizing internals. --- src/buildHTML.js | 77 ++++++++++------------------------------------ src/buildMathML.js | 6 ++-- src/functions.js | 34 ++++++++++---------- test/katex-spec.js | 4 +-- 4 files changed, 38 insertions(+), 83 deletions(-) diff --git a/src/buildHTML.js b/src/buildHTML.js index 15859ea..d30bbde 100644 --- a/src/buildHTML.js +++ b/src/buildHTML.js @@ -105,66 +105,20 @@ var buildExpression = function(expression, options, isRealGroup) { return groups; }; -// List of types used by getTypeOfGroup, -// see https://github.com/Khan/KaTeX/wiki/Examining-TeX#group-types -var groupToType = { - mathord: "mord", - textord: "mord", - bin: "mbin", - rel: "mrel", - text: "mord", - open: "mopen", - close: "mclose", - inner: "minner", - genfrac: "mord", - array: "mord", - spacing: "mord", - punct: "mpunct", - ordgroup: "mord", - op: "mop", - katex: "mord", - overline: "mord", - underline: "mord", - rule: "mord", - leftright: "minner", - sqrt: "mord", - accent: "mord", - llap: "mord", - rlap: "mord", -}; - -/** - * Gets the final math type of an expression, given its group type. This type is - * used to determine spacing between elements, and affects bin elements by - * causing them to change depending on what types are around them. This type - * must be attached to the outermost node of an element as a CSS class so that - * spacing with its surrounding elements works correctly. - * - * Some elements can be mapped one-to-one from group type to math type, and - * those are listed in the `groupToType` table. - * - * Others (usually elements that wrap around other elements) often have - * recursive definitions, and thus call `getTypeOfGroup` on their inner - * elements. - */ -var getTypeOfGroup = function(group) { - if (group == null) { - // Like when typesetting $^3$ - return groupToType.mathord; - } else if (group.type === "supsub") { - return getTypeOfGroup(group.value.base); - } else if (group.type === "color" || group.type === "sizing" - || group.type === "styling") { - // Return type of rightmost element of group. - var atoms = group.value.value; - return getTypeOfGroup(atoms[atoms.length - 1]); - } else if (group.type === "font") { - return getTypeOfGroup(group.value.body); - } else if (group.type === "delimsizing") { - return groupToType[group.value.delimType]; +// Return math atom class (mclass) of a domTree. +var getTypeOfDomTree = function(node) { + if (node instanceof domTree.documentFragment) { + if (node.children.length) { + return getTypeOfDomTree( + node.children[node.children.length - 1]); + } } else { - return groupToType[group.type]; + if (utils.contains(["mord", "mop", "mbin", "mrel", "mopen", "mclose", + "mpunct", "minner"], node.classes[0])) { + return node.classes[0]; + } } + return null; }; /** @@ -437,7 +391,8 @@ groupTypes.supsub = function(group, options) { } // We ensure to wrap the supsub vlist in a span.msupsub to reset text-align - return makeSpan([getTypeOfGroup(group.value.base)], + var mclass = getTypeOfDomTree(base) || "mord"; + return makeSpan([mclass], [base, makeSpan(["msupsub"], [supsub])], options); }; @@ -1200,13 +1155,13 @@ groupTypes.delimsizing = function(group, options) { if (delim === ".") { // Empty delimiters still count as elements, even though they don't // show anything. - return makeSpan([groupToType[group.value.delimType]]); + return makeSpan([group.value.mclass]); } // Use delimiter.sizedDelim to generate the delimiter. return delimiter.sizedDelim( delim, group.value.size, options, group.mode, - [groupToType[group.value.delimType]]); + [group.value.mclass]); }; groupTypes.leftright = function(group, options) { diff --git a/src/buildMathML.js b/src/buildMathML.js index 4a75d92..5b10fac 100644 --- a/src/buildMathML.js +++ b/src/buildMathML.js @@ -358,10 +358,10 @@ groupTypes.delimsizing = function(group) { var node = new mathMLTree.MathNode("mo", children); - if (group.value.delimType === "open" || - group.value.delimType === "close") { + if (group.value.mclass === "mopen" || + group.value.mclass === "mclose") { // Only some of the delimsizing functions act as fences, and they - // return "open" or "close" delimTypes. + // return "mopen" or "mclose" mclass. node.setAttribute("fence", "true"); } else { // Explicitly disable fencing if it's not a fence, to override the diff --git a/src/functions.js b/src/functions.js index 7888242..dc8a392 100644 --- a/src/functions.js +++ b/src/functions.js @@ -238,22 +238,22 @@ defineFunction("\\phantom", { // Extra data needed for the delimiter handler down below var delimiterSizes = { - "\\bigl" : {type: "open", size: 1}, - "\\Bigl" : {type: "open", size: 2}, - "\\biggl": {type: "open", size: 3}, - "\\Biggl": {type: "open", size: 4}, - "\\bigr" : {type: "close", size: 1}, - "\\Bigr" : {type: "close", size: 2}, - "\\biggr": {type: "close", size: 3}, - "\\Biggr": {type: "close", size: 4}, - "\\bigm" : {type: "rel", size: 1}, - "\\Bigm" : {type: "rel", size: 2}, - "\\biggm": {type: "rel", size: 3}, - "\\Biggm": {type: "rel", size: 4}, - "\\big" : {type: "textord", size: 1}, - "\\Big" : {type: "textord", size: 2}, - "\\bigg" : {type: "textord", size: 3}, - "\\Bigg" : {type: "textord", size: 4}, + "\\bigl" : {mclass: "mopen", size: 1}, + "\\Bigl" : {mclass: "mopen", size: 2}, + "\\biggl": {mclass: "mopen", size: 3}, + "\\Biggl": {mclass: "mopen", size: 4}, + "\\bigr" : {mclass: "mclose", size: 1}, + "\\Bigr" : {mclass: "mclose", size: 2}, + "\\biggr": {mclass: "mclose", size: 3}, + "\\Biggr": {mclass: "mclose", size: 4}, + "\\bigm" : {mclass: "mrel", size: 1}, + "\\Bigm" : {mclass: "mrel", size: 2}, + "\\biggm": {mclass: "mrel", size: 3}, + "\\Biggm": {mclass: "mrel", size: 4}, + "\\big" : {mclass: "mord", size: 1}, + "\\Big" : {mclass: "mord", size: 2}, + "\\bigg" : {mclass: "mord", size: 3}, + "\\Bigg" : {mclass: "mord", size: 4}, }; var delimiters = [ @@ -472,7 +472,7 @@ defineFunction([ return { type: "delimsizing", size: delimiterSizes[context.funcName].size, - delimType: delimiterSizes[context.funcName].type, + mclass: delimiterSizes[context.funcName].mclass, value: delim.value, }; } diff --git a/test/katex-spec.js b/test/katex-spec.js index 122c8db..b2fa955 100644 --- a/test/katex-spec.js +++ b/test/katex-spec.js @@ -883,8 +883,8 @@ describe("A delimiter sizing parser", function() { var leftParse = getParsed(normalDelim)[0]; var rightParse = getParsed(bigDelim)[0]; - expect(leftParse.value.delimType).toEqual("open"); - expect(rightParse.value.delimType).toEqual("close"); + expect(leftParse.value.mclass).toEqual("mopen"); + expect(rightParse.value.mclass).toEqual("mclose"); }); it("should parse the correct size delimiter", function() {