diff --git a/src/buildHTML.js b/src/buildHTML.js index d30bbde..253b0eb 100644 --- a/src/buildHTML.js +++ b/src/buildHTML.js @@ -786,6 +786,11 @@ groupTypes.op = function(group, options) { // The slant of the symbol is just its italic correction. slant = base.italic; + } else if (group.value.value) { + // If this is a list, compose that list. + var inner = buildExpression(group.value.value, options, true); + + base = makeSpan(["mop"], inner, options); } else { // Otherwise, this is a text operator. Build the text from the // operator's name. @@ -1399,6 +1404,12 @@ groupTypes.phantom = function(group, options) { return new buildCommon.makeFragment(elements); }; +groupTypes.mclass = function(group, options) { + var elements = buildExpression(group.value.value, options, true); + + return makeSpan([group.value.mclass], elements, options); +}; + /** * buildGroup is the function that takes a group and calls the correct groupType * function for it. It also handles the interaction of size and style changes diff --git a/src/buildMathML.js b/src/buildMathML.js index 5b10fac..11a088f 100644 --- a/src/buildMathML.js +++ b/src/buildMathML.js @@ -316,7 +316,7 @@ groupTypes.spacing = function(group) { return node; }; -groupTypes.op = function(group) { +groupTypes.op = function(group, options) { var node; // TODO(emily): handle big operators using the `largeop` attribute @@ -325,6 +325,10 @@ groupTypes.op = function(group) { // This is a symbol. Just add the symbol. node = new mathMLTree.MathNode( "mo", [makeText(group.value.body, group.mode)]); + } else if (group.value.value) { + // This is an operator with children. Add them. + node = new mathMLTree.MathNode( + "mo", buildExpression(group.value.value, options)); } else { // This is a text operator. Add all of the characters from the // operator's name. @@ -475,6 +479,11 @@ groupTypes.phantom = function(group, options) { return new mathMLTree.MathNode("mphantom", inner); }; +groupTypes.mclass = function(group, options) { + var inner = buildExpression(group.value.value, options); + return new mathMLTree.MathNode("mstyle", inner); +}; + /** * Takes a list of nodes, builds them, and returns a list of the generated * MathML nodes. A little simpler than the HTML version because we don't do any diff --git a/src/functions.js b/src/functions.js index dc8a392..deaf4f7 100644 --- a/src/functions.js +++ b/src/functions.js @@ -100,6 +100,16 @@ function defineFunction(names, props, handler) { } } +// Since the corresponding buildHTML/buildMathML function expects a +// list of elements, we normalize for different kinds of arguments +var ordargument = function(arg) { + if (arg.type === "ordgroup") { + return arg.value; + } else { + return [arg]; + } +}; + // A normal square root defineFunction("\\sqrt", { numArgs: 1, @@ -121,19 +131,9 @@ defineFunction("\\text", { greediness: 2, }, function(context, args) { var body = args[0]; - // Since the corresponding buildHTML/buildMathML function expects a - // list of elements, we normalize for different kinds of arguments - // TODO(emily): maybe this should be done somewhere else - var inner; - if (body.type === "ordgroup") { - inner = body.value; - } else { - inner = [body]; - } - return { type: "text", - body: inner, + body: ordargument(body), }; }); @@ -146,18 +146,10 @@ defineFunction("\\color", { }, function(context, args) { var color = args[0]; var body = args[1]; - // Normalize the different kinds of bodies (see \text above) - var inner; - if (body.type === "ordgroup") { - inner = body.value; - } else { - inner = [body]; - } - return { type: "color", color: color.value, - value: inner, + value: ordargument(body), }; }); @@ -223,16 +215,24 @@ defineFunction("\\phantom", { numArgs: 1, }, function(context, args) { var body = args[0]; - var inner; - if (body.type === "ordgroup") { - inner = body.value; - } else { - inner = [body]; - } - return { type: "phantom", - value: inner, + value: ordargument(body), + }; +}); + +// Math class commands except \mathop +defineFunction([ + "\\mathord", "\\mathbin", "\\mathrel", "\\mathopen", + "\\mathclose", "\\mathpunct", "\\mathinner", +], { + numArgs: 1, +}, function(context, args) { + var body = args[0]; + return { + type: "mclass", + mclass: "m" + context.funcName.substr(5), + value: ordargument(body), }; }); @@ -298,17 +298,10 @@ defineFunction([ greediness: 3, }, function(context, args) { var body = args[0]; - var atoms; - if (body.type === "ordgroup") { - atoms = body.value; - } else { - atoms = [body]; - } - return { type: "color", color: "katex-" + context.funcName.slice(1), - value: atoms, + value: ordargument(body), }; }); @@ -378,6 +371,19 @@ defineFunction([ }; }); +// \mathop class command +defineFunction("\\mathop", { + numArgs: 1, +}, function(context, args) { + var body = args[0]; + return { + type: "op", + limits: false, + symbol: false, + value: ordargument(body), + }; +}); + // Fractions defineFunction([ "\\dfrac", "\\frac", "\\tfrac", diff --git a/test/screenshotter/images/MathAtom-chrome.png b/test/screenshotter/images/MathAtom-chrome.png new file mode 100644 index 0000000..175c72a Binary files /dev/null and b/test/screenshotter/images/MathAtom-chrome.png differ diff --git a/test/screenshotter/images/MathAtom-firefox.png b/test/screenshotter/images/MathAtom-firefox.png new file mode 100644 index 0000000..d451d16 Binary files /dev/null and b/test/screenshotter/images/MathAtom-firefox.png differ diff --git a/test/screenshotter/images/MathAtom2-chrome.png b/test/screenshotter/images/MathAtom2-chrome.png new file mode 100644 index 0000000..cdfc0c7 Binary files /dev/null and b/test/screenshotter/images/MathAtom2-chrome.png differ diff --git a/test/screenshotter/images/MathAtom2-firefox.png b/test/screenshotter/images/MathAtom2-firefox.png new file mode 100644 index 0000000..cc0b696 Binary files /dev/null and b/test/screenshotter/images/MathAtom2-firefox.png differ diff --git a/test/screenshotter/ss_data.yaml b/test/screenshotter/ss_data.yaml index 6c5cd88..6c596c9 100644 --- a/test/screenshotter/ss_data.yaml +++ b/test/screenshotter/ss_data.yaml @@ -79,6 +79,8 @@ LeftRightStyleSizing: | LimitControls: | \displaystyle\int\limits_2^3 3x^2\,dx + \sum\nolimits^n_{i=1}i + \textstyle\int\limits_x^y z +MathAtom: a\mathrel{\mathop{=}\limits^{\blue ?}}b +MathAtom2: \mathop{\overline\mathrm{lim}}\limits_{x\to\infty}f(x) MathDefaultFonts: Ax2k\breve{a}\omega\Omega\imath+\KaTeX MathBb: \mathbb{Ax2k\breve{a}\omega\Omega\imath+\KaTeX} MathBf: \mathbf{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}