From 0be77d4e6ff7b3752c609e2cb161f82fd230d67b Mon Sep 17 00:00:00 2001 From: Emily Eisenberg Date: Wed, 10 Sep 2014 17:10:38 -0700 Subject: [PATCH] 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 --- Parser.js | 26 +++++++++++++--- buildTree.js | 18 +++++++++++ functions.js | 14 ++++++++- test/huxley/DisplayStyle.hux/firefox-1.png | Bin 0 -> 22330 bytes test/huxley/DisplayStyle.hux/record.json | 5 ++++ test/huxley/Huxleyfile.json | 6 ++++ test/katex-tests.js | 33 +++++++++++++++++++++ 7 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 test/huxley/DisplayStyle.hux/firefox-1.png create mode 100644 test/huxley/DisplayStyle.hux/record.json diff --git a/Parser.js b/Parser.js index 4fec946ee..0f18fe4bc 100644 --- a/Parser.js +++ b/Parser.js @@ -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); diff --git a/buildTree.js b/buildTree.js index d90f4c8e5..3a5f5d2db 100644 --- a/buildTree.js +++ b/buildTree.js @@ -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; diff --git a/functions.js b/functions.js index 20da6f9eb..0d6e8cac9 100644 --- a/functions.js +++ b/functions.js @@ -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 + } } ]; diff --git a/test/huxley/DisplayStyle.hux/firefox-1.png b/test/huxley/DisplayStyle.hux/firefox-1.png new file mode 100644 index 0000000000000000000000000000000000000000..2c1965e8c91cd211d971659ee4bf04713cc587da GIT binary patch literal 22330 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 quX6BLIru9G{wfFmzh#0suECG3^+RE