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}