mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-06 03:38:39 +00:00
Move HTML and MathML builders for symbol groups into src/functions/{symbolsOp,symbolsOrd}.js. (#1334)
* Move HTML and MathML builders for symbol groups into src/functions/{symbolsOp,symbolsOrd}.js.
This commit is contained in:
@@ -222,10 +222,10 @@ const boldsymbol = function(
|
|||||||
/**
|
/**
|
||||||
* Makes either a mathord or textord in the correct font and color.
|
* Makes either a mathord or textord in the correct font and color.
|
||||||
*/
|
*/
|
||||||
const makeOrd = function(
|
const makeOrd = function<NODETYPE: "textord" | "mathord">(
|
||||||
group: ParseNode<*>,
|
group: ParseNode<NODETYPE>,
|
||||||
options: Options,
|
options: Options,
|
||||||
type: NodeType,
|
type: NODETYPE,
|
||||||
): domTree.symbolNode {
|
): domTree.symbolNode {
|
||||||
const mode = group.mode;
|
const mode = group.mode;
|
||||||
const value = group.value;
|
const value = group.value;
|
||||||
|
@@ -242,28 +242,6 @@ export const makeNullDelimiter = function(options, classes) {
|
|||||||
* Simpler types come at the beginning, while complicated types come afterwards.
|
* Simpler types come at the beginning, while complicated types come afterwards.
|
||||||
*/
|
*/
|
||||||
export const groupTypes = {
|
export const groupTypes = {
|
||||||
mathord: (group, options) => buildCommon.makeOrd(group, options, "mathord"),
|
|
||||||
|
|
||||||
textord: (group, options) => buildCommon.makeOrd(group, options, "textord"),
|
|
||||||
|
|
||||||
bin: (group, options) =>
|
|
||||||
buildCommon.mathsym(group.value, group.mode, options, ["mbin"]),
|
|
||||||
|
|
||||||
rel: (group, options) =>
|
|
||||||
buildCommon.mathsym(group.value, group.mode, options, ["mrel"]),
|
|
||||||
|
|
||||||
open: (group, options) =>
|
|
||||||
buildCommon.mathsym(group.value, group.mode, options, ["mopen"]),
|
|
||||||
|
|
||||||
close: (group, options) =>
|
|
||||||
buildCommon.mathsym(group.value, group.mode, options, ["mclose"]),
|
|
||||||
|
|
||||||
inner: (group, options) =>
|
|
||||||
buildCommon.mathsym(group.value, group.mode, options, ["minner"]),
|
|
||||||
|
|
||||||
punct: (group, options) =>
|
|
||||||
buildCommon.mathsym(group.value, group.mode, options, ["mpunct"]),
|
|
||||||
|
|
||||||
ordgroup: (group, options) => makeSpan(
|
ordgroup: (group, options) => makeSpan(
|
||||||
["mord"], buildExpression(group.value, options, true), options),
|
["mord"], buildExpression(group.value, options, true), options),
|
||||||
|
|
||||||
|
@@ -60,7 +60,7 @@ export const makeTextRow = function(body, options) {
|
|||||||
/**
|
/**
|
||||||
* Returns the math variant as a string or null if none is required.
|
* Returns the math variant as a string or null if none is required.
|
||||||
*/
|
*/
|
||||||
const getVariant = function(group, options) {
|
export const getVariant = function(group, options) {
|
||||||
const font = options.font;
|
const font = options.font;
|
||||||
if (!font) {
|
if (!font) {
|
||||||
return null;
|
return null;
|
||||||
@@ -96,97 +96,6 @@ const getVariant = function(group, options) {
|
|||||||
*/
|
*/
|
||||||
export const groupTypes = {};
|
export const groupTypes = {};
|
||||||
|
|
||||||
const defaultVariant = {
|
|
||||||
"mi": "italic",
|
|
||||||
"mn": "normal",
|
|
||||||
"mtext": "normal",
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.mathord = function(group, options) {
|
|
||||||
const node = new mathMLTree.MathNode(
|
|
||||||
"mi",
|
|
||||||
[makeText(group.value, group.mode)]);
|
|
||||||
|
|
||||||
const variant = getVariant(group, options) || "italic";
|
|
||||||
if (variant !== defaultVariant[node.type]) {
|
|
||||||
node.setAttribute("mathvariant", variant);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.textord = function(group, options) {
|
|
||||||
const text = makeText(group.value, group.mode);
|
|
||||||
|
|
||||||
const variant = getVariant(group, options) || "normal";
|
|
||||||
|
|
||||||
let node;
|
|
||||||
if (group.mode === 'text') {
|
|
||||||
node = new mathMLTree.MathNode("mtext", [text]);
|
|
||||||
} else if (/[0-9]/.test(group.value)) {
|
|
||||||
// TODO(kevinb) merge adjacent <mn> nodes
|
|
||||||
// do it as a post processing step
|
|
||||||
node = new mathMLTree.MathNode("mn", [text]);
|
|
||||||
} else if (group.value === "\\prime") {
|
|
||||||
node = new mathMLTree.MathNode("mo", [text]);
|
|
||||||
} else {
|
|
||||||
node = new mathMLTree.MathNode("mi", [text]);
|
|
||||||
}
|
|
||||||
if (variant !== defaultVariant[node.type]) {
|
|
||||||
node.setAttribute("mathvariant", variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.bin = function(group, options) {
|
|
||||||
const node = new mathMLTree.MathNode(
|
|
||||||
"mo", [makeText(group.value, group.mode)]);
|
|
||||||
|
|
||||||
const variant = getVariant(group, options);
|
|
||||||
if (variant === "bold-italic") {
|
|
||||||
node.setAttribute("mathvariant", variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.rel = function(group) {
|
|
||||||
const node = new mathMLTree.MathNode(
|
|
||||||
"mo", [makeText(group.value, group.mode)]);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.open = function(group) {
|
|
||||||
const node = new mathMLTree.MathNode(
|
|
||||||
"mo", [makeText(group.value, group.mode)]);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.close = function(group) {
|
|
||||||
const node = new mathMLTree.MathNode(
|
|
||||||
"mo", [makeText(group.value, group.mode)]);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.inner = function(group) {
|
|
||||||
const node = new mathMLTree.MathNode(
|
|
||||||
"mo", [makeText(group.value, group.mode)]);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.punct = function(group) {
|
|
||||||
const node = new mathMLTree.MathNode(
|
|
||||||
"mo", [makeText(group.value, group.mode)]);
|
|
||||||
|
|
||||||
node.setAttribute("separator", "true");
|
|
||||||
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
|
|
||||||
groupTypes.ordgroup = function(group, options) {
|
groupTypes.ordgroup = function(group, options) {
|
||||||
const inner = buildExpression(group.value, options);
|
const inner = buildExpression(group.value, options);
|
||||||
|
|
||||||
|
@@ -26,6 +26,12 @@ export type FunctionHandler<NODETYPE: NodeType> = (
|
|||||||
optArgs: (?ParseNode<*>)[],
|
optArgs: (?ParseNode<*>)[],
|
||||||
) => NodeValue<NODETYPE>;
|
) => NodeValue<NODETYPE>;
|
||||||
|
|
||||||
|
export type HtmlBuilder<NODETYPE> = (ParseNode<NODETYPE>, Options) => HtmlDomNode;
|
||||||
|
export type MathMLBuilder<NODETYPE> = (
|
||||||
|
group: ParseNode<NODETYPE>,
|
||||||
|
options: Options,
|
||||||
|
) => MathNode | TextNode | domTree.documentFragment;
|
||||||
|
|
||||||
export type FunctionPropSpec = {
|
export type FunctionPropSpec = {
|
||||||
// The number of arguments the function takes.
|
// The number of arguments the function takes.
|
||||||
numArgs: number,
|
numArgs: number,
|
||||||
@@ -106,16 +112,13 @@ type FunctionDefSpec<NODETYPE: NodeType> = {|
|
|||||||
|
|
||||||
// This function returns an object representing the DOM structure to be
|
// This function returns an object representing the DOM structure to be
|
||||||
// created when rendering the defined LaTeX function.
|
// created when rendering the defined LaTeX function.
|
||||||
htmlBuilder?: (group: ParseNode<NODETYPE>, options: Options) => HtmlDomNode,
|
htmlBuilder?: HtmlBuilder<NODETYPE>,
|
||||||
|
|
||||||
// TODO: Currently functions/op.js returns documentFragment. Refactor it
|
// TODO: Currently functions/op.js returns documentFragment. Refactor it
|
||||||
// and update the return type of this function.
|
// and update the return type of this function.
|
||||||
// This function returns an object representing the MathML structure to be
|
// This function returns an object representing the MathML structure to be
|
||||||
// created when rendering the defined LaTeX function.
|
// created when rendering the defined LaTeX function.
|
||||||
mathmlBuilder?: (
|
mathmlBuilder?: MathMLBuilder<NODETYPE>,
|
||||||
group: ParseNode<NODETYPE>,
|
|
||||||
options: Options,
|
|
||||||
) => MathNode | TextNode | domTree.documentFragment,
|
|
||||||
|};
|
|};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,6 +201,28 @@ export default function defineFunction<NODETYPE: NodeType>({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this to register only the HTML and MathML builders for a function (e.g.
|
||||||
|
* if the function's ParseNode is generated in Parser.js rather than via a
|
||||||
|
* stand-alone handler provided to `defineFunction`).
|
||||||
|
*/
|
||||||
|
export function defineFunctionBuilders<NODETYPE: NodeType>({
|
||||||
|
type, htmlBuilder, mathmlBuilder,
|
||||||
|
}: {
|
||||||
|
type: NODETYPE,
|
||||||
|
htmlBuilder: HtmlBuilder<NODETYPE>,
|
||||||
|
mathmlBuilder: MathMLBuilder<NODETYPE>,
|
||||||
|
}) {
|
||||||
|
defineFunction({
|
||||||
|
type,
|
||||||
|
names: [],
|
||||||
|
props: {numArgs: 0},
|
||||||
|
handler() { throw new Error('Should never be called.'); },
|
||||||
|
htmlBuilder,
|
||||||
|
mathmlBuilder,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Since the corresponding buildHTML/buildMathML function expects a
|
// Since the corresponding buildHTML/buildMathML function expects a
|
||||||
// list of elements, we normalize for different kinds of arguments
|
// list of elements, we normalize for different kinds of arguments
|
||||||
export const ordargument = function(arg: ParseNode<*>): ParseNode<*>[] {
|
export const ordargument = function(arg: ParseNode<*>): ParseNode<*>[] {
|
||||||
|
@@ -35,6 +35,8 @@ import "./functions/sizing";
|
|||||||
import "./functions/smash";
|
import "./functions/smash";
|
||||||
import "./functions/sqrt";
|
import "./functions/sqrt";
|
||||||
import "./functions/styling";
|
import "./functions/styling";
|
||||||
|
import "./functions/symbolsOp";
|
||||||
|
import "./functions/symbolsOrd";
|
||||||
import "./functions/text";
|
import "./functions/text";
|
||||||
import "./functions/underline";
|
import "./functions/underline";
|
||||||
import "./functions/verb";
|
import "./functions/verb";
|
||||||
|
52
src/functions/symbolsOp.js
Normal file
52
src/functions/symbolsOp.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// @flow
|
||||||
|
import {defineFunctionBuilders} from "../defineFunction";
|
||||||
|
import buildCommon from "../buildCommon";
|
||||||
|
import mathMLTree from "../mathMLTree";
|
||||||
|
|
||||||
|
import * as mml from "../buildMathML";
|
||||||
|
|
||||||
|
import type Options from "../Options";
|
||||||
|
import type ParseNode from "../ParseNode";
|
||||||
|
import type {Group} from "../symbols";
|
||||||
|
|
||||||
|
// Operator ParseNodes created in Parser.js from symbol Groups in src/symbols.js.
|
||||||
|
|
||||||
|
// NOTE: `NODETYPE` is constrained by `Group` instead of `NodeType`. This
|
||||||
|
// guarantees that `group.value` is a string as required by buildCommon.mathsym.
|
||||||
|
function defineOpFunction<NODETYPE: Group>(
|
||||||
|
type: NODETYPE,
|
||||||
|
mathmlNodePostProcessor?: (
|
||||||
|
mathMLTree.MathNode,
|
||||||
|
ParseNode<NODETYPE>,
|
||||||
|
Options) => *,
|
||||||
|
) {
|
||||||
|
defineFunctionBuilders({
|
||||||
|
type,
|
||||||
|
htmlBuilder(group: ParseNode<NODETYPE>, options) {
|
||||||
|
const groupValue: string = group.value;
|
||||||
|
return buildCommon.mathsym(
|
||||||
|
groupValue, group.mode, options, ["m" + type]);
|
||||||
|
},
|
||||||
|
mathmlBuilder(group: ParseNode<NODETYPE>, options) {
|
||||||
|
const node = new mathMLTree.MathNode(
|
||||||
|
"mo", [mml.makeText(group.value, group.mode)]);
|
||||||
|
if (mathmlNodePostProcessor) {
|
||||||
|
mathmlNodePostProcessor(node, group, options);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
defineOpFunction("bin", (mathNode, group, options) => {
|
||||||
|
const variant = mml.getVariant(group, options);
|
||||||
|
if (variant === "bold-italic") {
|
||||||
|
mathNode.setAttribute("mathvariant", variant);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
defineOpFunction("rel");
|
||||||
|
defineOpFunction("open");
|
||||||
|
defineOpFunction("close");
|
||||||
|
defineOpFunction("inner");
|
||||||
|
defineOpFunction("punct", mathNode => mathNode.setAttribute("separator", "true"));
|
||||||
|
|
63
src/functions/symbolsOrd.js
Normal file
63
src/functions/symbolsOrd.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// @flow
|
||||||
|
import {defineFunctionBuilders} from "../defineFunction";
|
||||||
|
import buildCommon from "../buildCommon";
|
||||||
|
import mathMLTree from "../mathMLTree";
|
||||||
|
|
||||||
|
import * as mml from "../buildMathML";
|
||||||
|
|
||||||
|
// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
|
||||||
|
// src/symbols.js.
|
||||||
|
|
||||||
|
const defaultVariant = {
|
||||||
|
"mi": "italic",
|
||||||
|
"mn": "normal",
|
||||||
|
"mtext": "normal",
|
||||||
|
};
|
||||||
|
|
||||||
|
defineFunctionBuilders({
|
||||||
|
type: "mathord",
|
||||||
|
htmlBuilder(group, options) {
|
||||||
|
return buildCommon.makeOrd(group, options, "mathord");
|
||||||
|
},
|
||||||
|
mathmlBuilder(group, options) {
|
||||||
|
const node = new mathMLTree.MathNode(
|
||||||
|
"mi",
|
||||||
|
[mml.makeText(group.value, group.mode)]);
|
||||||
|
|
||||||
|
const variant = mml.getVariant(group, options) || "italic";
|
||||||
|
if (variant !== defaultVariant[node.type]) {
|
||||||
|
node.setAttribute("mathvariant", variant);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
defineFunctionBuilders({
|
||||||
|
type: "textord",
|
||||||
|
htmlBuilder(group, options) {
|
||||||
|
return buildCommon.makeOrd(group, options, "textord");
|
||||||
|
},
|
||||||
|
mathmlBuilder(group, options) {
|
||||||
|
const text = mml.makeText(group.value, group.mode);
|
||||||
|
|
||||||
|
const variant = mml.getVariant(group, options) || "normal";
|
||||||
|
|
||||||
|
let node;
|
||||||
|
if (group.mode === 'text') {
|
||||||
|
node = new mathMLTree.MathNode("mtext", [text]);
|
||||||
|
} else if (/[0-9]/.test(group.value)) {
|
||||||
|
// TODO(kevinb) merge adjacent <mn> nodes
|
||||||
|
// do it as a post processing step
|
||||||
|
node = new mathMLTree.MathNode("mn", [text]);
|
||||||
|
} else if (group.value === "\\prime") {
|
||||||
|
node = new mathMLTree.MathNode("mo", [text]);
|
||||||
|
} else {
|
||||||
|
node = new mathMLTree.MathNode("mi", [text]);
|
||||||
|
}
|
||||||
|
if (variant !== defaultVariant[node.type]) {
|
||||||
|
node.setAttribute("mathvariant", variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
});
|
@@ -24,7 +24,7 @@ type Font = "main" | "ams"
|
|||||||
// types for raw text tokens, and we want to avoid conflicts with higher-level
|
// types for raw text tokens, and we want to avoid conflicts with higher-level
|
||||||
// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
|
// `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
|
||||||
// looking up the `symbols` map.
|
// looking up the `symbols` map.
|
||||||
type Group =
|
export type Group =
|
||||||
"accent-token" | "bin" | "close" | "inner" | "mathord" |
|
"accent-token" | "bin" | "close" | "inner" | "mathord" |
|
||||||
"op-token" | "open" | "punct" | "rel" | "spacing" | "textord";
|
"op-token" | "open" | "punct" | "rel" | "spacing" | "textord";
|
||||||
type CharInfoMap = {[string]: {font: Font, group: Group, replace: ?string}};
|
type CharInfoMap = {[string]: {font: Font, group: Group, replace: ?string}};
|
||||||
|
Reference in New Issue
Block a user