diff --git a/src/buildHTML.js b/src/buildHTML.js
index 8a4fe9e4a..aee601df7 100644
--- a/src/buildHTML.js
+++ b/src/buildHTML.js
@@ -812,7 +812,37 @@ var groupTypes = {
], "firstBaseline", null, options);
}
- return makeSpan(["sqrt", "mord"], [delim, body]);
+ if (!group.value.index) {
+ return makeSpan(["sqrt", "mord"], [delim, body]);
+ } else {
+ // Handle the optional root index
+
+ // The index is always in scriptscript style
+ var root = buildGroup(
+ group.value.index,
+ options.withStyle(Style.SCRIPTSCRIPT));
+ var rootWrap = makeSpan(
+ [options.style.reset(), Style.SCRIPTSCRIPT.cls()],
+ [root]);
+
+ // Figure out the height and depth of the inner part
+ var innerHeight = Math.max(delim.height, body.height);
+ var innerDepth = Math.max(delim.depth, body.depth);
+
+ // The amount the index is shifted by. This is taken from the TeX
+ // source, in the definition of `\r@@t`.
+ var toShift = 0.6 * (innerHeight - innerDepth);
+
+ // Build a VList with the superscript shifted up correctly
+ var rootVList = buildCommon.makeVList(
+ [{type: "elem", elem: rootWrap}],
+ "shift", -toShift, options);
+ // Add a class surrounding it so we can add on the appropriate
+ // kerning
+ var rootVListWrap = makeSpan(["root"], [rootVList]);
+
+ return makeSpan(["sqrt", "mord"], [rootVListWrap, delim, body]);
+ }
},
sizing: function(group, options, prev) {
diff --git a/src/buildMathML.js b/src/buildMathML.js
index 129b26d60..a681decaa 100644
--- a/src/buildMathML.js
+++ b/src/buildMathML.js
@@ -187,8 +187,17 @@ var groupTypes = {
},
sqrt: function(group) {
- var node = new mathMLTree.MathNode(
- "msqrt", [buildGroup(group.value.body)]);
+ var node;
+ if (group.value.index) {
+ node = new mathMLTree.MathNode(
+ "mroot", [
+ buildGroup(group.value.body),
+ buildGroup(group.value.index)
+ ]);
+ } else {
+ node = new mathMLTree.MathNode(
+ "msqrt", [buildGroup(group.value.body)]);
+ }
return node;
},
diff --git a/src/functions.js b/src/functions.js
index 5bdbe0245..a00dd3f29 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -71,16 +71,11 @@ var functions = {
"\\sqrt": {
numArgs: 1,
numOptionalArgs: 1,
- handler: function(func, optional, body, positions) {
- if (optional != null) {
- throw new ParseError(
- "Optional arguments to \\sqrt aren't supported yet",
- this.lexer, positions[1] - 1);
- }
-
+ handler: function(func, index, body, positions) {
return {
type: "sqrt",
- body: body
+ body: body,
+ index: index
};
}
},
diff --git a/static/katex.less b/static/katex.less
index ff29f422f..44bc34536 100644
--- a/static/katex.less
+++ b/static/katex.less
@@ -1,5 +1,8 @@
@import "fonts.less";
+// The mu unit is defined as 1/18 em
+@mu: 1.0/18.0em;
+
.katex-display {
display: block;
margin: 1em 0;
@@ -359,6 +362,13 @@
margin-top: -1px;
}
}
+
+ > .root {
+ // These values are taken from the definition of `\r@@t`,
+ // `\mkern 5mu` and `\mkern -10mu`.
+ margin-left: 5*@mu;
+ margin-right: -10*@mu;
+ }
}
.sizing, .fontsize-ensurer {
diff --git a/test/katex-spec.js b/test/katex-spec.js
index e89ccdc0b..ed102cb07 100644
--- a/test/katex-spec.js
+++ b/test/katex-spec.js
@@ -1210,8 +1210,8 @@ describe("An optional argument parser", function() {
expect("\\rule[0.2em]{1em}{1em}").toParse();
});
- it("should fail on sqrts for now", function() {
- expect("\\sqrt[3]{2}").toNotParse();
+ it("should work with sqrts with optional arguments", function() {
+ expect("\\sqrt[3]{2}").toParse();
});
it("should work when the optional argument is missing", function() {
diff --git a/test/screenshotter/images/SqrtRoot-firefox.png b/test/screenshotter/images/SqrtRoot-firefox.png
new file mode 100644
index 000000000..09b51fe93
Binary files /dev/null and b/test/screenshotter/images/SqrtRoot-firefox.png differ
diff --git a/test/screenshotter/ss_data.json b/test/screenshotter/ss_data.json
index 62ff0cb68..5f0416f48 100644
--- a/test/screenshotter/ss_data.json
+++ b/test/screenshotter/ss_data.json
@@ -29,6 +29,7 @@
"Sizing": "http://localhost:7936/test/screenshotter/test.html?m={\\Huge x}{\\LARGE y}{\\normalsize z}{\\scriptsize w}",
"Spacing": "http://localhost:7936/test/screenshotter/test.html?m=^3+[-1][1-1]1=1(=1)\\lvert a\\rvert~b",
"Sqrt": "http://localhost:7936/test/screenshotter/test.html?m=\\sqrt{\\sqrt{\\sqrt{x}}}_{\\sqrt{\\sqrt{x}}}^{\\sqrt{\\sqrt{\\sqrt{x}}}^{\\sqrt{\\sqrt{\\sqrt{x}}}}}",
+ "SqrtRoot": "http://localhost:7936/test/screenshotter/test.html?m=1+\\sqrt[3]{2}+\\sqrt[1923^234]{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}}",
"SupSubCharacterBox": "http://localhost:7936/test/screenshotter/test.html?m=a_2f_2{f}_2{aa}_2{af}_2",
"SupSubHorizSpacing": "http://localhost:7936/test/screenshotter/test.html?m=x^{x^{x}}\\Big|x_{x_{x_{x_{x}}}}\\bigg|x^{x^{x_{x_{x_{x_{x}}}}}}\\bigg|",
"SupSubOffsets": "http://localhost:7936/test/screenshotter/test.html?m=\\displaystyle \\int_{2+3}x f^{2+3}+3\\lim_{2+3+4+5}f",