Add style changing functions

Summary:
Add \displaystyle, \textstyle, \scriptstyle, and \scriptscriptstyle commands.
Added tests and huxley screenshots for everything that looks different in
displaystyle vs normal style.

Fixes #24.

Test Plan:
 - See new tests work, and old tests still work
 - See no huxley screenshots changed, and new screenshot looks good

Reviewers: alpert

Reviewed By: alpert

Differential Revision: http://phabricator.khanacademy.org/D13079
This commit is contained in:
Emily Eisenberg 2014-09-10 17:10:38 -07:00
parent a76f6eb985
commit 0be77d4e6f
7 changed files with 97 additions and 5 deletions

View File

@ -242,6 +242,11 @@ var sizeFuncs = [
"\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge"
];
// A list of the style-changing functions, for use in parseImplicitGroup
var styleFuncs = [
"\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle"
];
// Parses an implicit group, which is a group that starts at the end of a
// specified, and ends right before a higher explicit group ends, or at EOL. It
// is used for functions that appear to affect the current style, like \Large or
@ -259,7 +264,9 @@ Parser.prototype.parseImplicitGroup = function(pos, mode) {
return this.parseFunction(pos, mode);
}
if (start.result.result === "\\left") {
var func = start.result.result;
if (func === "\\left") {
// If we see a left:
// Parse the entire left function (including the delimiter)
var left = this.parseFunction(pos, mode);
@ -282,17 +289,28 @@ Parser.prototype.parseImplicitGroup = function(pos, mode) {
} else {
throw new ParseError("Missing \\right", this.lexer, body.position);
}
} else if (start.result.result === "\\right") {
} else if (func === "\\right") {
// If we see a right, explicitly fail the parsing here so the \left
// handling ends the group
return null;
} else if (utils.contains(sizeFuncs, start.result.result)) {
} else if (utils.contains(sizeFuncs, func)) {
// If we see a sizing function, parse out the implict body
var body = this.handleExpressionBody(start.result.position, mode);
return new ParseResult(
new ParseNode("sizing", {
// Figure out what size to use based on the list of functions above
size: "size" + (utils.indexOf(sizeFuncs, start.result.result) + 1),
size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
value: body.body
}, mode),
body.position);
} else if (utils.contains(styleFuncs, func)) {
// If we see a styling function, parse out the implict body
var body = this.handleExpressionBody(start.result.position, mode);
return new ParseResult(
new ParseNode("styling", {
// Figure out what style to use by pulling out the style from
// the function name
style: func.slice(1, func.length - 5),
value: body.body
}, mode),
body.position);

View File

@ -54,6 +54,8 @@ var getTypeOfGroup = function(group) {
return getTypeOfGroup(group.value.value);
} else if (group.type === "sizing") {
return getTypeOfGroup(group.value.value);
} else if (group.type === "styling") {
return getTypeOfGroup(group.value.value);
} else if (group.type === "delimsizing") {
return groupToType[group.value.delimType];
} else {
@ -547,6 +549,22 @@ var groupTypes = {
return span;
},
styling: function(group, options, prev) {
var style = {
"display": Style.DISPLAY,
"text": Style.TEXT,
"script": Style.SCRIPT,
"scriptscript": Style.SCRIPTSCRIPT
};
var newStyle = style[group.value.style];
var inner = buildExpression(
group.value.value, options.withStyle(newStyle), prev);
return makeSpan([options.style.reset(), newStyle.cls()], inner);
},
delimsizing: function(group, options, prev) {
var delim = group.value.value;

View File

@ -310,7 +310,7 @@ var duplicatedFunctions = [
}
},
// Sizing functions
// Sizing functions (handled in Parser.js explicitly, hence no handler)
{
funcs: [
"\\tiny", "\\scriptsize", "\\footnotesize", "\\small",
@ -319,6 +319,18 @@ var duplicatedFunctions = [
data: {
numArgs: 0
}
},
// Style changing functions (handled in Parser.js explicitly, hence no
// handler)
{
funcs: [
"\\displaystyle", "\\textstyle", "\\scriptstyle",
"\\scriptscriptstyle"
],
data: {
numArgs: 0
}
}
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,5 @@
[
{
"action": "screenshot"
}
]

View File

@ -159,5 +159,11 @@
"name": "Sqrt",
"screenSize": [1024, 768],
"url": "http://localhost:7936/test/huxley/test.html?m=\\sqrt{\\sqrt{\\sqrt{x}}}_{\\sqrt{\\sqrt{x}}}^{\\sqrt{\\sqrt{\\sqrt{x}}}^{\\sqrt{\\sqrt{\\sqrt{x}}}}}"
},
{
"name": "DisplayStyle",
"screenSize": [1024, 768],
"url": "http://localhost:7936/test/huxley/test.html?m={\\displaystyle\\sqrt{x}}{\\sqrt{x}}{\\displaystyle \\frac12}{\\frac12}{\\displaystyle x^1_2}{x^1_2}"
}
]

View File

@ -916,3 +916,36 @@ describe("A TeX-compliant parser", function() {
}
});
});
describe("A style change parser", function() {
it("should not fail", function() {
expect("\\displaystyle x").toParse();
expect("\\textstyle x").toParse();
expect("\\scriptstyle x").toParse();
expect("\\scriptscriptstyle x").toParse();
});
it("should produce the correct style", function() {
var displayParse = parseTree("\\displaystyle x")[0];
expect(displayParse.value.style).toMatch("display");
var scriptscriptParse = parseTree("\\scriptscriptstyle x")[0];
expect(scriptscriptParse.value.style).toMatch("scriptscript");
});
it("should only change the style within its group", function() {
var text = "a b { c d \\displaystyle e f } g h";
expect(text).toParse();
var parse = parseTree(text);
var displayNode = parse[2].value[2];
expect(displayNode.type).toMatch("styling");
var displayBody = displayNode.value.value;
expect(displayBody.length).toEqual(2);
expect(displayBody[0].value).toMatch("e");
});
});