mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-13 06:58:40 +00:00
group all \phantom related code together
This commit is contained in:
committed by
Kevin Barabash
parent
092aa0c767
commit
8bdc5e3e6a
@@ -71,7 +71,7 @@ const spliceSpaces = function(children, i) {
|
||||
* is a real group (no atoms will be added on either side), as opposed to
|
||||
* a partial group (e.g. one created by \color).
|
||||
*/
|
||||
const buildExpression = function(expression, options, isRealGroup) {
|
||||
export const buildExpression = function(expression, options, isRealGroup) {
|
||||
// Parse expressions into `groups`.
|
||||
const groups = [];
|
||||
for (let i = 0; i < expression.length; i++) {
|
||||
@@ -255,7 +255,7 @@ const makeNullDelimiter = function(options, classes) {
|
||||
* This is a map of group types to the function used to handle that type.
|
||||
* Simpler types come at the beginning, while complicated types come afterwards.
|
||||
*/
|
||||
const groupTypes = {};
|
||||
export const groupTypes = {};
|
||||
|
||||
groupTypes.mathord = function(group, options) {
|
||||
return buildCommon.makeOrd(group, options, "mathord");
|
||||
@@ -1723,46 +1723,6 @@ groupTypes.xArrow = function(group, options) {
|
||||
return makeSpan(["mrel", "x-arrow"], [vlist], options);
|
||||
};
|
||||
|
||||
groupTypes.phantom = function(group, options) {
|
||||
const elements = buildExpression(
|
||||
group.value.value,
|
||||
options.withPhantom(),
|
||||
false
|
||||
);
|
||||
|
||||
// \phantom isn't supposed to affect the elements it contains.
|
||||
// See "color" for more details.
|
||||
return new buildCommon.makeFragment(elements);
|
||||
};
|
||||
|
||||
groupTypes.hphantom = function(group, options) {
|
||||
let node = makeSpan(
|
||||
[], [buildGroup(group.value.body, options.withPhantom())]);
|
||||
node.height = 0;
|
||||
node.depth = 0;
|
||||
if (node.children) {
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
node.children[i].height = 0;
|
||||
node.children[i].depth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// See smash for comment re: use of makeVList
|
||||
node = buildCommon.makeVList([
|
||||
{type: "elem", elem: node},
|
||||
], "firstBaseline", null, options);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.vphantom = function(group, options) {
|
||||
const inner = makeSpan(
|
||||
["inner"], [buildGroup(group.value.body, options.withPhantom())]);
|
||||
const fix = makeSpan(["fix"], []);
|
||||
return makeSpan(
|
||||
["mord", "rlap"], [inner, fix], options);
|
||||
};
|
||||
|
||||
groupTypes.mclass = function(group, options) {
|
||||
const elements = buildExpression(group.value.value, options, true);
|
||||
|
||||
@@ -1774,7 +1734,7 @@ groupTypes.mclass = function(group, options) {
|
||||
* function for it. It also handles the interaction of size and style changes
|
||||
* between parents and children.
|
||||
*/
|
||||
const buildGroup = function(group, options, baseOptions) {
|
||||
export const buildGroup = function(group, options, baseOptions) {
|
||||
if (!group) {
|
||||
return makeSpan();
|
||||
}
|
||||
@@ -1807,7 +1767,7 @@ const buildGroup = function(group, options, baseOptions) {
|
||||
* Take an entire parse tree, and build it into an appropriate set of HTML
|
||||
* nodes.
|
||||
*/
|
||||
const buildHTML = function(tree, options) {
|
||||
export default function buildHTML(tree, options) {
|
||||
// buildExpression is destructive, so we need to make a clone
|
||||
// of the incoming tree so that it isn't accidentally changed
|
||||
tree = JSON.parse(JSON.stringify(tree));
|
||||
@@ -1835,6 +1795,4 @@ const buildHTML = function(tree, options) {
|
||||
htmlNode.setAttribute("aria-hidden", "true");
|
||||
|
||||
return htmlNode;
|
||||
};
|
||||
|
||||
module.exports = buildHTML;
|
||||
}
|
||||
|
@@ -60,7 +60,7 @@ const getVariant = function(group, options) {
|
||||
* Functions for handling the different types of groups found in the parse
|
||||
* tree. Each function should take a parse group and return a MathML node.
|
||||
*/
|
||||
const groupTypes = {};
|
||||
export const groupTypes = {};
|
||||
|
||||
const defaultVariant = {
|
||||
"mi": "italic",
|
||||
@@ -650,25 +650,6 @@ groupTypes.smash = function(group, options) {
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.phantom = function(group, options) {
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
return new mathMLTree.MathNode("mphantom", inner);
|
||||
};
|
||||
|
||||
groupTypes.hphantom = function(group, options) {
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
const node = new mathMLTree.MathNode("mphantom", inner);
|
||||
node.setAttribute("height", "0px");
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.vphantom = function(group, options) {
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
const node = new mathMLTree.MathNode("mphantom", inner);
|
||||
node.setAttribute("width", "0px");
|
||||
return node;
|
||||
};
|
||||
|
||||
groupTypes.mclass = function(group, options) {
|
||||
const inner = buildExpression(group.value.value, options);
|
||||
return new mathMLTree.MathNode("mstyle", inner);
|
||||
@@ -679,7 +660,7 @@ groupTypes.mclass = function(group, options) {
|
||||
* MathML nodes. A little simpler than the HTML version because we don't do any
|
||||
* previous-node handling.
|
||||
*/
|
||||
const buildExpression = function(expression, options) {
|
||||
export const buildExpression = function(expression, options) {
|
||||
const groups = [];
|
||||
for (let i = 0; i < expression.length; i++) {
|
||||
const group = expression[i];
|
||||
@@ -695,8 +676,9 @@ const buildExpression = function(expression, options) {
|
||||
* Takes a group from the parser and calls the appropriate groupTypes function
|
||||
* on it to produce a MathML node.
|
||||
*/
|
||||
// TODO(kevinb): determine if removeUnnecessaryRow should always be true
|
||||
const buildGroup = function(group, options, removeUnnecessaryRow = false) {
|
||||
export const buildGroup = function(
|
||||
group, options, removeUnnecessaryRow = false,
|
||||
) {
|
||||
if (!group) {
|
||||
return new mathMLTree.MathNode("mrow");
|
||||
}
|
||||
@@ -724,7 +706,7 @@ const buildGroup = function(group, options, removeUnnecessaryRow = false) {
|
||||
* Note that we actually return a domTree element with a `<math>` inside it so
|
||||
* we can do appropriate styling.
|
||||
*/
|
||||
const buildMathML = function(tree, texExpression, options) {
|
||||
export default function buildMathML(tree, texExpression, options) {
|
||||
const expression = buildExpression(tree, options);
|
||||
|
||||
// Wrap up the expression in an mrow so it is presented in the semantics
|
||||
@@ -744,6 +726,4 @@ const buildMathML = function(tree, texExpression, options) {
|
||||
|
||||
// You can't style <math> nodes, so we wrap the node in a span.
|
||||
return makeSpan(["katex-mathml"], [math]);
|
||||
};
|
||||
|
||||
module.exports = buildMathML;
|
||||
}
|
||||
|
123
src/defineFunction.js
Normal file
123
src/defineFunction.js
Normal file
@@ -0,0 +1,123 @@
|
||||
import functions from "./functions";
|
||||
import {groupTypes as htmlGroupTypes} from "./buildHTML";
|
||||
import {groupTypes as mathmlGroupTypes} from "./buildMathML";
|
||||
|
||||
/* This file contains a list of functions that we parse, identified by
|
||||
* the calls to defineFunction.
|
||||
*
|
||||
* The first argument to defineFunction is a single name or a list of names.
|
||||
* All functions named in such a list will share a single implementation.
|
||||
*
|
||||
* Each declared function can have associated properties, which
|
||||
* include the following:
|
||||
*
|
||||
* - numArgs: The number of arguments the function takes.
|
||||
* If this is the only property, it can be passed as a number
|
||||
* instead of an element of a properties object.
|
||||
* - argTypes: (optional) An array corresponding to each argument of the
|
||||
* function, giving the type of argument that should be parsed. Its
|
||||
* length should be equal to `numArgs + numOptionalArgs`. Valid
|
||||
* types:
|
||||
* - "size": A size-like thing, such as "1em" or "5ex"
|
||||
* - "color": An html color, like "#abc" or "blue"
|
||||
* - "original": The same type as the environment that the
|
||||
* function being parsed is in (e.g. used for the
|
||||
* bodies of functions like \textcolor where the
|
||||
* first argument is special and the second
|
||||
* argument is parsed normally)
|
||||
* Other possible types (probably shouldn't be used)
|
||||
* - "text": Text-like (e.g. \text)
|
||||
* - "math": Normal math
|
||||
* If undefined, this will be treated as an appropriate length
|
||||
* array of "original" strings
|
||||
* - greediness: (optional) The greediness of the function to use ungrouped
|
||||
* arguments.
|
||||
*
|
||||
* E.g. if you have an expression
|
||||
* \sqrt \frac 1 2
|
||||
* since \frac has greediness=2 vs \sqrt's greediness=1, \frac
|
||||
* will use the two arguments '1' and '2' as its two arguments,
|
||||
* then that whole function will be used as the argument to
|
||||
* \sqrt. On the other hand, the expressions
|
||||
* \frac \frac 1 2 3
|
||||
* and
|
||||
* \frac \sqrt 1 2
|
||||
* will fail because \frac and \frac have equal greediness
|
||||
* and \sqrt has a lower greediness than \frac respectively. To
|
||||
* make these parse, we would have to change them to:
|
||||
* \frac {\frac 1 2} 3
|
||||
* and
|
||||
* \frac {\sqrt 1} 2
|
||||
*
|
||||
* The default value is `1`
|
||||
* - allowedInText: (optional) Whether or not the function is allowed inside
|
||||
* text mode (default false)
|
||||
* - numOptionalArgs: (optional) The number of optional arguments the function
|
||||
* should parse. If the optional arguments aren't found,
|
||||
* `null` will be passed to the handler in their place.
|
||||
* (default 0)
|
||||
* - infix: (optional) Must be true if the function is an infix operator.
|
||||
*
|
||||
* The last argument is that implementation, the handler for the function(s).
|
||||
* It is called to handle these functions and their arguments.
|
||||
* It receives two arguments:
|
||||
* - context contains information and references provided by the parser
|
||||
* - args is an array of arguments obtained from TeX input
|
||||
* The context contains the following properties:
|
||||
* - funcName: the text (i.e. name) of the function, including \
|
||||
* - parser: the parser object
|
||||
* - lexer: the lexer object
|
||||
* - positions: the positions in the overall string of the function
|
||||
* and the arguments.
|
||||
* The latter three should only be used to produce error messages.
|
||||
*
|
||||
* The function should return an object with the following keys:
|
||||
* - type: The type of element that this is. This is then used in
|
||||
* buildHTML/buildMathML to determine which function
|
||||
* should be called to build this node into a DOM node
|
||||
* Any other data can be added to the object, which will be passed
|
||||
* in to the function in buildHTML/buildMathML as `group.value`.
|
||||
*/
|
||||
|
||||
export default function defineFunction(
|
||||
names, props, handler, type, htmlBuilder, mathmlBuilder
|
||||
) {
|
||||
if (typeof names === "string") {
|
||||
names = [names];
|
||||
}
|
||||
if (typeof props === "number") {
|
||||
props = { numArgs: props };
|
||||
}
|
||||
// Set default values of functions
|
||||
const data = {
|
||||
numArgs: props.numArgs,
|
||||
argTypes: props.argTypes,
|
||||
greediness: (props.greediness === undefined) ? 1 : props.greediness,
|
||||
allowedInText: !!props.allowedInText,
|
||||
allowedInMath: props.allowedInMath,
|
||||
numOptionalArgs: props.numOptionalArgs || 0,
|
||||
infix: !!props.infix,
|
||||
handler: handler,
|
||||
};
|
||||
for (let i = 0; i < names.length; ++i) {
|
||||
functions[names[i]] = data;
|
||||
}
|
||||
if (type) {
|
||||
if (htmlBuilder) {
|
||||
htmlGroupTypes[type] = htmlBuilder;
|
||||
}
|
||||
if (mathmlBuilder) {
|
||||
mathmlGroupTypes[type] = mathmlBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since the corresponding buildHTML/buildMathML function expects a
|
||||
// list of elements, we normalize for different kinds of arguments
|
||||
export const ordargument = function(arg) {
|
||||
if (arg.type === "ordgroup") {
|
||||
return arg.value;
|
||||
} else {
|
||||
return [arg];
|
||||
}
|
||||
};
|
121
src/functions.js
121
src/functions.js
@@ -2,115 +2,7 @@ import utils from "./utils";
|
||||
import ParseError from "./ParseError";
|
||||
import ParseNode from "./ParseNode";
|
||||
|
||||
/* This file contains a list of functions that we parse, identified by
|
||||
* the calls to defineFunction.
|
||||
*
|
||||
* The first argument to defineFunction is a single name or a list of names.
|
||||
* All functions named in such a list will share a single implementation.
|
||||
*
|
||||
* Each declared function can have associated properties, which
|
||||
* include the following:
|
||||
*
|
||||
* - numArgs: The number of arguments the function takes.
|
||||
* If this is the only property, it can be passed as a number
|
||||
* instead of an element of a properties object.
|
||||
* - argTypes: (optional) An array corresponding to each argument of the
|
||||
* function, giving the type of argument that should be parsed. Its
|
||||
* length should be equal to `numArgs + numOptionalArgs`. Valid
|
||||
* types:
|
||||
* - "size": A size-like thing, such as "1em" or "5ex"
|
||||
* - "color": An html color, like "#abc" or "blue"
|
||||
* - "original": The same type as the environment that the
|
||||
* function being parsed is in (e.g. used for the
|
||||
* bodies of functions like \textcolor where the
|
||||
* first argument is special and the second
|
||||
* argument is parsed normally)
|
||||
* Other possible types (probably shouldn't be used)
|
||||
* - "text": Text-like (e.g. \text)
|
||||
* - "math": Normal math
|
||||
* If undefined, this will be treated as an appropriate length
|
||||
* array of "original" strings
|
||||
* - greediness: (optional) The greediness of the function to use ungrouped
|
||||
* arguments.
|
||||
*
|
||||
* E.g. if you have an expression
|
||||
* \sqrt \frac 1 2
|
||||
* since \frac has greediness=2 vs \sqrt's greediness=1, \frac
|
||||
* will use the two arguments '1' and '2' as its two arguments,
|
||||
* then that whole function will be used as the argument to
|
||||
* \sqrt. On the other hand, the expressions
|
||||
* \frac \frac 1 2 3
|
||||
* and
|
||||
* \frac \sqrt 1 2
|
||||
* will fail because \frac and \frac have equal greediness
|
||||
* and \sqrt has a lower greediness than \frac respectively. To
|
||||
* make these parse, we would have to change them to:
|
||||
* \frac {\frac 1 2} 3
|
||||
* and
|
||||
* \frac {\sqrt 1} 2
|
||||
*
|
||||
* The default value is `1`
|
||||
* - allowedInText: (optional) Whether or not the function is allowed inside
|
||||
* text mode (default false)
|
||||
* - numOptionalArgs: (optional) The number of optional arguments the function
|
||||
* should parse. If the optional arguments aren't found,
|
||||
* `null` will be passed to the handler in their place.
|
||||
* (default 0)
|
||||
* - infix: (optional) Must be true if the function is an infix operator.
|
||||
*
|
||||
* The last argument is that implementation, the handler for the function(s).
|
||||
* It is called to handle these functions and their arguments.
|
||||
* It receives two arguments:
|
||||
* - context contains information and references provided by the parser
|
||||
* - args is an array of arguments obtained from TeX input
|
||||
* The context contains the following properties:
|
||||
* - funcName: the text (i.e. name) of the function, including \
|
||||
* - parser: the parser object
|
||||
* - lexer: the lexer object
|
||||
* - positions: the positions in the overall string of the function
|
||||
* and the arguments.
|
||||
* The latter three should only be used to produce error messages.
|
||||
*
|
||||
* The function should return an object with the following keys:
|
||||
* - type: The type of element that this is. This is then used in
|
||||
* buildHTML/buildMathML to determine which function
|
||||
* should be called to build this node into a DOM node
|
||||
* Any other data can be added to the object, which will be passed
|
||||
* in to the function in buildHTML/buildMathML as `group.value`.
|
||||
*/
|
||||
|
||||
function defineFunction(names, props, handler) {
|
||||
if (typeof names === "string") {
|
||||
names = [names];
|
||||
}
|
||||
if (typeof props === "number") {
|
||||
props = { numArgs: props };
|
||||
}
|
||||
// Set default values of functions
|
||||
const data = {
|
||||
numArgs: props.numArgs,
|
||||
argTypes: props.argTypes,
|
||||
greediness: (props.greediness === undefined) ? 1 : props.greediness,
|
||||
allowedInText: !!props.allowedInText,
|
||||
allowedInMath: props.allowedInMath,
|
||||
numOptionalArgs: props.numOptionalArgs || 0,
|
||||
infix: !!props.infix,
|
||||
handler: handler,
|
||||
};
|
||||
for (let i = 0; i < names.length; ++i) {
|
||||
module.exports[names[i]] = data;
|
||||
}
|
||||
}
|
||||
|
||||
// Since the corresponding buildHTML/buildMathML function expects a
|
||||
// list of elements, we normalize for different kinds of arguments
|
||||
const ordargument = function(arg) {
|
||||
if (arg.type === "ordgroup") {
|
||||
return arg.value;
|
||||
} else {
|
||||
return [arg];
|
||||
}
|
||||
};
|
||||
import defineFunction, {ordargument} from "./defineFunction";
|
||||
|
||||
// A normal square root
|
||||
defineFunction("\\sqrt", {
|
||||
@@ -234,16 +126,7 @@ defineFunction("\\KaTeX", {
|
||||
};
|
||||
});
|
||||
|
||||
defineFunction(["\\phantom", "\\hphantom", "\\vphantom"], {
|
||||
numArgs: 1,
|
||||
}, function(context, args) {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: context.funcName.slice(1),
|
||||
value: ordargument(body),
|
||||
body: body,
|
||||
};
|
||||
});
|
||||
import "./functions/phantom";
|
||||
|
||||
// Math class commands except \mathop
|
||||
defineFunction([
|
||||
|
108
src/functions/phantom.js
Normal file
108
src/functions/phantom.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import defineFunction, {ordargument} from "../defineFunction";
|
||||
import buildCommon from "../buildCommon";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
defineFunction(
|
||||
"\\phantom",
|
||||
{
|
||||
numArgs: 1,
|
||||
},
|
||||
(context, args) => {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "phantom",
|
||||
value: ordargument(body),
|
||||
};
|
||||
},
|
||||
"phantom",
|
||||
(group, options) => {
|
||||
const elements = html.buildExpression(
|
||||
group.value.value,
|
||||
options.withPhantom(),
|
||||
false
|
||||
);
|
||||
|
||||
// \phantom isn't supposed to affect the elements it contains.
|
||||
// See "color" for more details.
|
||||
return new buildCommon.makeFragment(elements);
|
||||
},
|
||||
(group, options) => {
|
||||
const inner = mml.buildExpression(group.value.value, options);
|
||||
return new mathMLTree.MathNode("mphantom", inner);
|
||||
},
|
||||
);
|
||||
|
||||
defineFunction(
|
||||
"\\hphantom",
|
||||
{
|
||||
numArgs: 1,
|
||||
},
|
||||
(context, args) => {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "hphantom",
|
||||
value: ordargument(body),
|
||||
body: body,
|
||||
};
|
||||
},
|
||||
"hphantom",
|
||||
(group, options) => {
|
||||
let node = buildCommon.makeSpan(
|
||||
[], [html.buildGroup(group.value.body, options.withPhantom())]);
|
||||
node.height = 0;
|
||||
node.depth = 0;
|
||||
if (node.children) {
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
node.children[i].height = 0;
|
||||
node.children[i].depth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// See smash for comment re: use of makeVList
|
||||
node = buildCommon.makeVList([
|
||||
{type: "elem", elem: node},
|
||||
], "firstBaseline", null, options);
|
||||
|
||||
return node;
|
||||
},
|
||||
(group, options) => {
|
||||
const inner = mml.buildExpression(group.value.value, options);
|
||||
const node = new mathMLTree.MathNode("mphantom", inner);
|
||||
node.setAttribute("height", "0px");
|
||||
return node;
|
||||
},
|
||||
);
|
||||
|
||||
defineFunction(
|
||||
"\\vphantom",
|
||||
{
|
||||
numArgs: 1,
|
||||
},
|
||||
(context, args) => {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "vphantom",
|
||||
value: ordargument(body),
|
||||
body: body,
|
||||
};
|
||||
},
|
||||
"vphantom",
|
||||
(group, options) => {
|
||||
const inner = buildCommon.makeSpan(
|
||||
["inner"],
|
||||
[html.buildGroup(group.value.body, options.withPhantom())]);
|
||||
const fix = buildCommon.makeSpan(["fix"], []);
|
||||
return buildCommon.makeSpan(
|
||||
["mord", "rlap"], [inner, fix], options);
|
||||
},
|
||||
(group, options) => {
|
||||
const inner = mml.buildExpression(group.value.value, options);
|
||||
const node = new mathMLTree.MathNode("mphantom", inner);
|
||||
node.setAttribute("width", "0px");
|
||||
return node;
|
||||
},
|
||||
);
|
||||
|
Reference in New Issue
Block a user