完成世界书、骰子、apiconfig页面处理
This commit is contained in:
314
frontend/node_modules/katex/src/Options.ts
generated
vendored
Normal file
314
frontend/node_modules/katex/src/Options.ts
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* This file contains information about the options that the Parser carries
|
||||
* around with it while parsing. Data is held in an `Options` object, and when
|
||||
* recursing, a new `Options` object can be created with the `.with*` and
|
||||
* `.reset` functions.
|
||||
*/
|
||||
|
||||
import {getGlobalMetrics} from "./fontMetrics";
|
||||
import type {FontMetrics} from "./fontMetrics";
|
||||
import type {StyleInterface} from "./Style";
|
||||
|
||||
const sizeStyleMap = [
|
||||
// Each element contains [textsize, scriptsize, scriptscriptsize].
|
||||
// The size mappings are taken from TeX with \normalsize=10pt.
|
||||
[1, 1, 1], // size1: [5, 5, 5] \tiny
|
||||
[2, 1, 1], // size2: [6, 5, 5]
|
||||
[3, 1, 1], // size3: [7, 5, 5] \scriptsize
|
||||
[4, 2, 1], // size4: [8, 6, 5] \footnotesize
|
||||
[5, 2, 1], // size5: [9, 6, 5] \small
|
||||
[6, 3, 1], // size6: [10, 7, 5] \normalsize
|
||||
[7, 4, 2], // size7: [12, 8, 6] \large
|
||||
[8, 6, 3], // size8: [14.4, 10, 7] \Large
|
||||
[9, 7, 6], // size9: [17.28, 12, 10] \LARGE
|
||||
[10, 8, 7], // size10: [20.74, 14.4, 12] \huge
|
||||
[11, 10, 9], // size11: [24.88, 20.74, 17.28] \HUGE
|
||||
];
|
||||
|
||||
const sizeMultipliers = [
|
||||
// fontMetrics.js:getGlobalMetrics also uses size indexes, so if
|
||||
// you change size indexes, change that function.
|
||||
0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.44, 1.728, 2.074, 2.488,
|
||||
];
|
||||
|
||||
const sizeAtStyle = function(size: number, style: StyleInterface): number {
|
||||
return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1];
|
||||
};
|
||||
|
||||
// In these types, "" (empty string) means "no change".
|
||||
export type FontWeight = "textbf" | "textmd" | "";
|
||||
export type FontShape = "textit" | "textup" | "";
|
||||
|
||||
export type OptionsData = {
|
||||
style: StyleInterface;
|
||||
color?: string | undefined;
|
||||
size?: number;
|
||||
textSize?: number;
|
||||
phantom?: boolean;
|
||||
font?: string;
|
||||
fontFamily?: string;
|
||||
fontWeight?: FontWeight;
|
||||
fontShape?: FontShape;
|
||||
sizeMultiplier?: number;
|
||||
maxSize: number;
|
||||
minRuleThickness: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the main options class. It contains the current style, size, color,
|
||||
* and font.
|
||||
*
|
||||
* Options objects should not be modified. To create a new Options with
|
||||
* different properties, call a `.having*` method.
|
||||
*/
|
||||
class Options {
|
||||
style: StyleInterface;
|
||||
color: string | undefined;
|
||||
size: number;
|
||||
textSize: number;
|
||||
phantom: boolean;
|
||||
// A font family applies to a group of fonts (i.e. SansSerif), while a font
|
||||
// represents a specific font (i.e. SansSerif Bold).
|
||||
// See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm
|
||||
font: string;
|
||||
fontFamily: string;
|
||||
fontWeight: FontWeight;
|
||||
fontShape: FontShape;
|
||||
sizeMultiplier: number;
|
||||
maxSize: number;
|
||||
minRuleThickness: number;
|
||||
_fontMetrics: FontMetrics | undefined;
|
||||
|
||||
/**
|
||||
* The base size index.
|
||||
*/
|
||||
static BASESIZE: number = 6;
|
||||
|
||||
constructor(data: OptionsData) {
|
||||
this.style = data.style;
|
||||
this.color = data.color;
|
||||
this.size = data.size || Options.BASESIZE;
|
||||
this.textSize = data.textSize || this.size;
|
||||
this.phantom = !!data.phantom;
|
||||
this.font = data.font || "";
|
||||
this.fontFamily = data.fontFamily || "";
|
||||
this.fontWeight = data.fontWeight || '';
|
||||
this.fontShape = data.fontShape || '';
|
||||
this.sizeMultiplier = sizeMultipliers[this.size - 1];
|
||||
this.maxSize = data.maxSize;
|
||||
this.minRuleThickness = data.minRuleThickness;
|
||||
this._fontMetrics = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new options object with the same properties as "this". Properties
|
||||
* from "extension" will be copied to the new options object.
|
||||
*/
|
||||
extend(extension: Partial<OptionsData>): Options {
|
||||
const data: OptionsData = {
|
||||
style: this.style,
|
||||
size: this.size,
|
||||
textSize: this.textSize,
|
||||
color: this.color,
|
||||
phantom: this.phantom,
|
||||
font: this.font,
|
||||
fontFamily: this.fontFamily,
|
||||
fontWeight: this.fontWeight,
|
||||
fontShape: this.fontShape,
|
||||
maxSize: this.maxSize,
|
||||
minRuleThickness: this.minRuleThickness,
|
||||
};
|
||||
|
||||
Object.assign(data, extension);
|
||||
|
||||
return new Options(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an options object with the given style. If `this.style === style`,
|
||||
* returns `this`.
|
||||
*/
|
||||
havingStyle(style: StyleInterface): Options {
|
||||
if (this.style === style) {
|
||||
return this;
|
||||
} else {
|
||||
return this.extend({
|
||||
style: style,
|
||||
size: sizeAtStyle(this.textSize, style),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an options object with a cramped version of the current style. If
|
||||
* the current style is cramped, returns `this`.
|
||||
*/
|
||||
havingCrampedStyle(): Options {
|
||||
return this.havingStyle(this.style.cramp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an options object with the given size and in at least `\textstyle`.
|
||||
* Returns `this` if appropriate.
|
||||
*/
|
||||
havingSize(size: number): Options {
|
||||
if (this.size === size && this.textSize === size) {
|
||||
return this;
|
||||
} else {
|
||||
return this.extend({
|
||||
style: this.style.text(),
|
||||
size: size,
|
||||
textSize: size,
|
||||
sizeMultiplier: sizeMultipliers[size - 1],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like `this.havingSize(BASESIZE).havingStyle(style)`. If `style` is omitted,
|
||||
* changes to at least `\textstyle`.
|
||||
*/
|
||||
havingBaseStyle(style: StyleInterface): Options {
|
||||
style = style || this.style.text();
|
||||
const wantSize = sizeAtStyle(Options.BASESIZE, style);
|
||||
if (this.size === wantSize && this.textSize === Options.BASESIZE
|
||||
&& this.style === style) {
|
||||
return this;
|
||||
} else {
|
||||
return this.extend({
|
||||
style: style,
|
||||
size: wantSize,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the effect of sizing changes such as \Huge.
|
||||
* Keep the effect of the current style, such as \scriptstyle.
|
||||
*/
|
||||
havingBaseSizing(): Options {
|
||||
let size;
|
||||
switch (this.style.id) {
|
||||
case 4:
|
||||
case 5:
|
||||
size = 3; // normalsize in scriptstyle
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
size = 1; // normalsize in scriptscriptstyle
|
||||
break;
|
||||
default:
|
||||
size = 6; // normalsize in textstyle or displaystyle
|
||||
}
|
||||
return this.extend({
|
||||
style: this.style.text(),
|
||||
size: size,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new options object with the given color.
|
||||
*/
|
||||
withColor(color: string): Options {
|
||||
return this.extend({
|
||||
color: color,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new options object with "phantom" set to true.
|
||||
*/
|
||||
withPhantom(): Options {
|
||||
return this.extend({
|
||||
phantom: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new options object with the given math font or old text font.
|
||||
* @type {[type]}
|
||||
*/
|
||||
withFont(font: string): Options {
|
||||
return this.extend({
|
||||
font,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new options objects with the given fontFamily.
|
||||
*/
|
||||
withTextFontFamily(fontFamily: string): Options {
|
||||
return this.extend({
|
||||
fontFamily,
|
||||
font: "",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new options object with the given font weight
|
||||
*/
|
||||
withTextFontWeight(fontWeight: FontWeight): Options {
|
||||
return this.extend({
|
||||
fontWeight,
|
||||
font: "",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new options object with the given font weight
|
||||
*/
|
||||
withTextFontShape(fontShape: FontShape): Options {
|
||||
return this.extend({
|
||||
fontShape,
|
||||
font: "",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSS sizing classes required to switch from enclosing options
|
||||
* `oldOptions` to `this`. Returns an array of classes.
|
||||
*/
|
||||
sizingClasses(oldOptions: Options): Array<string> {
|
||||
if (oldOptions.size !== this.size) {
|
||||
return ["sizing", "reset-size" + oldOptions.size, "size" + this.size];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSS sizing classes required to switch to the base size. Like
|
||||
* `this.havingSize(BASESIZE).sizingClasses(this)`.
|
||||
*/
|
||||
baseSizingClasses(): Array<string> {
|
||||
if (this.size !== Options.BASESIZE) {
|
||||
return ["sizing", "reset-size" + this.size, "size" + Options.BASESIZE];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the font metrics for this size.
|
||||
*/
|
||||
fontMetrics(): FontMetrics {
|
||||
if (!this._fontMetrics) {
|
||||
this._fontMetrics = getGlobalMetrics(this.size);
|
||||
}
|
||||
return this._fontMetrics;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the CSS color of the current options object
|
||||
*/
|
||||
getColor(): string | undefined {
|
||||
if (this.phantom) {
|
||||
return "transparent";
|
||||
} else {
|
||||
return this.color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Options;
|
||||
775
frontend/node_modules/katex/src/buildCommon.ts
generated
vendored
Normal file
775
frontend/node_modules/katex/src/buildCommon.ts
generated
vendored
Normal file
@@ -0,0 +1,775 @@
|
||||
/* eslint no-console:0 */
|
||||
/**
|
||||
* This module contains general functions that can be used for building
|
||||
* different kinds of domTree nodes in a consistent manner.
|
||||
*/
|
||||
|
||||
import {SymbolNode, Anchor, Span, PathNode, SvgNode, createClass} from "./domTree";
|
||||
import {getCharacterMetrics} from "./fontMetrics";
|
||||
import symbols, {ligatures} from "./symbols";
|
||||
import {wideCharacterFont} from "./wide-character";
|
||||
import {calculateSize, makeEm} from "./units";
|
||||
import {DocumentFragment} from "./tree";
|
||||
|
||||
import type Options from "./Options";
|
||||
import type {ParseNode} from "./parseNode";
|
||||
import type {CharacterMetrics} from "./fontMetrics";
|
||||
import type {FontVariant, Mode} from "./types";
|
||||
import type {documentFragment as HtmlDocumentFragment} from "./domTree";
|
||||
import type {HtmlDomNode, DomSpan, SvgSpan, CssStyle} from "./domTree";
|
||||
import type {Measurement} from "./units";
|
||||
|
||||
/**
|
||||
* Looks up the given symbol in fontMetrics, after applying any symbol
|
||||
* replacements defined in symbol.js
|
||||
*/
|
||||
const lookupSymbol = function(
|
||||
value: string,
|
||||
// TODO(#963): Use a union type for this.
|
||||
fontName: string,
|
||||
mode: Mode,
|
||||
): {
|
||||
value: string;
|
||||
metrics: CharacterMetrics | null | undefined;
|
||||
} {
|
||||
// Replace the value with its replaced value from symbol.js
|
||||
if (symbols[mode][value]) {
|
||||
const replacement = symbols[mode][value].replace;
|
||||
if (replacement) {
|
||||
value = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
metrics: getCharacterMetrics(value, fontName, mode),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a symbolNode after translation via the list of symbols in symbols.js.
|
||||
* Correctly pulls out metrics for the character, and optionally takes a list of
|
||||
* classes to be attached to the node.
|
||||
*
|
||||
* TODO: make argument order closer to makeSpan
|
||||
* TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
|
||||
* should if present come first in `classes`.
|
||||
* TODO(#953): Make `options` mandatory and always pass it in.
|
||||
*/
|
||||
export const makeSymbol = function(
|
||||
value: string,
|
||||
fontName: string,
|
||||
mode: Mode,
|
||||
options?: Options,
|
||||
classes?: string[],
|
||||
): SymbolNode {
|
||||
const lookup = lookupSymbol(value, fontName, mode);
|
||||
const metrics = lookup.metrics;
|
||||
value = lookup.value;
|
||||
|
||||
let symbolNode;
|
||||
if (metrics) {
|
||||
let italic = metrics.italic;
|
||||
if (mode === "text" || (options && options.font === "mathit")) {
|
||||
italic = 0;
|
||||
}
|
||||
symbolNode = new SymbolNode(
|
||||
value, metrics.height, metrics.depth, italic, metrics.skew,
|
||||
metrics.width, classes);
|
||||
} else {
|
||||
// TODO(emily): Figure out a good way to only print this in development
|
||||
typeof console !== "undefined" && console.warn("No character metrics " +
|
||||
`for '${value}' in style '${fontName}' and mode '${mode}'`);
|
||||
symbolNode = new SymbolNode(value, 0, 0, 0, 0, 0, classes);
|
||||
}
|
||||
|
||||
if (options) {
|
||||
symbolNode.maxFontSize = options.sizeMultiplier;
|
||||
if (options.style.isTight()) {
|
||||
symbolNode.classes.push("mtight");
|
||||
}
|
||||
const color = options.getColor();
|
||||
if (color) {
|
||||
symbolNode.style.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
return symbolNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a symbol in Main-Regular or AMS-Regular.
|
||||
* Used for rel, bin, open, close, inner, and punct.
|
||||
*/
|
||||
export const mathsym = function(
|
||||
value: string,
|
||||
mode: Mode,
|
||||
options: Options,
|
||||
classes: string[] = [],
|
||||
): SymbolNode {
|
||||
// Decide what font to render the symbol in by its entry in the symbols
|
||||
// table.
|
||||
// Have a special case for when the value = \ because the \ is used as a
|
||||
// textord in unsupported command errors but cannot be parsed as a regular
|
||||
// text ordinal and is therefore not present as a symbol in the symbols
|
||||
// table for text, as well as a special case for boldsymbol because it
|
||||
// can be used for bold + and -
|
||||
if (options.font === "boldsymbol" &&
|
||||
lookupSymbol(value, "Main-Bold", mode).metrics) {
|
||||
return makeSymbol(value, "Main-Bold", mode, options,
|
||||
classes.concat(["mathbf"]));
|
||||
} else if (value === "\\" || symbols[mode][value].font === "main") {
|
||||
return makeSymbol(value, "Main-Regular", mode, options, classes);
|
||||
} else {
|
||||
return makeSymbol(
|
||||
value, "AMS-Regular", mode, options, classes.concat(["amsrm"]));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines which of the two font names (Main-Bold and Math-BoldItalic) and
|
||||
* corresponding style tags (mathbf or boldsymbol) to use for font "boldsymbol",
|
||||
* depending on the symbol. Use this function instead of fontMap for font
|
||||
* "boldsymbol".
|
||||
*/
|
||||
const boldsymbol = function(
|
||||
value: string,
|
||||
mode: Mode,
|
||||
options: Options,
|
||||
classes: string[],
|
||||
type: "mathord" | "textord",
|
||||
): {
|
||||
fontName: string;
|
||||
fontClass: string;
|
||||
} {
|
||||
if (type !== "textord" &&
|
||||
lookupSymbol(value, "Math-BoldItalic", mode).metrics) {
|
||||
return {
|
||||
fontName: "Math-BoldItalic",
|
||||
fontClass: "boldsymbol",
|
||||
};
|
||||
} else {
|
||||
// Some glyphs do not exist in Math-BoldItalic so we need to use
|
||||
// Main-Bold instead.
|
||||
return {
|
||||
fontName: "Main-Bold",
|
||||
fontClass: "mathbf",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes either a mathord or textord in the correct font and color.
|
||||
*/
|
||||
export const makeOrd = function<NODETYPE extends "spacing" | "mathord" | "textord">(
|
||||
group: ParseNode<NODETYPE>,
|
||||
options: Options,
|
||||
type: "mathord" | "textord",
|
||||
): HtmlDocumentFragment | SymbolNode {
|
||||
const mode = group.mode;
|
||||
const text = group.text;
|
||||
|
||||
const classes = ["mord"];
|
||||
|
||||
// Math mode or Old font (i.e. \rm)
|
||||
const isFont = mode === "math" || (mode === "text" && options.font);
|
||||
const fontOrFamily = isFont ? options.font : options.fontFamily;
|
||||
let wideFontName = "";
|
||||
let wideFontClass = "";
|
||||
if (text.charCodeAt(0) === 0xD835) {
|
||||
[wideFontName, wideFontClass] = wideCharacterFont(text, mode);
|
||||
}
|
||||
if (wideFontName.length > 0) {
|
||||
// surrogate pairs get special treatment
|
||||
return makeSymbol(text, wideFontName, mode, options,
|
||||
classes.concat(wideFontClass));
|
||||
} else if (fontOrFamily) {
|
||||
let fontName;
|
||||
let fontClasses;
|
||||
if (fontOrFamily === "boldsymbol") {
|
||||
const fontData = boldsymbol(text, mode, options, classes, type);
|
||||
fontName = fontData.fontName;
|
||||
fontClasses = [fontData.fontClass];
|
||||
} else if (isFont) {
|
||||
fontName = fontMap[fontOrFamily].fontName;
|
||||
fontClasses = [fontOrFamily];
|
||||
} else {
|
||||
fontName = retrieveTextFontName(fontOrFamily, options.fontWeight,
|
||||
options.fontShape);
|
||||
fontClasses = [fontOrFamily, options.fontWeight, options.fontShape];
|
||||
}
|
||||
|
||||
if (lookupSymbol(text, fontName, mode).metrics) {
|
||||
return makeSymbol(text, fontName, mode, options,
|
||||
classes.concat(fontClasses));
|
||||
} else if (ligatures.hasOwnProperty(text) &&
|
||||
fontName.slice(0, 10) === "Typewriter") {
|
||||
// Deconstruct ligatures in monospace fonts (\texttt, \tt).
|
||||
const parts = [];
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
parts.push(makeSymbol(text[i], fontName, mode, options,
|
||||
classes.concat(fontClasses)));
|
||||
}
|
||||
return makeFragment(parts);
|
||||
}
|
||||
}
|
||||
|
||||
// Makes a symbol in the default font for mathords and textords.
|
||||
if (type === "mathord") {
|
||||
return makeSymbol(text, "Math-Italic", mode, options,
|
||||
classes.concat(["mathnormal"]));
|
||||
} else if (type === "textord") {
|
||||
const font = symbols[mode][text] && symbols[mode][text].font;
|
||||
if (font === "ams") {
|
||||
const fontName = retrieveTextFontName("amsrm", options.fontWeight,
|
||||
options.fontShape);
|
||||
return makeSymbol(
|
||||
text, fontName, mode, options,
|
||||
classes.concat("amsrm", options.fontWeight, options.fontShape));
|
||||
} else if (font === "main" || !font) {
|
||||
const fontName = retrieveTextFontName("textrm", options.fontWeight,
|
||||
options.fontShape);
|
||||
return makeSymbol(
|
||||
text, fontName, mode, options,
|
||||
classes.concat(options.fontWeight, options.fontShape));
|
||||
} else { // fonts added by plugins
|
||||
const fontName = retrieveTextFontName(font, options.fontWeight,
|
||||
options.fontShape);
|
||||
// We add font name as a css class
|
||||
return makeSymbol(
|
||||
text, fontName, mode, options,
|
||||
classes.concat(fontName, options.fontWeight, options.fontShape));
|
||||
}
|
||||
} else {
|
||||
throw new Error("unexpected type: " + type + " in makeOrd");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if subsequent symbolNodes have the same classes, skew, maxFont,
|
||||
* and styles. For mathnormal text, the left node must also have zero italic
|
||||
* correction so we don't lose spacing between combined glyphs.
|
||||
*/
|
||||
const canCombine = (prev: SymbolNode, next: SymbolNode) => {
|
||||
if (createClass(prev.classes) !== createClass(next.classes)
|
||||
|| prev.skew !== next.skew
|
||||
|| prev.maxFontSize !== next.maxFontSize
|
||||
|| (prev.italic !== 0 && prev.hasClass("mathnormal"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If prev and next both are just "mbin"s or "mord"s we don't combine them
|
||||
// so that the proper spacing can be preserved.
|
||||
if (prev.classes.length === 1) {
|
||||
const cls = prev.classes[0];
|
||||
if (cls === "mbin" || cls === "mord") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(prev.style) as Array<keyof CssStyle>) {
|
||||
if (prev.style[key] !== next.style[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(next.style) as Array<keyof CssStyle>) {
|
||||
if (prev.style[key] !== next.style[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Combine consecutive domTree.symbolNodes into a single symbolNode.
|
||||
* Note: this function mutates the argument.
|
||||
*/
|
||||
export const tryCombineChars = (chars: HtmlDomNode[]): HtmlDomNode[] => {
|
||||
for (let i = 0; i < chars.length - 1; i++) {
|
||||
const prev = chars[i];
|
||||
const next = chars[i + 1];
|
||||
if (prev instanceof SymbolNode
|
||||
&& next instanceof SymbolNode
|
||||
&& canCombine(prev, next)) {
|
||||
|
||||
prev.text += next.text;
|
||||
prev.height = Math.max(prev.height, next.height);
|
||||
prev.depth = Math.max(prev.depth, next.depth);
|
||||
// Use the last character's italic correction since we use
|
||||
// it to add padding to the right of the span created from
|
||||
// the combined characters.
|
||||
prev.italic = next.italic;
|
||||
chars.splice(i + 1, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return chars;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the height, depth, and maxFontSize of an element based on its
|
||||
* children.
|
||||
*/
|
||||
const sizeElementFromChildren = function(
|
||||
elem: DomSpan | Anchor | HtmlDocumentFragment,
|
||||
) {
|
||||
let height = 0;
|
||||
let depth = 0;
|
||||
let maxFontSize = 0;
|
||||
|
||||
for (let i = 0; i < elem.children.length; i++) {
|
||||
const child = elem.children[i];
|
||||
if (child.height > height) {
|
||||
height = child.height;
|
||||
}
|
||||
if (child.depth > depth) {
|
||||
depth = child.depth;
|
||||
}
|
||||
if (child.maxFontSize > maxFontSize) {
|
||||
maxFontSize = child.maxFontSize;
|
||||
}
|
||||
}
|
||||
|
||||
elem.height = height;
|
||||
elem.depth = depth;
|
||||
elem.maxFontSize = maxFontSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a span with the given list of classes, list of children, and options.
|
||||
*
|
||||
* TODO(#953): Ensure that `options` is always provided (currently some call
|
||||
* sites don't pass it) and make the type below mandatory.
|
||||
* TODO: add a separate argument for math class (e.g. `mop`, `mbin`), which
|
||||
* should if present come first in `classes`.
|
||||
*/
|
||||
export const makeSpan = function(
|
||||
classes?: string[],
|
||||
children?: HtmlDomNode[],
|
||||
options?: Options,
|
||||
style?: CssStyle,
|
||||
): DomSpan {
|
||||
const span = new Span(classes, children, options, style);
|
||||
|
||||
sizeElementFromChildren(span);
|
||||
|
||||
return span;
|
||||
};
|
||||
|
||||
// SVG one is simpler -- doesn't require height, depth, max-font setting.
|
||||
// This is also a separate method for typesafety.
|
||||
export const makeSvgSpan = (
|
||||
classes?: string[],
|
||||
children?: SvgNode[],
|
||||
options?: Options,
|
||||
style?: CssStyle,
|
||||
): SvgSpan => new Span(classes, children, options, style);
|
||||
|
||||
export const makeLineSpan = function(
|
||||
className: string,
|
||||
options: Options,
|
||||
thickness?: number,
|
||||
): DomSpan {
|
||||
const line = makeSpan([className], [], options);
|
||||
line.height = Math.max(
|
||||
thickness || options.fontMetrics().defaultRuleThickness,
|
||||
options.minRuleThickness,
|
||||
);
|
||||
line.style.borderBottomWidth = makeEm(line.height);
|
||||
line.maxFontSize = 1.0;
|
||||
return line;
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes an anchor with the given href, list of classes, list of children,
|
||||
* and options.
|
||||
*/
|
||||
export const makeAnchor = function(
|
||||
href: string,
|
||||
classes: string[],
|
||||
children: HtmlDomNode[],
|
||||
options: Options,
|
||||
): Anchor {
|
||||
const anchor = new Anchor(href, classes, children, options);
|
||||
|
||||
sizeElementFromChildren(anchor);
|
||||
|
||||
return anchor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a document fragment with the given list of children.
|
||||
*/
|
||||
export const makeFragment = function(
|
||||
children: HtmlDomNode[],
|
||||
): HtmlDocumentFragment {
|
||||
const fragment = new DocumentFragment(children);
|
||||
|
||||
sizeElementFromChildren(fragment);
|
||||
|
||||
return fragment;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wraps group in a span if it's a document fragment, allowing to apply classes
|
||||
* and styles
|
||||
*/
|
||||
export const wrapFragment = function(
|
||||
group: HtmlDomNode,
|
||||
options: Options,
|
||||
): HtmlDomNode {
|
||||
if (group instanceof DocumentFragment) {
|
||||
return makeSpan([], [group], options);
|
||||
}
|
||||
return group;
|
||||
};
|
||||
|
||||
export type VListElem = {
|
||||
type: "elem";
|
||||
elem: HtmlDomNode;
|
||||
marginLeft?: string | null | undefined;
|
||||
marginRight?: string;
|
||||
wrapperClasses?: string[];
|
||||
wrapperStyle?: CssStyle;
|
||||
};
|
||||
type VListElemAndShift = {
|
||||
type: "elem";
|
||||
elem: HtmlDomNode;
|
||||
shift: number;
|
||||
marginLeft?: string | null | undefined;
|
||||
marginRight?: string;
|
||||
wrapperClasses?: string[];
|
||||
wrapperStyle?: CssStyle;
|
||||
};
|
||||
type VListKern = {
|
||||
type: "kern";
|
||||
size: number;
|
||||
};
|
||||
|
||||
// A list of child or kern nodes to be stacked on top of each other (i.e. the
|
||||
// first element will be at the bottom, and the last at the top).
|
||||
type VListChild = VListElem | VListKern;
|
||||
type VListParam = {
|
||||
// Each child contains how much it should be shifted downward.
|
||||
positionType: "individualShift";
|
||||
children: VListElemAndShift[];
|
||||
} | {
|
||||
// "top": The positionData specifies the topmost point of the vlist (note this
|
||||
// is expected to be a height, so positive values move up).
|
||||
// "bottom": The positionData specifies the bottommost point of the vlist (note
|
||||
// this is expected to be a depth, so positive values move down).
|
||||
// "shift": The vlist will be positioned such that its baseline is positionData
|
||||
// away from the baseline of the first child which MUST be an
|
||||
// "elem". Positive values move downwards.
|
||||
positionType: "top" | "bottom" | "shift";
|
||||
positionData: number;
|
||||
children: VListChild[];
|
||||
} | {
|
||||
// The vlist is positioned so that its baseline is aligned with the baseline
|
||||
// of the first child which MUST be an "elem". This is equivalent to "shift"
|
||||
// with positionData=0.
|
||||
positionType: "firstBaseline";
|
||||
children: VListChild[];
|
||||
};
|
||||
|
||||
// Computes the updated `children` list and the overall depth.
|
||||
//
|
||||
// This helper function for makeVList makes it easier to enforce type safety by
|
||||
// allowing early exits (returns) in the logic.
|
||||
const getVListChildrenAndDepth = function(params: VListParam): {
|
||||
children: (VListChild | VListElemAndShift)[] | VListChild[];
|
||||
depth: number;
|
||||
} {
|
||||
if (params.positionType === "individualShift") {
|
||||
const oldChildren = params.children;
|
||||
const children: (VListChild | VListElemAndShift)[] = [oldChildren[0]];
|
||||
|
||||
// Add in kerns to the list of params.children to get each element to be
|
||||
// shifted to the correct specified shift
|
||||
const depth = -oldChildren[0].shift - oldChildren[0].elem.depth;
|
||||
let currPos = depth;
|
||||
for (let i = 1; i < oldChildren.length; i++) {
|
||||
const diff = -oldChildren[i].shift - currPos -
|
||||
oldChildren[i].elem.depth;
|
||||
const size = diff -
|
||||
(oldChildren[i - 1].elem.height +
|
||||
oldChildren[i - 1].elem.depth);
|
||||
|
||||
currPos = currPos + diff;
|
||||
children.push({type: "kern", size});
|
||||
children.push(oldChildren[i]);
|
||||
}
|
||||
|
||||
return {children, depth};
|
||||
}
|
||||
|
||||
let depth;
|
||||
if (params.positionType === "top") {
|
||||
// We always start at the bottom, so calculate the bottom by adding up
|
||||
// all the sizes
|
||||
let bottom = params.positionData;
|
||||
for (let i = 0; i < params.children.length; i++) {
|
||||
const child = params.children[i];
|
||||
bottom -= child.type === "kern"
|
||||
? child.size
|
||||
: child.elem.height + child.elem.depth;
|
||||
}
|
||||
depth = bottom;
|
||||
} else if (params.positionType === "bottom") {
|
||||
depth = -params.positionData;
|
||||
} else {
|
||||
const firstChild = params.children[0];
|
||||
if (firstChild.type !== "elem") {
|
||||
throw new Error('First child must have type "elem".');
|
||||
}
|
||||
if (params.positionType === "shift") {
|
||||
depth = -firstChild.elem.depth - params.positionData;
|
||||
} else if (params.positionType === "firstBaseline") {
|
||||
depth = -firstChild.elem.depth;
|
||||
} else {
|
||||
throw new Error(`Invalid positionType ${params.positionType}.`);
|
||||
}
|
||||
}
|
||||
|
||||
return {children: params.children, depth};
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a vertical list by stacking elements and kerns on top of each other.
|
||||
* Allows for many different ways of specifying the positioning method.
|
||||
*
|
||||
* See VListParam documentation above.
|
||||
*/
|
||||
export const makeVList = function(params: VListParam, options: Options): DomSpan {
|
||||
const {children, depth} = getVListChildrenAndDepth(params);
|
||||
|
||||
// Create a strut that is taller than any list item. The strut is added to
|
||||
// each item, where it will determine the item's baseline. Since it has
|
||||
// `overflow:hidden`, the strut's top edge will sit on the item's line box's
|
||||
// top edge and the strut's bottom edge will sit on the item's baseline,
|
||||
// with no additional line-height spacing. This allows the item baseline to
|
||||
// be positioned precisely without worrying about font ascent and
|
||||
// line-height.
|
||||
let pstrutSize = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
if (child.type === "elem") {
|
||||
const elem = child.elem;
|
||||
pstrutSize = Math.max(pstrutSize, elem.maxFontSize, elem.height);
|
||||
}
|
||||
}
|
||||
pstrutSize += 2;
|
||||
const pstrut = makeSpan(["pstrut"], []);
|
||||
pstrut.style.height = makeEm(pstrutSize);
|
||||
|
||||
// Create a new list of actual children at the correct offsets
|
||||
const realChildren = [];
|
||||
let minPos = depth;
|
||||
let maxPos = depth;
|
||||
let currPos = depth;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
if (child.type === "kern") {
|
||||
currPos += child.size;
|
||||
} else {
|
||||
const elem = child.elem;
|
||||
const classes = child.wrapperClasses || [];
|
||||
const style = child.wrapperStyle || {};
|
||||
|
||||
const childWrap = makeSpan(classes, [pstrut, elem], undefined, style);
|
||||
childWrap.style.top = makeEm(-pstrutSize - currPos - elem.depth);
|
||||
if (child.marginLeft) {
|
||||
childWrap.style.marginLeft = child.marginLeft;
|
||||
}
|
||||
if (child.marginRight) {
|
||||
childWrap.style.marginRight = child.marginRight;
|
||||
}
|
||||
|
||||
realChildren.push(childWrap);
|
||||
currPos += elem.height + elem.depth;
|
||||
}
|
||||
minPos = Math.min(minPos, currPos);
|
||||
maxPos = Math.max(maxPos, currPos);
|
||||
}
|
||||
|
||||
// The vlist contents go in a table-cell with `vertical-align:bottom`.
|
||||
// This cell's bottom edge will determine the containing table's baseline
|
||||
// without overly expanding the containing line-box.
|
||||
const vlist = makeSpan(["vlist"], realChildren);
|
||||
vlist.style.height = makeEm(maxPos);
|
||||
|
||||
// A second row is used if necessary to represent the vlist's depth.
|
||||
let rows;
|
||||
if (minPos < 0) {
|
||||
// We will define depth in an empty span with display: table-cell.
|
||||
// It should render with the height that we define. But Chrome, in
|
||||
// contenteditable mode only, treats that span as if it contains some
|
||||
// text content. And that min-height over-rides our desired height.
|
||||
// So we put another empty span inside the depth strut span.
|
||||
const emptySpan = makeSpan([], []);
|
||||
const depthStrut = makeSpan(["vlist"], [emptySpan]);
|
||||
depthStrut.style.height = makeEm(-minPos);
|
||||
|
||||
// Safari wants the first row to have inline content; otherwise it
|
||||
// puts the bottom of the *second* row on the baseline.
|
||||
const topStrut = makeSpan(["vlist-s"], [new SymbolNode("\u200b")]);
|
||||
|
||||
rows = [makeSpan(["vlist-r"], [vlist, topStrut]),
|
||||
makeSpan(["vlist-r"], [depthStrut])];
|
||||
} else {
|
||||
rows = [makeSpan(["vlist-r"], [vlist])];
|
||||
}
|
||||
|
||||
const vtable = makeSpan(["vlist-t"], rows);
|
||||
if (rows.length === 2) {
|
||||
vtable.classes.push("vlist-t2");
|
||||
}
|
||||
vtable.height = maxPos;
|
||||
vtable.depth = -minPos;
|
||||
return vtable;
|
||||
};
|
||||
|
||||
// Glue is a concept from TeX which is a flexible space between elements in
|
||||
// either a vertical or horizontal list. In KaTeX, at least for now, it's
|
||||
// static space between elements in a horizontal layout.
|
||||
export const makeGlue = (measurement: Measurement, options: Options): DomSpan => {
|
||||
// Make an empty span for the space
|
||||
const rule = makeSpan(["mspace"], [], options);
|
||||
const size = calculateSize(measurement, options);
|
||||
rule.style.marginRight = makeEm(size);
|
||||
return rule;
|
||||
};
|
||||
|
||||
// Takes font options, and returns the appropriate fontLookup name
|
||||
const retrieveTextFontName = function(
|
||||
fontFamily: string,
|
||||
fontWeight: string,
|
||||
fontShape: string,
|
||||
): string {
|
||||
let baseFontName = "";
|
||||
switch (fontFamily) {
|
||||
case "amsrm":
|
||||
baseFontName = "AMS";
|
||||
break;
|
||||
case "textrm":
|
||||
baseFontName = "Main";
|
||||
break;
|
||||
case "textsf":
|
||||
baseFontName = "SansSerif";
|
||||
break;
|
||||
case "texttt":
|
||||
baseFontName = "Typewriter";
|
||||
break;
|
||||
default:
|
||||
baseFontName = fontFamily; // use fonts added by a plugin
|
||||
}
|
||||
|
||||
let fontStylesName;
|
||||
if (fontWeight === "textbf" && fontShape === "textit") {
|
||||
fontStylesName = "BoldItalic";
|
||||
} else if (fontWeight === "textbf") {
|
||||
fontStylesName = "Bold";
|
||||
} else if (fontWeight === "textit") {
|
||||
fontStylesName = "Italic";
|
||||
} else {
|
||||
fontStylesName = "Regular";
|
||||
}
|
||||
|
||||
return `${baseFontName}-${fontStylesName}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps TeX font commands to objects containing:
|
||||
* - variant: string used for "mathvariant" attribute in buildMathML.js
|
||||
* - fontName: the "style" parameter to fontMetrics.getCharacterMetrics
|
||||
*/
|
||||
// A map between tex font commands an MathML mathvariant attribute values
|
||||
export const fontMap: Record<string, {
|
||||
variant: FontVariant;
|
||||
fontName: string;
|
||||
}> = {
|
||||
// styles
|
||||
"mathbf": {
|
||||
variant: "bold",
|
||||
fontName: "Main-Bold",
|
||||
},
|
||||
"mathrm": {
|
||||
variant: "normal",
|
||||
fontName: "Main-Regular",
|
||||
},
|
||||
"textit": {
|
||||
variant: "italic",
|
||||
fontName: "Main-Italic",
|
||||
},
|
||||
"mathit": {
|
||||
variant: "italic",
|
||||
fontName: "Main-Italic",
|
||||
},
|
||||
"mathnormal": {
|
||||
variant: "italic",
|
||||
fontName: "Math-Italic",
|
||||
},
|
||||
"mathsfit": {
|
||||
variant: "sans-serif-italic",
|
||||
fontName: "SansSerif-Italic",
|
||||
},
|
||||
// "boldsymbol" is missing because they require the use of multiple fonts:
|
||||
// Math-BoldItalic and Main-Bold. This is handled by a special case in
|
||||
// makeOrd which ends up calling boldsymbol.
|
||||
|
||||
// families
|
||||
"mathbb": {
|
||||
variant: "double-struck",
|
||||
fontName: "AMS-Regular",
|
||||
},
|
||||
"mathcal": {
|
||||
variant: "script",
|
||||
fontName: "Caligraphic-Regular",
|
||||
},
|
||||
"mathfrak": {
|
||||
variant: "fraktur",
|
||||
fontName: "Fraktur-Regular",
|
||||
},
|
||||
"mathscr": {
|
||||
variant: "script",
|
||||
fontName: "Script-Regular",
|
||||
},
|
||||
"mathsf": {
|
||||
variant: "sans-serif",
|
||||
fontName: "SansSerif-Regular",
|
||||
},
|
||||
"mathtt": {
|
||||
variant: "monospace",
|
||||
fontName: "Typewriter-Regular",
|
||||
},
|
||||
};
|
||||
|
||||
export const svgData: Record<string, [string, number, number]> = {
|
||||
// path, width, height
|
||||
vec: ["vec", 0.471, 0.714], // values from the font glyph
|
||||
oiintSize1: ["oiintSize1", 0.957, 0.499], // oval to overlay the integrand
|
||||
oiintSize2: ["oiintSize2", 1.472, 0.659],
|
||||
oiiintSize1: ["oiiintSize1", 1.304, 0.499],
|
||||
oiiintSize2: ["oiiintSize2", 1.98, 0.659],
|
||||
};
|
||||
|
||||
export const staticSvg = function(value: string, options: Options): SvgSpan {
|
||||
// Create a span with inline SVG for the element.
|
||||
const [pathName, width, height] = svgData[value];
|
||||
const path = new PathNode(pathName);
|
||||
const svgNode = new SvgNode([path], {
|
||||
"width": makeEm(width),
|
||||
"height": makeEm(height),
|
||||
// Override CSS rule `.katex svg { width: 100% }`
|
||||
"style": "width:" + makeEm(width),
|
||||
"viewBox": "0 0 " + 1000 * width + " " + 1000 * height,
|
||||
"preserveAspectRatio": "xMinYMin",
|
||||
});
|
||||
const span = makeSvgSpan(["overlay"], [svgNode], options);
|
||||
span.height = height;
|
||||
span.style.height = makeEm(height);
|
||||
span.style.width = makeEm(width);
|
||||
return span;
|
||||
};
|
||||
124
frontend/node_modules/katex/src/defineMacro.ts
generated
vendored
Normal file
124
frontend/node_modules/katex/src/defineMacro.ts
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
import {Token} from "./Token";
|
||||
import type Namespace from "./Namespace";
|
||||
import type {Mode} from "./types";
|
||||
|
||||
/**
|
||||
* Provides context to macros defined by functions. Implemented by
|
||||
* MacroExpander.
|
||||
*/
|
||||
export interface MacroContextInterface {
|
||||
mode: Mode;
|
||||
|
||||
/**
|
||||
* Object mapping macros to their expansions.
|
||||
*/
|
||||
macros: Namespace<MacroDefinition>;
|
||||
|
||||
/**
|
||||
* Returns the topmost token on the stack, without expanding it.
|
||||
* Similar in behavior to TeX's `\futurelet`.
|
||||
*/
|
||||
future(): Token;
|
||||
|
||||
/**
|
||||
* Remove and return the next unexpanded token.
|
||||
*/
|
||||
popToken(): Token;
|
||||
|
||||
/**
|
||||
* Consume all following space tokens, without expansion.
|
||||
*/
|
||||
consumeSpaces(): void;
|
||||
|
||||
/**
|
||||
* Expand the next token only once if possible.
|
||||
*/
|
||||
expandOnce(expandableOnly?: boolean): number | boolean;
|
||||
|
||||
/**
|
||||
* Expand the next token only once (if possible), and return the resulting
|
||||
* top token on the stack (without removing anything from the stack).
|
||||
* Similar in behavior to TeX's `\expandafter\futurelet`.
|
||||
*/
|
||||
expandAfterFuture(): Token;
|
||||
|
||||
/**
|
||||
* Recursively expand first token, then return first non-expandable token.
|
||||
*/
|
||||
expandNextToken(): Token;
|
||||
|
||||
/**
|
||||
* Fully expand the given macro name and return the resulting list of
|
||||
* tokens, or return `undefined` if no such macro is defined.
|
||||
*/
|
||||
expandMacro(name: string): Token[] | undefined;
|
||||
|
||||
/**
|
||||
* Fully expand the given macro name and return the result as a string,
|
||||
* or return `undefined` if no such macro is defined.
|
||||
*/
|
||||
expandMacroAsText(name: string): string | undefined;
|
||||
|
||||
/**
|
||||
* Fully expand the given token stream and return the resulting list of
|
||||
* tokens. Note that the input tokens are in reverse order, but the
|
||||
* output tokens are in forward order.
|
||||
*/
|
||||
expandTokens(tokens: Token[]): Token[];
|
||||
|
||||
/**
|
||||
* Consume an argument from the token stream, and return the resulting array
|
||||
* of tokens and start/end token.
|
||||
*/
|
||||
consumeArg(delims?: string[] | null | undefined): MacroArg;
|
||||
|
||||
/**
|
||||
* Consume the specified number of arguments from the token stream,
|
||||
* and return the resulting array of arguments.
|
||||
*/
|
||||
consumeArgs(numArgs: number): Token[][];
|
||||
|
||||
/**
|
||||
* Determine whether a command is currently "defined" (has some
|
||||
* functionality), meaning that it's a macro (in the current group),
|
||||
* a function, a symbol, or one of the special commands listed in
|
||||
* `implicitCommands`.
|
||||
*/
|
||||
isDefined(name: string): boolean;
|
||||
|
||||
/**
|
||||
* Determine whether a command is expandable.
|
||||
*/
|
||||
isExpandable(name: string): boolean;
|
||||
}
|
||||
|
||||
export type MacroArg = {
|
||||
tokens: Token[];
|
||||
start: Token;
|
||||
end: Token;
|
||||
};
|
||||
|
||||
/** Macro tokens (in reverse order). */
|
||||
export type MacroExpansion = {
|
||||
tokens: Token[];
|
||||
numArgs: number;
|
||||
delimiters?: string[][];
|
||||
unexpandable?: boolean; // used in \let
|
||||
};
|
||||
|
||||
export type MacroDefinition = string | MacroExpansion |
|
||||
((arg0: MacroContextInterface) => string | MacroExpansion);
|
||||
export type MacroMap = Record<string, MacroDefinition>;
|
||||
|
||||
/**
|
||||
* All registered global/built-in macros.
|
||||
* `macros.js` exports this same dictionary again and makes it public.
|
||||
* `Parser.js` requires this dictionary via `macros.js`.
|
||||
*/
|
||||
export const _macros: MacroMap = {};
|
||||
|
||||
// This function might one day accept an additional argument and do more things.
|
||||
export default function defineMacro(name: string, body: MacroDefinition) {
|
||||
_macros[name] = body;
|
||||
}
|
||||
280
frontend/node_modules/katex/src/fontMetrics.ts
generated
vendored
Normal file
280
frontend/node_modules/katex/src/fontMetrics.ts
generated
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
import {supportedCodepoint} from "./unicodeScripts";
|
||||
|
||||
import type {Mode} from "./types";
|
||||
|
||||
/**
|
||||
* This file contains metrics regarding fonts and individual symbols. The sigma
|
||||
* and xi variables, as well as the metricMap map contain data extracted from
|
||||
* TeX, TeX font metrics, and the TTF files. These data are then exposed via the
|
||||
* `metrics` variable and the getCharacterMetrics function.
|
||||
*/
|
||||
|
||||
// In TeX, there are actually three sets of dimensions, one for each of
|
||||
// textstyle (size index 5 and higher: >=9pt), scriptstyle (size index 3 and 4:
|
||||
// 7-8pt), and scriptscriptstyle (size index 1 and 2: 5-6pt). These are
|
||||
// provided in the arrays below, in that order.
|
||||
//
|
||||
// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respectively.
|
||||
// This was determined by running the following script:
|
||||
//
|
||||
// latex -interaction=nonstopmode \
|
||||
// '\documentclass{article}\usepackage{amsmath}\begin{document}' \
|
||||
// '$a$ \expandafter\show\the\textfont2' \
|
||||
// '\expandafter\show\the\scriptfont2' \
|
||||
// '\expandafter\show\the\scriptscriptfont2' \
|
||||
// '\stop'
|
||||
//
|
||||
// The metrics themselves were retrieved using the following commands:
|
||||
//
|
||||
// tftopl cmsy10
|
||||
// tftopl cmsy7
|
||||
// tftopl cmsy5
|
||||
//
|
||||
// The output of each of these commands is quite lengthy. The only part we
|
||||
// care about is the FONTDIMEN section. Each value is measured in EMs.
|
||||
const sigmasAndXis: Record<string, [number, number, number]> = {
|
||||
slant: [0.250, 0.250, 0.250], // sigma1
|
||||
space: [0.000, 0.000, 0.000], // sigma2
|
||||
stretch: [0.000, 0.000, 0.000], // sigma3
|
||||
shrink: [0.000, 0.000, 0.000], // sigma4
|
||||
xHeight: [0.431, 0.431, 0.431], // sigma5
|
||||
quad: [1.000, 1.171, 1.472], // sigma6
|
||||
extraSpace: [0.000, 0.000, 0.000], // sigma7
|
||||
num1: [0.677, 0.732, 0.925], // sigma8
|
||||
num2: [0.394, 0.384, 0.387], // sigma9
|
||||
num3: [0.444, 0.471, 0.504], // sigma10
|
||||
denom1: [0.686, 0.752, 1.025], // sigma11
|
||||
denom2: [0.345, 0.344, 0.532], // sigma12
|
||||
sup1: [0.413, 0.503, 0.504], // sigma13
|
||||
sup2: [0.363, 0.431, 0.404], // sigma14
|
||||
sup3: [0.289, 0.286, 0.294], // sigma15
|
||||
sub1: [0.150, 0.143, 0.200], // sigma16
|
||||
sub2: [0.247, 0.286, 0.400], // sigma17
|
||||
supDrop: [0.386, 0.353, 0.494], // sigma18
|
||||
subDrop: [0.050, 0.071, 0.100], // sigma19
|
||||
delim1: [2.390, 1.700, 1.980], // sigma20
|
||||
delim2: [1.010, 1.157, 1.420], // sigma21
|
||||
axisHeight: [0.250, 0.250, 0.250], // sigma22
|
||||
|
||||
// These font metrics are extracted from TeX by using tftopl on cmex10.tfm;
|
||||
// they correspond to the font parameters of the extension fonts (family 3).
|
||||
// See the TeXbook, page 441. In AMSTeX, the extension fonts scale; to
|
||||
// match cmex7, we'd use cmex7.tfm values for script and scriptscript
|
||||
// values.
|
||||
defaultRuleThickness: [0.04, 0.049, 0.049], // xi8; cmex7: 0.049
|
||||
bigOpSpacing1: [0.111, 0.111, 0.111], // xi9
|
||||
bigOpSpacing2: [0.166, 0.166, 0.166], // xi10
|
||||
bigOpSpacing3: [0.2, 0.2, 0.2], // xi11
|
||||
bigOpSpacing4: [0.6, 0.611, 0.611], // xi12; cmex7: 0.611
|
||||
bigOpSpacing5: [0.1, 0.143, 0.143], // xi13; cmex7: 0.143
|
||||
|
||||
// The \sqrt rule width is taken from the height of the surd character.
|
||||
// Since we use the same font at all sizes, this thickness doesn't scale.
|
||||
sqrtRuleThickness: [0.04, 0.04, 0.04],
|
||||
|
||||
// This value determines how large a pt is, for metrics which are defined
|
||||
// in terms of pts.
|
||||
// This value is also used in katex.scss; if you change it make sure the
|
||||
// values match.
|
||||
ptPerEm: [10.0, 10.0, 10.0],
|
||||
|
||||
// The space between adjacent `|` columns in an array definition. From
|
||||
// `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm.
|
||||
doubleRuleSep: [0.2, 0.2, 0.2],
|
||||
|
||||
// The width of separator lines in {array} environments. From
|
||||
// `\showthe\arrayrulewidth` in LaTeX. Equals 0.4 / ptPerEm.
|
||||
arrayRuleWidth: [0.04, 0.04, 0.04],
|
||||
|
||||
// Two values from LaTeX source2e:
|
||||
fboxsep: [0.3, 0.3, 0.3], // 3 pt / ptPerEm
|
||||
fboxrule: [0.04, 0.04, 0.04], // 0.4 pt / ptPerEm
|
||||
};
|
||||
|
||||
// This map contains a mapping from font name and character code to character
|
||||
// metrics, including height, depth, italic correction, and skew (kern from the
|
||||
// character to the corresponding \skewchar)
|
||||
// This map is generated via `make metrics`. It should not be changed manually.
|
||||
import metricMap from "./fontMetricsData";
|
||||
|
||||
// These are very rough approximations. We default to Times New Roman which
|
||||
// should have Latin-1 and Cyrillic characters, but may not depending on the
|
||||
// operating system. The metrics do not account for extra height from the
|
||||
// accents. In the case of Cyrillic characters which have both ascenders and
|
||||
// descenders we prefer approximations with ascenders, primarily to prevent
|
||||
// the fraction bar or root line from intersecting the glyph.
|
||||
// TODO(kevinb) allow union of multiple glyph metrics for better accuracy.
|
||||
const extraCharacterMap: Record<string, string> = {
|
||||
// Latin-1
|
||||
'Å': 'A',
|
||||
'Ð': 'D',
|
||||
'Þ': 'o',
|
||||
'å': 'a',
|
||||
'ð': 'd',
|
||||
'þ': 'o',
|
||||
|
||||
// Cyrillic
|
||||
'А': 'A',
|
||||
'Б': 'B',
|
||||
'В': 'B',
|
||||
'Г': 'F',
|
||||
'Д': 'A',
|
||||
'Е': 'E',
|
||||
'Ж': 'K',
|
||||
'З': '3',
|
||||
'И': 'N',
|
||||
'Й': 'N',
|
||||
'К': 'K',
|
||||
'Л': 'N',
|
||||
'М': 'M',
|
||||
'Н': 'H',
|
||||
'О': 'O',
|
||||
'П': 'N',
|
||||
'Р': 'P',
|
||||
'С': 'C',
|
||||
'Т': 'T',
|
||||
'У': 'y',
|
||||
'Ф': 'O',
|
||||
'Х': 'X',
|
||||
'Ц': 'U',
|
||||
'Ч': 'h',
|
||||
'Ш': 'W',
|
||||
'Щ': 'W',
|
||||
'Ъ': 'B',
|
||||
'Ы': 'X',
|
||||
'Ь': 'B',
|
||||
'Э': '3',
|
||||
'Ю': 'X',
|
||||
'Я': 'R',
|
||||
'а': 'a',
|
||||
'б': 'b',
|
||||
'в': 'a',
|
||||
'г': 'r',
|
||||
'д': 'y',
|
||||
'е': 'e',
|
||||
'ж': 'm',
|
||||
'з': 'e',
|
||||
'и': 'n',
|
||||
'й': 'n',
|
||||
'к': 'n',
|
||||
'л': 'n',
|
||||
'м': 'm',
|
||||
'н': 'n',
|
||||
'о': 'o',
|
||||
'п': 'n',
|
||||
'р': 'p',
|
||||
'с': 'c',
|
||||
'т': 'o',
|
||||
'у': 'y',
|
||||
'ф': 'b',
|
||||
'х': 'x',
|
||||
'ц': 'n',
|
||||
'ч': 'n',
|
||||
'ш': 'w',
|
||||
'щ': 'w',
|
||||
'ъ': 'a',
|
||||
'ы': 'm',
|
||||
'ь': 'a',
|
||||
'э': 'e',
|
||||
'ю': 'm',
|
||||
'я': 'r',
|
||||
};
|
||||
|
||||
export type CharacterMetrics = {
|
||||
depth: number;
|
||||
height: number;
|
||||
italic: number;
|
||||
skew: number;
|
||||
width: number;
|
||||
};
|
||||
|
||||
export type MetricMap = {
|
||||
[key: string]: [number, number, number, number, number];
|
||||
};
|
||||
|
||||
/**
|
||||
* This function adds new font metrics to default metricMap
|
||||
* It can also override existing metrics
|
||||
*/
|
||||
export function setFontMetrics(fontName: string, metrics: MetricMap) {
|
||||
metricMap[fontName] = metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is a convenience function for looking up information in the
|
||||
* metricMap table. It takes a character as a string, and a font.
|
||||
*
|
||||
* Note: the `width` property may be undefined if fontMetricsData.js wasn't
|
||||
* built using `Make extended_metrics`.
|
||||
*/
|
||||
export function getCharacterMetrics(
|
||||
character: string,
|
||||
font: string,
|
||||
mode: Mode,
|
||||
): CharacterMetrics | null | undefined {
|
||||
if (!metricMap[font]) {
|
||||
throw new Error(`Font metrics not found for font: ${font}.`);
|
||||
}
|
||||
let ch = character.charCodeAt(0);
|
||||
let metrics = metricMap[font][ch];
|
||||
if (!metrics && character[0] in extraCharacterMap) {
|
||||
ch = extraCharacterMap[character[0]].charCodeAt(0);
|
||||
metrics = metricMap[font][ch];
|
||||
}
|
||||
|
||||
if (!metrics && mode === 'text') {
|
||||
// We don't typically have font metrics for Asian scripts.
|
||||
// But since we support them in text mode, we need to return
|
||||
// some sort of metrics.
|
||||
// So if the character is in a script we support but we
|
||||
// don't have metrics for it, just use the metrics for
|
||||
// the Latin capital letter M. This is close enough because
|
||||
// we (currently) only care about the height of the glyph
|
||||
// not its width.
|
||||
if (supportedCodepoint(ch)) {
|
||||
metrics = metricMap[font][77]; // 77 is the charcode for 'M'
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics) {
|
||||
return {
|
||||
depth: metrics[0],
|
||||
height: metrics[1],
|
||||
italic: metrics[2],
|
||||
skew: metrics[3],
|
||||
width: metrics[4],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
type FontSizeIndex = 0 | 1 | 2;
|
||||
export type FontMetrics = {
|
||||
cssEmPerMu: number;
|
||||
[key: string]: number;
|
||||
};
|
||||
const fontMetricsBySizeIndex: Partial<Record<FontSizeIndex, FontMetrics>> = {};
|
||||
|
||||
/**
|
||||
* Get the font metrics for a given size.
|
||||
*/
|
||||
export function getGlobalMetrics(size: number): FontMetrics {
|
||||
let sizeIndex: FontSizeIndex;
|
||||
if (size >= 5) {
|
||||
sizeIndex = 0;
|
||||
} else if (size >= 3) {
|
||||
sizeIndex = 1;
|
||||
} else {
|
||||
sizeIndex = 2;
|
||||
}
|
||||
if (!fontMetricsBySizeIndex[sizeIndex]) {
|
||||
const metrics: FontMetrics = fontMetricsBySizeIndex[sizeIndex] = {
|
||||
cssEmPerMu: sigmasAndXis.quad[sizeIndex] / 18,
|
||||
};
|
||||
for (const key in sigmasAndXis) {
|
||||
if (sigmasAndXis.hasOwnProperty(key)) {
|
||||
metrics[key] = sigmasAndXis[key][sizeIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
return fontMetricsBySizeIndex[sizeIndex]!;
|
||||
}
|
||||
2077
frontend/node_modules/katex/src/fontMetricsData.js
generated
vendored
Normal file
2077
frontend/node_modules/katex/src/fontMetricsData.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
139
frontend/node_modules/katex/src/fonts/Makefile
generated
vendored
Normal file
139
frontend/node_modules/katex/src/fonts/Makefile
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
#!gmake
|
||||
#
|
||||
# Version: Apache License 2.0
|
||||
#
|
||||
# Copyright (c) 2013 MathJax Project
|
||||
# Copyright (c) 2013 The MathJax Consortium
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
CUSTOM=custom.cfg
|
||||
|
||||
-include $(CUSTOM)
|
||||
|
||||
MFTRACE_MODIFIED=lib/mftrace-modified
|
||||
|
||||
all: config fonts
|
||||
|
||||
$(CUSTOM):
|
||||
@cp default.cfg $(CUSTOM);
|
||||
|
||||
$(CUSTOM).pl: $(CUSTOM)
|
||||
@echo "Creating Perl config file..."
|
||||
@cp $(CUSTOM) $(CUSTOM).pl
|
||||
@echo >> $(CUSTOM).pl # ensure that the config file ends by a new line
|
||||
@echo "MFTRACE_PATH=`$(WHICH) $(MFTRACE)`" >> $(CUSTOM).pl
|
||||
@$(SED) -i "s|^\([A-Z_0-9]*\)=\(.*\)|$$\1='\2';|" $(CUSTOM).pl
|
||||
@echo "1;" >> $(CUSTOM).pl
|
||||
|
||||
.PHONY: config
|
||||
config: $(CUSTOM).pl
|
||||
|
||||
blacker: $(MFTRACE_MODIFIED)
|
||||
$(MFTRACE_MODIFIED):
|
||||
$(PERL) -I. makeBlacker 15 # values between 10 and 30 seem best
|
||||
|
||||
pfa: $(MFTRACE_MODIFIED)
|
||||
@echo "cmr10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmr10
|
||||
|
||||
@echo "cmmi10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --encoding $(TETEXENCODING)/aae443f0.enc --simplify cmmi10
|
||||
|
||||
@echo "cmsy10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --encoding $(TETEXENCODING)/10037936.enc --simplify cmsy10
|
||||
|
||||
@echo "cmex10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmex10
|
||||
|
||||
@echo "cmbx10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmbx10
|
||||
|
||||
@echo "cmbxti10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmbxti10
|
||||
|
||||
@echo "cmti10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmti10
|
||||
|
||||
@echo "msam10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify --encoding $(TETEXENCODING)/10037936.enc msam10
|
||||
|
||||
@echo "msbm10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify --encoding $(TETEXENCODING)/10037936.enc msbm10
|
||||
|
||||
@echo "cmmib10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --encoding $(TETEXENCODING)/aae443f0.enc --simplify cmmib10
|
||||
|
||||
@echo "cmbsy10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --encoding $(TETEXENCODING)/10037936.enc --simplify cmbsy10
|
||||
|
||||
@echo "cmtt10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmtt10
|
||||
|
||||
@echo "cmss10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmss10
|
||||
@echo "cmssi10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmssi10
|
||||
@echo "cmssbx10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify cmssbx10
|
||||
|
||||
@echo "eufm10"
|
||||
cp "`$(KPSEWHICH) eufm10.pfb`" eufm10.pfb
|
||||
@echo "eufb10"
|
||||
cp "`$(KPSEWHICH) eufb10.pfb`" eufb10.pfb
|
||||
|
||||
# echo "eusm10"
|
||||
# $(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify eusm10
|
||||
# echo "eusb10"
|
||||
# $(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify eusb10
|
||||
|
||||
@echo "rsfs10"
|
||||
$(PYTHON) $(MFTRACE_MODIFIED) --magnification 1000 --simplify --encoding $(BASEENCODING)/tex256.enc rsfs10
|
||||
|
||||
mkdir -p pfa
|
||||
rm -f pfa/*
|
||||
mv *.pfa pfa
|
||||
mv *.pfb pfa
|
||||
|
||||
ff: pfa
|
||||
mkdir -p ff otf
|
||||
rm -f ff/* otf/*
|
||||
$(PERL) -I. makeFF
|
||||
|
||||
.PHONY: fonts
|
||||
fonts: ff
|
||||
mkdir -p ttf woff woff2
|
||||
rm -f ttf/* woff/* woff2/*
|
||||
|
||||
@for file in `ls ff/*.ff | $(SED) 's|ff/\(.*\)\.ff|\1|'`; do \
|
||||
echo ""; \
|
||||
echo $$file; \
|
||||
$(FONTFORGE) -lang=ff -script ff/$$file.ff; \
|
||||
\
|
||||
echo "Hinting $$file"; \
|
||||
if echo "$$file" | $(GREP) -q -e "Size[1-4]" -e "Typewriter"; then \
|
||||
$(TTFAUTOHINT) -f none -S --windows-compatibility --symbol ttf/$$file.ttf ttf/$$file.ttf.hinted; \
|
||||
else \
|
||||
$(TTFAUTOHINT) -f none -S --windows-compatibility ttf/$$file.ttf ttf/$$file.ttf.hinted; \
|
||||
fi; \
|
||||
mv ttf/$$file.ttf.hinted ttf/$$file.ttf; \
|
||||
\
|
||||
echo "Generating $$file..."; \
|
||||
$(PYTHON) generate_fonts.py ttf/$$file.ttf; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f $(CUSTOM).pl
|
||||
rm -f $(MFTRACE_MODIFIED) lib/blacker.mf
|
||||
rm -rf pfa ff otf ttf woff woff2
|
||||
20
frontend/node_modules/katex/src/fonts/default.cfg
generated
vendored
Normal file
20
frontend/node_modules/katex/src/fonts/default.cfg
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Note: paths should be absolute, unless they point to programs in your $PATH.
|
||||
|
||||
##### Standard programs #####
|
||||
GREP=grep
|
||||
PERL=perl
|
||||
PYTHON=python3
|
||||
SED=sed
|
||||
WHICH=which
|
||||
KPSEWHICH=kpsewhich
|
||||
|
||||
##### Font tools #####
|
||||
# Most of the tools below are standard and should be available from your package manager.
|
||||
FONTFORGE=fontforge
|
||||
MFTRACE=mftrace
|
||||
TTX=ttx
|
||||
TTFAUTOHINT=ttfautohint
|
||||
|
||||
##### TeXLive Encoding
|
||||
TETEXENCODING=/usr/share/texlive/texmf-texlive/fonts/enc/dvips/tetex/
|
||||
BASEENCODING=/usr/share/texlive/texmf-texlive/fonts/enc/dvips/base/
|
||||
234
frontend/node_modules/katex/src/fonts/lib/Space.ttx
generated
vendored
Normal file
234
frontend/node_modules/katex/src/fonts/lib/Space.ttx
generated
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="OTTO" ttLibVersion="3.28">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="space"/>
|
||||
<GlyphID id="2" name="uni00A0"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<head>
|
||||
<!-- Most of this table will be recalculated by the compiler -->
|
||||
<tableVersion value="1.0"/>
|
||||
<fontRevision value="1.0"/>
|
||||
<checkSumAdjustment value="0xa98c8795"/>
|
||||
<magicNumber value="0x5f0f3cf5"/>
|
||||
<flags value="00000000 00000011"/>
|
||||
<unitsPerEm value="1000"/>
|
||||
<created value="Sun Jan 24 23:04:46 2010"/>
|
||||
<modified value="Sat May 14 12:26:22 2011"/>
|
||||
<xMin value="50"/>
|
||||
<yMin value="0"/>
|
||||
<xMax value="200"/>
|
||||
<yMax value="533"/>
|
||||
<macStyle value="00000000 00000000"/>
|
||||
<lowestRecPPEM value="8"/>
|
||||
<fontDirectionHint value="2"/>
|
||||
<indexToLocFormat value="0"/>
|
||||
<glyphDataFormat value="0"/>
|
||||
</head>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="0x00010000"/>
|
||||
<ascent value="800"/>
|
||||
<descent value="-200"/>
|
||||
<lineGap value="90"/>
|
||||
<advanceWidthMax value="250"/>
|
||||
<minLeftSideBearing value="50"/>
|
||||
<minRightSideBearing value="50"/>
|
||||
<xMaxExtent value="200"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfHMetrics value="1"/>
|
||||
</hhea>
|
||||
|
||||
<maxp>
|
||||
<tableVersion value="0x5000"/>
|
||||
<numGlyphs value="3"/>
|
||||
</maxp>
|
||||
|
||||
<OS_2>
|
||||
<!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
|
||||
will be recalculated by the compiler -->
|
||||
<version value="2"/>
|
||||
<xAvgCharWidth value="225"/>
|
||||
<usWeightClass value="400"/>
|
||||
<usWidthClass value="5"/>
|
||||
<fsType value="00000000 00000000"/>
|
||||
<ySubscriptXSize value="650"/>
|
||||
<ySubscriptYSize value="700"/>
|
||||
<ySubscriptXOffset value="0"/>
|
||||
<ySubscriptYOffset value="140"/>
|
||||
<ySuperscriptXSize value="650"/>
|
||||
<ySuperscriptYSize value="700"/>
|
||||
<ySuperscriptXOffset value="0"/>
|
||||
<ySuperscriptYOffset value="480"/>
|
||||
<yStrikeoutSize value="49"/>
|
||||
<yStrikeoutPosition value="258"/>
|
||||
<sFamilyClass value="0"/>
|
||||
<panose>
|
||||
<bFamilyType value="0"/>
|
||||
<bSerifStyle value="0"/>
|
||||
<bWeight value="0"/>
|
||||
<bProportion value="0"/>
|
||||
<bContrast value="0"/>
|
||||
<bStrokeVariation value="0"/>
|
||||
<bArmStyle value="0"/>
|
||||
<bLetterForm value="0"/>
|
||||
<bMidline value="0"/>
|
||||
<bXHeight value="0"/>
|
||||
</panose>
|
||||
<ulUnicodeRange1 value="10000000 00000000 00000000 11101111"/>
|
||||
<ulUnicodeRange2 value="00010000 00000000 11101100 11101101"/>
|
||||
<ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
|
||||
<achVendID value="PfEd"/>
|
||||
<fsSelection value="00000000 01000000"/>
|
||||
<usFirstCharIndex value="32"/>
|
||||
<usLastCharIndex value="160"/>
|
||||
<sTypoAscender value="800"/>
|
||||
<sTypoDescender value="-200"/>
|
||||
<sTypoLineGap value="90"/>
|
||||
<usWinAscent value="533"/>
|
||||
<usWinDescent value="0"/>
|
||||
<ulCodePageRange1 value="00100000 00000000 00000000 10001111"/>
|
||||
<ulCodePageRange2 value="01011110 00000011 00000000 00000000"/>
|
||||
<sxHeight value="0"/>
|
||||
<sCapHeight value="0"/>
|
||||
<usDefaultChar value="32"/>
|
||||
<usBreakChar value="32"/>
|
||||
<usMaxContext value="1"/>
|
||||
</OS_2>
|
||||
|
||||
<name>
|
||||
<namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
|
||||
Copyright (c) 2009-2010 Design Science, Inc.
|
||||
Copyright (c) 2014-2018 Khan Academy
|
||||
</namerecord>
|
||||
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
|
||||
*NAME*
|
||||
</namerecord>
|
||||
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
|
||||
*WEIGHT_S*
|
||||
</namerecord>
|
||||
<namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
|
||||
FontForge 2.0 : *NAME*-*WEIGHT*
|
||||
</namerecord>
|
||||
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
|
||||
*NAME*-*WEIGHT*
|
||||
</namerecord>
|
||||
<namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
|
||||
Version 1.1
|
||||
</namerecord>
|
||||
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
|
||||
*NAME*-*WEIGHT*
|
||||
</namerecord>
|
||||
<namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
|
||||
Copyright (c) 2009-2010, Design Science, Inc. (<www.mathjax.org>)
|
||||
Copyright (c) 2014-2018 Khan Academy (<www.khanacademy.org>),
|
||||
with Reserved Font Name *NAME*.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
</namerecord>
|
||||
<namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
|
||||
http://scripts.sil.org/OFL
|
||||
</namerecord>
|
||||
</name>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="0" platEncID="3" language="0">
|
||||
<map code="0x20" name="space"/><!-- SPACE -->
|
||||
<map code="0xa0" name="uni00A0"/><!-- NO-BREAK SPACE -->
|
||||
</cmap_format_4>
|
||||
<cmap_format_4 platformID="3" platEncID="1" language="0">
|
||||
<map code="0x20" name="space"/><!-- SPACE -->
|
||||
<map code="0xa0" name="uni00A0"/><!-- NO-BREAK SPACE -->
|
||||
</cmap_format_4>
|
||||
</cmap>
|
||||
|
||||
<post>
|
||||
<formatType value="3.0"/>
|
||||
<italicAngle value="0.0"/>
|
||||
<underlinePosition value="-125"/>
|
||||
<underlineThickness value="50"/>
|
||||
<isFixedPitch value="0"/>
|
||||
<minMemType42 value="0"/>
|
||||
<maxMemType42 value="0"/>
|
||||
<minMemType1 value="0"/>
|
||||
<maxMemType1 value="0"/>
|
||||
</post>
|
||||
|
||||
<CFF>
|
||||
<major value="1"/>
|
||||
<minor value="0"/>
|
||||
<CFFFont name="*NAME*-*WEIGHT*">
|
||||
<version value="001.001"/>
|
||||
<Notice value="Copyright (c) 2009-2010 Design Science, Inc., Copyright (c) 2014-2018 Khan Academy"/>
|
||||
<FullName value="*NAME*-*WEIGHT*"/>
|
||||
<FamilyName value="*NAME*"/>
|
||||
<Weight value="*NORMAL*"/>
|
||||
<isFixedPitch value="0"/>
|
||||
<ItalicAngle value="0"/>
|
||||
<UnderlinePosition value="-150"/>
|
||||
<UnderlineThickness value="50"/>
|
||||
<PaintType value="0"/>
|
||||
<CharstringType value="2"/>
|
||||
<FontMatrix value="0.001 0 0 0.001 0 0"/>
|
||||
<FontBBox value="50 0 200 533"/>
|
||||
<StrokeWidth value="0"/>
|
||||
<!-- charset is dumped separately as the 'GlyphOrder' element -->
|
||||
<Encoding name="StandardEncoding"/>
|
||||
<Private>
|
||||
<BlueScale value="0.03963"/>
|
||||
<BlueShift value="0"/>
|
||||
<BlueFuzz value="1"/>
|
||||
<StdHW value="50"/>
|
||||
<StdVW value="50"/>
|
||||
<ForceBold value="0"/>
|
||||
<LanguageGroup value="0"/>
|
||||
<ExpansionFactor value="0.06"/>
|
||||
<initialRandomSeed value="0"/>
|
||||
<defaultWidthX value="250"/>
|
||||
<nominalWidthX value="193"/>
|
||||
</Private>
|
||||
<CharStrings>
|
||||
<CharString name=".notdef">
|
||||
0 50 433 50 hstem
|
||||
50 50 50 50 vstem
|
||||
50 hmoveto
|
||||
150 533 -150 hlineto
|
||||
50 -483 rmoveto
|
||||
433 50 -433 vlineto
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="space">
|
||||
endchar
|
||||
</CharString>
|
||||
<CharString name="uni00A0">
|
||||
endchar
|
||||
</CharString>
|
||||
</CharStrings>
|
||||
</CFFFont>
|
||||
|
||||
<GlobalSubrs>
|
||||
<!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
|
||||
</GlobalSubrs>
|
||||
</CFF>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="250" lsb="50"/>
|
||||
<mtx name="space" width="250" lsb="0"/>
|
||||
<mtx name="uni00A0" width="250" lsb="0"/>
|
||||
</hmtx>
|
||||
|
||||
</ttFont>
|
||||
54
frontend/node_modules/katex/src/functions.ts
generated
vendored
Normal file
54
frontend/node_modules/katex/src/functions.ts
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/** Include this to ensure that all functions are defined. */
|
||||
import {_functions} from "./defineFunction";
|
||||
|
||||
const functions = _functions;
|
||||
export default functions;
|
||||
|
||||
// TODO(kevinb): have functions return an object and call defineFunction with
|
||||
// that object in this file instead of relying on side-effects.
|
||||
import "./functions/accent";
|
||||
import "./functions/accentunder";
|
||||
import "./functions/arrow";
|
||||
import "./functions/pmb";
|
||||
import "./environments/cd";
|
||||
import "./functions/char";
|
||||
import "./functions/color";
|
||||
import "./functions/cr";
|
||||
import "./functions/def";
|
||||
import "./functions/delimsizing";
|
||||
import "./functions/enclose";
|
||||
import "./functions/environment";
|
||||
import "./functions/font";
|
||||
import "./functions/genfrac";
|
||||
import "./functions/horizBrace";
|
||||
import "./functions/href";
|
||||
import "./functions/hbox";
|
||||
import "./functions/html";
|
||||
import "./functions/htmlmathml";
|
||||
import "./functions/includegraphics";
|
||||
import "./functions/kern";
|
||||
import "./functions/lap";
|
||||
import "./functions/math";
|
||||
import "./functions/mathchoice";
|
||||
import "./functions/mclass";
|
||||
import "./functions/op";
|
||||
import "./functions/operatorname";
|
||||
import "./functions/ordgroup";
|
||||
import "./functions/overline";
|
||||
import "./functions/phantom";
|
||||
import "./functions/raisebox";
|
||||
import "./functions/relax";
|
||||
import "./functions/rule";
|
||||
import "./functions/sizing";
|
||||
import "./functions/smash";
|
||||
import "./functions/sqrt";
|
||||
import "./functions/styling";
|
||||
import "./functions/supsub";
|
||||
import "./functions/symbolsOp";
|
||||
import "./functions/symbolsOrd";
|
||||
import "./functions/symbolsSpacing";
|
||||
import "./functions/tag";
|
||||
import "./functions/text";
|
||||
import "./functions/underline";
|
||||
import "./functions/vcenter";
|
||||
import "./functions/verb";
|
||||
119
frontend/node_modules/katex/src/functions/font.ts
generated
vendored
Normal file
119
frontend/node_modules/katex/src/functions/font.ts
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
// TODO(kevinb): implement \\sl and \\sc
|
||||
|
||||
import {binrelClass} from "./mclass";
|
||||
import defineFunction, {normalizeArgument} from "../defineFunction";
|
||||
import {isCharacterBox} from "../utils";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type Options from "../Options";
|
||||
import type {ParseNode} from "../parseNode";
|
||||
|
||||
const htmlBuilder = (group: ParseNode<"font">, options: Options) => {
|
||||
const font = group.font;
|
||||
const newOptions = options.withFont(font);
|
||||
return html.buildGroup(group.body, newOptions);
|
||||
};
|
||||
|
||||
const mathmlBuilder = (group: ParseNode<"font">, options: Options) => {
|
||||
const font = group.font;
|
||||
const newOptions = options.withFont(font);
|
||||
return mml.buildGroup(group.body, newOptions);
|
||||
};
|
||||
|
||||
const fontAliases: Record<string, string> = {
|
||||
"\\Bbb": "\\mathbb",
|
||||
"\\bold": "\\mathbf",
|
||||
"\\frak": "\\mathfrak",
|
||||
"\\bm": "\\boldsymbol",
|
||||
};
|
||||
|
||||
defineFunction({
|
||||
type: "font",
|
||||
names: [
|
||||
// styles, except \boldsymbol defined below
|
||||
"\\mathrm", "\\mathit", "\\mathbf", "\\mathnormal", "\\mathsfit",
|
||||
|
||||
// families
|
||||
"\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
|
||||
"\\mathtt",
|
||||
|
||||
// aliases, except \bm defined below
|
||||
"\\Bbb", "\\bold", "\\frak",
|
||||
],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
allowedInArgument: true,
|
||||
},
|
||||
handler: ({parser, funcName}, args) => {
|
||||
const body = normalizeArgument(args[0]);
|
||||
let func = funcName;
|
||||
if (func in fontAliases) {
|
||||
func = fontAliases[func];
|
||||
}
|
||||
return {
|
||||
type: "font",
|
||||
mode: parser.mode,
|
||||
font: func.slice(1),
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
|
||||
defineFunction({
|
||||
type: "mclass",
|
||||
names: ["\\boldsymbol", "\\bm"],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
},
|
||||
handler: ({parser}, args) => {
|
||||
const body = args[0];
|
||||
// amsbsy.sty's \boldsymbol uses \binrel spacing to inherit the
|
||||
// argument's bin|rel|ord status
|
||||
return {
|
||||
type: "mclass",
|
||||
mode: parser.mode,
|
||||
mclass: binrelClass(body),
|
||||
body: [
|
||||
{
|
||||
type: "font",
|
||||
mode: parser.mode,
|
||||
font: "boldsymbol",
|
||||
body,
|
||||
},
|
||||
],
|
||||
isCharacterBox: isCharacterBox(body),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Old font changing functions
|
||||
defineFunction({
|
||||
type: "font",
|
||||
names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"],
|
||||
props: {
|
||||
numArgs: 0,
|
||||
allowedInText: true,
|
||||
},
|
||||
handler: ({parser, funcName, breakOnTokenText}, args) => {
|
||||
const {mode} = parser;
|
||||
const body = parser.parseExpression(true, breakOnTokenText);
|
||||
const style = `math${funcName.slice(1)}`;
|
||||
|
||||
return {
|
||||
type: "font",
|
||||
mode: mode,
|
||||
font: style,
|
||||
body: {
|
||||
type: "ordgroup",
|
||||
mode: parser.mode,
|
||||
body,
|
||||
},
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
105
frontend/node_modules/katex/src/functions/html.ts
generated
vendored
Normal file
105
frontend/node_modules/katex/src/functions/html.ts
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
import defineFunction, {ordargument} from "../defineFunction";
|
||||
import {makeSpan} from "../buildCommon";
|
||||
import {assertNodeType} from "../parseNode";
|
||||
import ParseError from "../ParseError";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
import type {AnyTrustContext} from "../Settings";
|
||||
|
||||
defineFunction({
|
||||
type: "html",
|
||||
names: ["\\htmlClass", "\\htmlId", "\\htmlStyle", "\\htmlData"],
|
||||
props: {
|
||||
numArgs: 2,
|
||||
argTypes: ["raw", "original"],
|
||||
allowedInText: true,
|
||||
},
|
||||
handler: ({parser, funcName, token}, args) => {
|
||||
const value = assertNodeType(args[0], "raw").string;
|
||||
const body = args[1];
|
||||
|
||||
if (parser.settings.strict) {
|
||||
parser.settings.reportNonstrict("htmlExtension",
|
||||
"HTML extension is disabled on strict mode");
|
||||
}
|
||||
|
||||
let trustContext: AnyTrustContext;
|
||||
const attributes: Record<string, string> = {};
|
||||
|
||||
switch (funcName) {
|
||||
case "\\htmlClass":
|
||||
attributes.class = value;
|
||||
trustContext = {
|
||||
command: "\\htmlClass",
|
||||
class: value,
|
||||
};
|
||||
break;
|
||||
case "\\htmlId":
|
||||
attributes.id = value;
|
||||
trustContext = {
|
||||
command: "\\htmlId",
|
||||
id: value,
|
||||
};
|
||||
break;
|
||||
case "\\htmlStyle":
|
||||
attributes.style = value;
|
||||
trustContext = {
|
||||
command: "\\htmlStyle",
|
||||
style: value,
|
||||
};
|
||||
break;
|
||||
case "\\htmlData": {
|
||||
const data = value.split(",");
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i];
|
||||
const firstEquals = item.indexOf("=");
|
||||
if (firstEquals < 0) {
|
||||
throw new ParseError(`\\htmlData key/value '${item}'` +
|
||||
` missing equals sign`);
|
||||
}
|
||||
const key = item.slice(0, firstEquals);
|
||||
const value = item.slice(firstEquals + 1);
|
||||
attributes["data-" + key.trim()] = value;
|
||||
}
|
||||
|
||||
trustContext = {
|
||||
command: "\\htmlData",
|
||||
attributes,
|
||||
};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Unrecognized html command");
|
||||
}
|
||||
|
||||
if (!parser.settings.isTrusted(trustContext)) {
|
||||
return parser.formatUnsupportedCmd(funcName);
|
||||
}
|
||||
return {
|
||||
type: "html",
|
||||
mode: parser.mode,
|
||||
attributes,
|
||||
body: ordargument(body),
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
const elements = html.buildExpression(group.body, options, false);
|
||||
|
||||
const classes = ["enclosing"];
|
||||
if (group.attributes.class) {
|
||||
classes.push(...group.attributes.class.trim().split(/\s+/));
|
||||
}
|
||||
|
||||
const span = makeSpan(classes, elements, options);
|
||||
for (const attr in group.attributes) {
|
||||
if (attr !== "class" && group.attributes.hasOwnProperty(attr)) {
|
||||
span.setAttribute(attr, group.attributes[attr]);
|
||||
}
|
||||
}
|
||||
return span;
|
||||
},
|
||||
mathmlBuilder: (group, options) => {
|
||||
return mml.buildExpressionRow(group.body, options);
|
||||
},
|
||||
});
|
||||
55
frontend/node_modules/katex/src/functions/kern.ts
generated
vendored
Normal file
55
frontend/node_modules/katex/src/functions/kern.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// Horizontal spacing commands
|
||||
|
||||
import defineFunction from "../defineFunction";
|
||||
import {makeGlue} from "../buildCommon";
|
||||
import {SpaceNode} from "../mathMLTree";
|
||||
import {calculateSize} from "../units";
|
||||
import {assertNodeType} from "../parseNode";
|
||||
|
||||
// TODO: \hskip and \mskip should support plus and minus in lengths
|
||||
|
||||
defineFunction({
|
||||
type: "kern",
|
||||
names: ["\\kern", "\\mkern", "\\hskip", "\\mskip"],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
argTypes: ["size"],
|
||||
primitive: true,
|
||||
allowedInText: true,
|
||||
},
|
||||
handler({parser, funcName}, args) {
|
||||
const size = assertNodeType(args[0], "size");
|
||||
if (parser.settings.strict) {
|
||||
const mathFunction = (funcName[1] === 'm'); // \mkern, \mskip
|
||||
const muUnit = (size.value.unit === 'mu');
|
||||
if (mathFunction) {
|
||||
if (!muUnit) {
|
||||
parser.settings.reportNonstrict("mathVsTextUnits",
|
||||
`LaTeX's ${funcName} supports only mu units, ` +
|
||||
`not ${size.value.unit} units`);
|
||||
}
|
||||
if (parser.mode !== "math") {
|
||||
parser.settings.reportNonstrict("mathVsTextUnits",
|
||||
`LaTeX's ${funcName} works only in math mode`);
|
||||
}
|
||||
} else { // !mathFunction
|
||||
if (muUnit) {
|
||||
parser.settings.reportNonstrict("mathVsTextUnits",
|
||||
`LaTeX's ${funcName} doesn't support mu units`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: "kern",
|
||||
mode: parser.mode,
|
||||
dimension: size.value,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
return makeGlue(group.dimension, options);
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
const dimension = calculateSize(group.dimension, options);
|
||||
return new SpaceNode(dimension);
|
||||
},
|
||||
});
|
||||
41
frontend/node_modules/katex/src/functions/math.ts
generated
vendored
Normal file
41
frontend/node_modules/katex/src/functions/math.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import defineFunction from "../defineFunction";
|
||||
import ParseError from "../ParseError";
|
||||
|
||||
// Switching from text mode back to math mode
|
||||
defineFunction({
|
||||
type: "styling",
|
||||
names: ["\\(", "$"],
|
||||
props: {
|
||||
numArgs: 0,
|
||||
allowedInText: true,
|
||||
allowedInMath: false,
|
||||
},
|
||||
handler({funcName, parser}, args) {
|
||||
const outerMode = parser.mode;
|
||||
parser.switchMode("math");
|
||||
const close = (funcName === "\\(" ? "\\)" : "$");
|
||||
const body = parser.parseExpression(false, close);
|
||||
parser.expect(close);
|
||||
parser.switchMode(outerMode);
|
||||
return {
|
||||
type: "styling",
|
||||
mode: parser.mode,
|
||||
style: "text",
|
||||
body,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Check for extra closing math delimiters
|
||||
defineFunction({
|
||||
type: "text", // Doesn't matter what this is.
|
||||
names: ["\\)", "\\]"],
|
||||
props: {
|
||||
numArgs: 0,
|
||||
allowedInText: true,
|
||||
allowedInMath: false,
|
||||
},
|
||||
handler(context, args) {
|
||||
throw new ParseError(`Mismatched ${context.funcName}`);
|
||||
},
|
||||
});
|
||||
165
frontend/node_modules/katex/src/functions/mclass.ts
generated
vendored
Normal file
165
frontend/node_modules/katex/src/functions/mclass.ts
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
import defineFunction, {ordargument} from "../defineFunction";
|
||||
import {makeSpan} from "../buildCommon";
|
||||
import {isCharacterBox} from "../utils";
|
||||
import {MathNode} from "../mathMLTree";
|
||||
import type {AnyParseNode} from "../parseNode";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type Options from "../Options";
|
||||
import type {ParseNode} from "../parseNode";
|
||||
|
||||
function htmlBuilder(group: ParseNode<"mclass">, options: Options) {
|
||||
const elements = html.buildExpression(group.body, options, true);
|
||||
return makeSpan([group.mclass], elements, options);
|
||||
}
|
||||
|
||||
function mathmlBuilder(group: ParseNode<"mclass">, options: Options) {
|
||||
let node: MathNode;
|
||||
const inner = mml.buildExpression(group.body, options);
|
||||
|
||||
if (group.mclass === "minner") {
|
||||
node = new MathNode("mpadded", inner);
|
||||
} else if (group.mclass === "mord") {
|
||||
if (group.isCharacterBox) {
|
||||
node = inner[0];
|
||||
node.type = "mi";
|
||||
} else {
|
||||
node = new MathNode("mi", inner);
|
||||
}
|
||||
} else {
|
||||
if (group.isCharacterBox) {
|
||||
node = inner[0];
|
||||
node.type = "mo";
|
||||
} else {
|
||||
node = new MathNode("mo", inner);
|
||||
}
|
||||
|
||||
// Set spacing based on what is the most likely adjacent atom type.
|
||||
// See TeXbook p170.
|
||||
if (group.mclass === "mbin") {
|
||||
node.attributes.lspace = "0.22em"; // medium space
|
||||
node.attributes.rspace = "0.22em";
|
||||
} else if (group.mclass === "mpunct") {
|
||||
node.attributes.lspace = "0em";
|
||||
node.attributes.rspace = "0.17em"; // thinspace
|
||||
} else if (group.mclass === "mopen" || group.mclass === "mclose") {
|
||||
node.attributes.lspace = "0em";
|
||||
node.attributes.rspace = "0em";
|
||||
} else if (group.mclass === "minner") {
|
||||
node.attributes.lspace = "0.0556em"; // 1 mu is the most likely option
|
||||
node.attributes.width = "+0.1111em";
|
||||
}
|
||||
// MathML <mo> default space is 5/18 em, so <mrel> needs no action.
|
||||
// Ref: https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mo
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// Math class commands except \mathop
|
||||
defineFunction({
|
||||
type: "mclass",
|
||||
names: [
|
||||
"\\mathord", "\\mathbin", "\\mathrel", "\\mathopen",
|
||||
"\\mathclose", "\\mathpunct", "\\mathinner",
|
||||
],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
primitive: true,
|
||||
},
|
||||
handler({parser, funcName}, args) {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "mclass",
|
||||
mode: parser.mode,
|
||||
mclass: "m" + funcName.slice(5), // TODO(kevinb): don't prefix with 'm'
|
||||
body: ordargument(body),
|
||||
isCharacterBox: isCharacterBox(body),
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
|
||||
export const binrelClass = (arg: AnyParseNode): string => {
|
||||
// \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument.
|
||||
// (by rendering separately and with {}s before and after, and measuring
|
||||
// the change in spacing). We'll do roughly the same by detecting the
|
||||
// atom type directly.
|
||||
const atom = (arg.type === "ordgroup" && arg.body.length ? arg.body[0] : arg);
|
||||
if (atom.type === "atom" && (atom.family === "bin" || atom.family === "rel")) {
|
||||
return "m" + atom.family;
|
||||
} else {
|
||||
return "mord";
|
||||
}
|
||||
};
|
||||
|
||||
// \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord.
|
||||
// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX.
|
||||
defineFunction({
|
||||
type: "mclass",
|
||||
names: ["\\@binrel"],
|
||||
props: {
|
||||
numArgs: 2,
|
||||
},
|
||||
handler({parser}, args) {
|
||||
return {
|
||||
type: "mclass",
|
||||
mode: parser.mode,
|
||||
mclass: binrelClass(args[0]),
|
||||
body: ordargument(args[1]),
|
||||
isCharacterBox: isCharacterBox(args[1]),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
// Build a relation or stacked op by placing one symbol on top of another
|
||||
defineFunction({
|
||||
type: "mclass",
|
||||
names: ["\\stackrel", "\\overset", "\\underset"],
|
||||
props: {
|
||||
numArgs: 2,
|
||||
},
|
||||
handler({parser, funcName}, args) {
|
||||
const baseArg = args[1];
|
||||
const shiftedArg = args[0];
|
||||
|
||||
let mclass;
|
||||
if (funcName !== "\\stackrel") {
|
||||
// LaTeX applies \binrel spacing to \overset and \underset.
|
||||
mclass = binrelClass(baseArg);
|
||||
} else {
|
||||
mclass = "mrel"; // for \stackrel
|
||||
}
|
||||
|
||||
const baseOp: ParseNode<"op"> = {
|
||||
type: "op",
|
||||
mode: baseArg.mode,
|
||||
limits: true,
|
||||
alwaysHandleSupSub: true,
|
||||
parentIsSupSub: false,
|
||||
symbol: false,
|
||||
suppressBaseShift: funcName !== "\\stackrel",
|
||||
body: ordargument(baseArg),
|
||||
};
|
||||
|
||||
const supsub: ParseNode<"supsub"> = {
|
||||
type: "supsub",
|
||||
mode: shiftedArg.mode,
|
||||
base: baseOp,
|
||||
sup: funcName === "\\underset" ? null : shiftedArg,
|
||||
sub: funcName === "\\underset" ? shiftedArg : null,
|
||||
};
|
||||
|
||||
return {
|
||||
type: "mclass",
|
||||
mode: parser.mode,
|
||||
mclass,
|
||||
body: [supsub],
|
||||
isCharacterBox: isCharacterBox(supsub),
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
161
frontend/node_modules/katex/src/functions/operatorname.ts
generated
vendored
Normal file
161
frontend/node_modules/katex/src/functions/operatorname.ts
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
import defineFunction, {ordargument} from "../defineFunction";
|
||||
import defineMacro from "../defineMacro";
|
||||
import {makeSpan} from "../buildCommon";
|
||||
import {MathNode, newDocumentFragment, SpaceNode, TextNode} from "../mathMLTree";
|
||||
import {SymbolNode} from "../domTree";
|
||||
import {assembleSupSub} from "./utils/assembleSupSub";
|
||||
import {assertNodeType} from "../parseNode";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
|
||||
import type {AnyParseNode, ParseNode} from "../parseNode";
|
||||
|
||||
// NOTE: Unlike most `htmlBuilder`s, this one handles not only
|
||||
// "operatorname", but also "supsub" since \operatorname* can
|
||||
// affect super/subscripting.
|
||||
export const htmlBuilder: HtmlBuilderSupSub<"operatorname"> = (grp, options) => {
|
||||
// Operators are handled in the TeXbook pg. 443-444, rule 13(a).
|
||||
let supGroup;
|
||||
let subGroup;
|
||||
let hasLimits = false;
|
||||
let group: ParseNode<"operatorname">;
|
||||
if (grp.type === "supsub") {
|
||||
// If we have limits, supsub will pass us its group to handle. Pull
|
||||
// out the superscript and subscript and set the group to the op in
|
||||
// its base.
|
||||
supGroup = grp.sup;
|
||||
subGroup = grp.sub;
|
||||
group = assertNodeType(grp.base, "operatorname");
|
||||
hasLimits = true;
|
||||
} else {
|
||||
group = assertNodeType(grp, "operatorname");
|
||||
}
|
||||
|
||||
let base;
|
||||
if (group.body.length > 0) {
|
||||
const body = group.body.map((child): AnyParseNode => {
|
||||
const childText = "text" in child ? child.text : undefined;
|
||||
if (typeof childText === "string") {
|
||||
return {
|
||||
type: "textord",
|
||||
mode: child.mode,
|
||||
text: childText,
|
||||
};
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
});
|
||||
|
||||
// Consolidate function names into symbol characters.
|
||||
const expression = html.buildExpression(
|
||||
body, options.withFont("mathrm"), true);
|
||||
|
||||
for (let i = 0; i < expression.length; i++) {
|
||||
const child = expression[i];
|
||||
if (child instanceof SymbolNode) {
|
||||
// Per amsopn package,
|
||||
// change minus to hyphen and \ast to asterisk
|
||||
child.text = child.text.replace(/\u2212/, "-")
|
||||
.replace(/\u2217/, "*");
|
||||
}
|
||||
}
|
||||
base = makeSpan(["mop"], expression, options);
|
||||
} else {
|
||||
base = makeSpan(["mop"], [], options);
|
||||
}
|
||||
|
||||
if (hasLimits) {
|
||||
return assembleSupSub(base, supGroup, subGroup, options,
|
||||
options.style, 0, 0);
|
||||
|
||||
} else {
|
||||
return base;
|
||||
}
|
||||
};
|
||||
|
||||
const mathmlBuilder: MathMLBuilder<"operatorname"> = (group, options) => {
|
||||
// The steps taken here are similar to the html version.
|
||||
let expression: Array<MathNode | TextNode> = mml.buildExpression(
|
||||
group.body, options.withFont("mathrm"));
|
||||
|
||||
// Is expression a string or has it something like a fraction?
|
||||
let isAllString = true; // default
|
||||
for (let i = 0; i < expression.length; i++) {
|
||||
const node = expression[i];
|
||||
if (node instanceof SpaceNode) {
|
||||
// Do nothing
|
||||
} else if (node instanceof MathNode) {
|
||||
switch (node.type) {
|
||||
case "mi":
|
||||
case "mn":
|
||||
case "mspace":
|
||||
case "mtext":
|
||||
break; // Do nothing yet.
|
||||
case "mo": {
|
||||
const child = node.children[0];
|
||||
if (node.children.length === 1 &&
|
||||
child instanceof TextNode) {
|
||||
child.text =
|
||||
child.text.replace(/\u2212/, "-")
|
||||
.replace(/\u2217/, "*");
|
||||
} else {
|
||||
isAllString = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
isAllString = false;
|
||||
}
|
||||
} else {
|
||||
isAllString = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAllString) {
|
||||
// Write a single TextNode instead of multiple nested tags.
|
||||
const word = expression.map(node => node.toText()).join("");
|
||||
expression = [new TextNode(word)];
|
||||
}
|
||||
|
||||
const identifier = new MathNode("mi", expression);
|
||||
identifier.setAttribute("mathvariant", "normal");
|
||||
|
||||
// \u2061 is the same as ⁡
|
||||
// ref: https://www.w3schools.com/charsets/ref_html_entities_a.asp
|
||||
const operator = new MathNode("mo",
|
||||
[mml.makeText("\u2061", "text")]);
|
||||
|
||||
if (group.parentIsSupSub) {
|
||||
return new MathNode("mrow", [identifier, operator]);
|
||||
} else {
|
||||
return newDocumentFragment([identifier, operator]);
|
||||
}
|
||||
};
|
||||
|
||||
// \operatorname
|
||||
// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
|
||||
defineFunction({
|
||||
type: "operatorname",
|
||||
names: ["\\operatorname@", "\\operatornamewithlimits"],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
},
|
||||
handler: ({parser, funcName}, args) => {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "operatorname",
|
||||
mode: parser.mode,
|
||||
body: ordargument(body),
|
||||
alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"),
|
||||
limits: false,
|
||||
parentIsSupSub: false,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
|
||||
defineMacro("\\operatorname",
|
||||
"\\@ifstar\\operatornamewithlimits\\operatorname@");
|
||||
124
frontend/node_modules/katex/src/functions/sqrt.ts
generated
vendored
Normal file
124
frontend/node_modules/katex/src/functions/sqrt.ts
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
import defineFunction from "../defineFunction";
|
||||
import {makeSpan, makeVList, wrapFragment} from "../buildCommon";
|
||||
import {MathNode} from "../mathMLTree";
|
||||
import {makeSqrtImage} from "../delimiter";
|
||||
import Style from "../Style";
|
||||
import {makeEm} from "../units";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
defineFunction({
|
||||
type: "sqrt",
|
||||
names: ["\\sqrt"],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
numOptionalArgs: 1,
|
||||
},
|
||||
handler({parser}, args, optArgs) {
|
||||
const index = optArgs[0];
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "sqrt",
|
||||
mode: parser.mode,
|
||||
body,
|
||||
index,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
// Square roots are handled in the TeXbook pg. 443, Rule 11.
|
||||
|
||||
// First, we do the same steps as in overline to build the inner group
|
||||
// and line
|
||||
let inner = html.buildGroup(group.body, options.havingCrampedStyle());
|
||||
if (inner.height === 0) {
|
||||
// Render a small surd.
|
||||
inner.height = options.fontMetrics().xHeight;
|
||||
}
|
||||
|
||||
// Some groups can return document fragments. Handle those by wrapping
|
||||
// them in a span.
|
||||
inner = wrapFragment(inner, options);
|
||||
|
||||
// Calculate the minimum size for the \surd delimiter
|
||||
const metrics = options.fontMetrics();
|
||||
const theta = metrics.defaultRuleThickness;
|
||||
|
||||
let phi = theta;
|
||||
if (options.style.id < Style.TEXT.id) {
|
||||
phi = options.fontMetrics().xHeight;
|
||||
}
|
||||
|
||||
// Calculate the clearance between the body and line
|
||||
let lineClearance = theta + phi / 4;
|
||||
|
||||
const minDelimiterHeight = (inner.height + inner.depth +
|
||||
lineClearance + theta);
|
||||
|
||||
// Create a sqrt SVG of the required minimum size
|
||||
const {span: img, ruleWidth, advanceWidth} =
|
||||
makeSqrtImage(minDelimiterHeight, options);
|
||||
|
||||
const delimDepth = img.height - ruleWidth;
|
||||
|
||||
// Adjust the clearance based on the delimiter size
|
||||
if (delimDepth > inner.height + inner.depth + lineClearance) {
|
||||
lineClearance =
|
||||
(lineClearance + delimDepth - inner.height - inner.depth) / 2;
|
||||
}
|
||||
|
||||
// Shift the sqrt image
|
||||
const imgShift = img.height - inner.height - lineClearance - ruleWidth;
|
||||
|
||||
inner.style.paddingLeft = makeEm(advanceWidth);
|
||||
|
||||
// Overlay the image and the argument.
|
||||
const body = makeVList({
|
||||
positionType: "firstBaseline",
|
||||
children: [
|
||||
{type: "elem", elem: inner, wrapperClasses: ["svg-align"]},
|
||||
{type: "kern", size: -(inner.height + imgShift)},
|
||||
{type: "elem", elem: img},
|
||||
{type: "kern", size: ruleWidth},
|
||||
],
|
||||
}, options);
|
||||
|
||||
if (!group.index) {
|
||||
return makeSpan(["mord", "sqrt"], [body], options);
|
||||
} else {
|
||||
// Handle the optional root index
|
||||
|
||||
// The index is always in scriptscript style
|
||||
const newOptions = options.havingStyle(Style.SCRIPTSCRIPT);
|
||||
const rootm = html.buildGroup(group.index, newOptions, options);
|
||||
|
||||
// The amount the index is shifted by. This is taken from the TeX
|
||||
// source, in the definition of `\r@@t`.
|
||||
const toShift = 0.6 * (body.height - body.depth);
|
||||
|
||||
// Build a VList with the superscript shifted up correctly
|
||||
const rootVList = makeVList({
|
||||
positionType: "shift",
|
||||
positionData: -toShift,
|
||||
children: [{type: "elem", elem: rootm}],
|
||||
}, options);
|
||||
// Add a class surrounding it so we can add on the appropriate
|
||||
// kerning
|
||||
const rootVListWrap = makeSpan(["root"], [rootVList]);
|
||||
|
||||
return makeSpan(["mord", "sqrt"],
|
||||
[rootVListWrap, body], options);
|
||||
}
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
const {body, index} = group;
|
||||
return index ?
|
||||
new MathNode(
|
||||
"mroot", [
|
||||
mml.buildGroup(body, options),
|
||||
mml.buildGroup(index, options),
|
||||
]) :
|
||||
new MathNode(
|
||||
"msqrt", [mml.buildGroup(body, options)]);
|
||||
},
|
||||
});
|
||||
72
frontend/node_modules/katex/src/functions/symbolsSpacing.ts
generated
vendored
Normal file
72
frontend/node_modules/katex/src/functions/symbolsSpacing.ts
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import {defineFunctionBuilders} from "../defineFunction";
|
||||
import {mathsym, makeOrd, makeSpan} from "../buildCommon";
|
||||
import {MathNode, TextNode} from "../mathMLTree";
|
||||
import ParseError from "../ParseError";
|
||||
|
||||
// A map of CSS-based spacing functions to their CSS class.
|
||||
const cssSpace: Record<string, string> = {
|
||||
"\\nobreak": "nobreak",
|
||||
"\\allowbreak": "allowbreak",
|
||||
};
|
||||
|
||||
// A lookup table to determine whether a spacing function/symbol should be
|
||||
// treated like a regular space character. If a symbol or command is a key
|
||||
// in this table, then it should be a regular space character. Furthermore,
|
||||
// the associated value may have a `className` specifying an extra CSS class
|
||||
// to add to the created `span`.
|
||||
const regularSpace: Record<string, {className?: string}> = {
|
||||
" ": {},
|
||||
"\\ ": {},
|
||||
"~": {
|
||||
className: "nobreak",
|
||||
},
|
||||
"\\space": {},
|
||||
"\\nobreakspace": {
|
||||
className: "nobreak",
|
||||
},
|
||||
};
|
||||
|
||||
// ParseNode<"spacing"> created in Parser.js from the "spacing" symbol Groups in
|
||||
// src/symbols.js.
|
||||
defineFunctionBuilders({
|
||||
type: "spacing",
|
||||
htmlBuilder(group, options) {
|
||||
if (regularSpace.hasOwnProperty(group.text)) {
|
||||
const className = regularSpace[group.text].className || "";
|
||||
// Spaces are generated by adding an actual space. Each of these
|
||||
// things has an entry in the symbols table, so these will be turned
|
||||
// into appropriate outputs.
|
||||
if (group.mode === "text") {
|
||||
const ord = makeOrd(group, options, "textord");
|
||||
ord.classes.push(className);
|
||||
return ord;
|
||||
} else {
|
||||
return makeSpan(["mspace", className],
|
||||
[mathsym(group.text, group.mode, options)],
|
||||
options);
|
||||
}
|
||||
} else if (cssSpace.hasOwnProperty(group.text)) {
|
||||
// Spaces based on just a CSS class.
|
||||
return makeSpan(
|
||||
["mspace", cssSpace[group.text]],
|
||||
[], options);
|
||||
} else {
|
||||
throw new ParseError(`Unknown type of space "${group.text}"`);
|
||||
}
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
let node;
|
||||
|
||||
if (regularSpace.hasOwnProperty(group.text)) {
|
||||
node = new MathNode(
|
||||
"mtext", [new TextNode("\u00a0")]);
|
||||
} else if (cssSpace.hasOwnProperty(group.text)) {
|
||||
// CSS-based MathML spaces (\nobreak, \allowbreak) are ignored
|
||||
return new MathNode("mspace");
|
||||
} else {
|
||||
throw new ParseError(`Unknown type of space "${group.text}"`);
|
||||
}
|
||||
|
||||
return node;
|
||||
},
|
||||
});
|
||||
77
frontend/node_modules/katex/src/functions/text.ts
generated
vendored
Normal file
77
frontend/node_modules/katex/src/functions/text.ts
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
import defineFunction, {ordargument} from "../defineFunction";
|
||||
import {makeSpan} from "../buildCommon";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
import type Options from "../Options";
|
||||
import type {ParseNode} from "../parseNode";
|
||||
|
||||
// Non-mathy text, possibly in a font
|
||||
const textFontFamilies: Record<string, string | undefined> = {
|
||||
"\\text": undefined, "\\textrm": "textrm", "\\textsf": "textsf",
|
||||
"\\texttt": "texttt", "\\textnormal": "textrm",
|
||||
};
|
||||
|
||||
const textFontWeights: Record<string, "textbf" | "textmd"> = {
|
||||
"\\textbf": "textbf",
|
||||
"\\textmd": "textmd",
|
||||
};
|
||||
|
||||
const textFontShapes: Record<string, "textit" | "textup"> = {
|
||||
"\\textit": "textit",
|
||||
"\\textup": "textup",
|
||||
};
|
||||
|
||||
const optionsWithFont = (group: ParseNode<"text">, options: Options): Options => {
|
||||
const font = group.font;
|
||||
// Checks if the argument is a font family or a font style.
|
||||
if (!font) {
|
||||
return options;
|
||||
} else if (textFontFamilies[font]) {
|
||||
return options.withTextFontFamily(textFontFamilies[font]);
|
||||
} else if (textFontWeights[font]) {
|
||||
return options.withTextFontWeight(textFontWeights[font]);
|
||||
} else if (font === "\\emph") {
|
||||
return options.fontShape === "textit" ?
|
||||
options.withTextFontShape("textup") :
|
||||
options.withTextFontShape("textit");
|
||||
}
|
||||
|
||||
return options.withTextFontShape(textFontShapes[font] as "textit" | "textup");
|
||||
};
|
||||
|
||||
defineFunction({
|
||||
type: "text",
|
||||
names: [
|
||||
// Font families
|
||||
"\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",
|
||||
// Font weights
|
||||
"\\textbf", "\\textmd",
|
||||
// Font Shapes
|
||||
"\\textit", "\\textup", "\\emph",
|
||||
],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
argTypes: ["text"],
|
||||
allowedInArgument: true,
|
||||
allowedInText: true,
|
||||
},
|
||||
handler({parser, funcName}, args) {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "text",
|
||||
mode: parser.mode,
|
||||
body: ordargument(body),
|
||||
font: funcName,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
const newOptions = optionsWithFont(group, options);
|
||||
const inner = html.buildExpression(group.body, newOptions, true);
|
||||
return makeSpan(["mord", "text"], inner, newOptions);
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
const newOptions = optionsWithFont(group, options);
|
||||
return mml.buildExpressionRow(group.body, newOptions);
|
||||
},
|
||||
});
|
||||
259
frontend/node_modules/katex/src/mathMLTree.ts
generated
vendored
Normal file
259
frontend/node_modules/katex/src/mathMLTree.ts
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* These objects store data about MathML nodes. This is the MathML equivalent
|
||||
* of the types in domTree.js. Since MathML handles its own rendering, and
|
||||
* since we're mainly using MathML to improve accessibility, we don't manage
|
||||
* any of the styling state that the plain DOM nodes do.
|
||||
*
|
||||
* The `toNode` and `toMarkup` functions work similarly to how they do in
|
||||
* domTree.js, creating namespaced DOM nodes and HTML text markup respectively.
|
||||
*/
|
||||
|
||||
import {escape} from "./utils";
|
||||
import {DocumentFragment} from "./tree";
|
||||
import {createClass} from "./domTree";
|
||||
import {makeEm} from "./units";
|
||||
|
||||
import type {VirtualNode} from "./tree";
|
||||
|
||||
/**
|
||||
* MathML node types used in KaTeX. For a complete list of MathML nodes, see
|
||||
* https://developer.mozilla.org/en-US/docs/Web/MathML/Element.
|
||||
*/
|
||||
export type MathNodeType =
|
||||
"math" | "annotation" | "semantics" |
|
||||
"mtext" | "mn" | "mo" | "mi" | "mspace" |
|
||||
"mover" | "munder" | "munderover" | "msup" | "msub" | "msubsup" |
|
||||
"mfrac" | "mroot" | "msqrt" |
|
||||
"mtable" | "mtr" | "mtd" | "mlabeledtr" |
|
||||
"mrow" | "menclose" |
|
||||
"mstyle" | "mpadded" | "mphantom" | "mglyph";
|
||||
|
||||
export interface MathDomNode extends VirtualNode {
|
||||
toText(): string;
|
||||
}
|
||||
|
||||
export type documentFragment = DocumentFragment<MathDomNode>;
|
||||
export function newDocumentFragment(
|
||||
children: ReadonlyArray<MathDomNode>
|
||||
): documentFragment {
|
||||
return new DocumentFragment(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* This node represents a general purpose MathML node of any type. The
|
||||
* constructor requires the type of node to create (for example, `"mo"` or
|
||||
* `"mspace"`, corresponding to `<mo>` and `<mspace>` tags).
|
||||
*/
|
||||
export class MathNode implements MathDomNode {
|
||||
type: MathNodeType;
|
||||
attributes: Record<string, string>;
|
||||
children: MathDomNode[];
|
||||
classes: string[];
|
||||
|
||||
constructor(
|
||||
type: MathNodeType,
|
||||
children?: MathDomNode[],
|
||||
classes?: string[]
|
||||
) {
|
||||
this.type = type;
|
||||
this.attributes = {};
|
||||
this.children = children || [];
|
||||
this.classes = classes || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute on a MathML node. MathML depends on attributes to convey a
|
||||
* semantic content, so this is used heavily.
|
||||
*/
|
||||
setAttribute(name: string, value: string) {
|
||||
this.attributes[name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an attribute on a MathML node.
|
||||
*/
|
||||
getAttribute(name: string): string {
|
||||
return this.attributes[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the math node into a MathML-namespaced DOM element.
|
||||
*/
|
||||
toNode(): Node {
|
||||
const node = document.createElementNS(
|
||||
"http://www.w3.org/1998/Math/MathML", this.type);
|
||||
|
||||
for (const attr in this.attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
||||
node.setAttribute(attr, this.attributes[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.classes.length > 0) {
|
||||
node.className = createClass(this.classes);
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
// Combine multiple TextNodes into one TextNode, to prevent
|
||||
// screen readers from reading each as a separate word [#3995]
|
||||
if (this.children[i] instanceof TextNode &&
|
||||
this.children[i + 1] instanceof TextNode) {
|
||||
let text = this.children[i].toText() + this.children[++i].toText();
|
||||
while (this.children[i + 1] instanceof TextNode) {
|
||||
text += this.children[++i].toText();
|
||||
}
|
||||
node.appendChild(new TextNode(text).toNode());
|
||||
} else {
|
||||
node.appendChild(this.children[i].toNode());
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the math node into an HTML markup string.
|
||||
*/
|
||||
toMarkup(): string {
|
||||
let markup = "<" + this.type;
|
||||
|
||||
// Add the attributes
|
||||
for (const attr in this.attributes) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
||||
markup += " " + attr + "=\"";
|
||||
markup += escape(this.attributes[attr]);
|
||||
markup += "\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (this.classes.length > 0) {
|
||||
markup += ` class ="${escape(createClass(this.classes))}"`;
|
||||
}
|
||||
|
||||
markup += ">";
|
||||
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
markup += this.children[i].toMarkup();
|
||||
}
|
||||
|
||||
markup += "</" + this.type + ">";
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the math node into a string, similar to innerText, but escaped.
|
||||
*/
|
||||
toText(): string {
|
||||
return this.children.map(child => child.toText()).join("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This node represents a piece of text.
|
||||
*/
|
||||
export class TextNode implements MathDomNode {
|
||||
text: string;
|
||||
|
||||
constructor(text: string) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the text node into a DOM text node.
|
||||
*/
|
||||
toNode(): Node {
|
||||
return document.createTextNode(this.text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the text node into escaped HTML markup
|
||||
* (representing the text itself).
|
||||
*/
|
||||
toMarkup(): string {
|
||||
return escape(this.toText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the text node into a string
|
||||
* (representing the text itself).
|
||||
*/
|
||||
toText(): string {
|
||||
return this.text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This node represents a space, but may render as <mspace.../> or as text,
|
||||
* depending on the width.
|
||||
*/
|
||||
export class SpaceNode implements MathDomNode {
|
||||
width: number;
|
||||
character: string | null | undefined;
|
||||
|
||||
/**
|
||||
* Create a Space node with width given in CSS ems.
|
||||
*/
|
||||
constructor(width: number) {
|
||||
this.width = width;
|
||||
// See https://www.w3.org/TR/2000/WD-MathML2-20000328/chapter6.html
|
||||
// for a table of space-like characters. We use Unicode
|
||||
// representations instead of &LongNames; as it's not clear how to
|
||||
// make the latter via document.createTextNode.
|
||||
if (width >= 0.05555 && width <= 0.05556) {
|
||||
this.character = "\u200a"; //  
|
||||
} else if (width >= 0.1666 && width <= 0.1667) {
|
||||
this.character = "\u2009"; //  
|
||||
} else if (width >= 0.2222 && width <= 0.2223) {
|
||||
this.character = "\u2005"; //  
|
||||
} else if (width >= 0.2777 && width <= 0.2778) {
|
||||
this.character = "\u2005\u200a"; //   
|
||||
} else if (width >= -0.05556 && width <= -0.05555) {
|
||||
this.character = "\u200a\u2063"; // ​
|
||||
} else if (width >= -0.1667 && width <= -0.1666) {
|
||||
this.character = "\u2009\u2063"; // ​
|
||||
} else if (width >= -0.2223 && width <= -0.2222) {
|
||||
this.character = "\u205f\u2063"; // ​
|
||||
} else if (width >= -0.2778 && width <= -0.2777) {
|
||||
this.character = "\u2005\u2063"; // ​
|
||||
} else {
|
||||
this.character = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the math node into a MathML-namespaced DOM element.
|
||||
*/
|
||||
toNode(): Node {
|
||||
if (this.character) {
|
||||
return document.createTextNode(this.character);
|
||||
} else {
|
||||
const node = document.createElementNS(
|
||||
"http://www.w3.org/1998/Math/MathML", "mspace");
|
||||
node.setAttribute("width", makeEm(this.width));
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the math node into an HTML markup string.
|
||||
*/
|
||||
toMarkup(): string {
|
||||
if (this.character) {
|
||||
return `<mtext>${this.character}</mtext>`;
|
||||
} else {
|
||||
return `<mspace width="${makeEm(this.width)}"/>`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the math node into a string, similar to innerText.
|
||||
*/
|
||||
toText(): string {
|
||||
if (this.character) {
|
||||
return this.character;
|
||||
} else {
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
28
frontend/node_modules/katex/src/metrics/format_json.py
generated
vendored
Normal file
28
frontend/node_modules/katex/src/metrics/format_json.py
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
props = ['depth', 'height', 'italic', 'skew']
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == '--width':
|
||||
props.append('width')
|
||||
|
||||
data = json.load(sys.stdin)
|
||||
sys.stdout.write(
|
||||
"// This file is GENERATED by buildMetrics.sh. DO NOT MODIFY.\n")
|
||||
sep = "export default {\n "
|
||||
for font in sorted(data):
|
||||
sys.stdout.write(sep + json.dumps(font))
|
||||
sep = ": {\n "
|
||||
for glyph in sorted(data[font], key=int):
|
||||
sys.stdout.write(sep + json.dumps(glyph) + ": ")
|
||||
|
||||
values = [value if value != 0.0 else 0 for value in
|
||||
[data[font][glyph][key] for key in props]]
|
||||
|
||||
sys.stdout.write(json.dumps(values))
|
||||
sep = ",\n "
|
||||
sep = ",\n },\n "
|
||||
sys.stdout.write(",\n },\n};\n")
|
||||
108
frontend/node_modules/katex/src/unicodeSupOrSub.ts
generated
vendored
Normal file
108
frontend/node_modules/katex/src/unicodeSupOrSub.ts
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Helpers for Parser.js handling of Unicode (sub|super)script characters.
|
||||
|
||||
export const unicodeSubRegEx = /^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/;
|
||||
|
||||
export const uSubsAndSups: Readonly<Record<string, string>> = Object.freeze({
|
||||
'₊': '+',
|
||||
'₋': '-',
|
||||
'₌': '=',
|
||||
'₍': '(',
|
||||
'₎': ')',
|
||||
'₀': '0',
|
||||
'₁': '1',
|
||||
'₂': '2',
|
||||
'₃': '3',
|
||||
'₄': '4',
|
||||
'₅': '5',
|
||||
'₆': '6',
|
||||
'₇': '7',
|
||||
'₈': '8',
|
||||
'₉': '9',
|
||||
'\u2090': 'a',
|
||||
'\u2091': 'e',
|
||||
'\u2095': 'h',
|
||||
'\u1D62': 'i',
|
||||
'\u2C7C': 'j',
|
||||
'\u2096': 'k',
|
||||
'\u2097': 'l',
|
||||
'\u2098': 'm',
|
||||
'\u2099': 'n',
|
||||
'\u2092': 'o',
|
||||
'\u209A': 'p',
|
||||
'\u1D63': 'r',
|
||||
'\u209B': 's',
|
||||
'\u209C': 't',
|
||||
'\u1D64': 'u',
|
||||
'\u1D65': 'v',
|
||||
'\u2093': 'x',
|
||||
'\u1D66': 'β',
|
||||
'\u1D67': 'γ',
|
||||
'\u1D68': 'ρ',
|
||||
'\u1D69': '\u03d5',
|
||||
'\u1D6A': 'χ',
|
||||
'⁺': '+',
|
||||
'⁻': '-',
|
||||
'⁼': '=',
|
||||
'⁽': '(',
|
||||
'⁾': ')',
|
||||
'⁰': '0',
|
||||
'¹': '1',
|
||||
'²': '2',
|
||||
'³': '3',
|
||||
'⁴': '4',
|
||||
'⁵': '5',
|
||||
'⁶': '6',
|
||||
'⁷': '7',
|
||||
'⁸': '8',
|
||||
'⁹': '9',
|
||||
'\u1D2C': 'A',
|
||||
'\u1D2E': 'B',
|
||||
'\u1D30': 'D',
|
||||
'\u1D31': 'E',
|
||||
'\u1D33': 'G',
|
||||
'\u1D34': 'H',
|
||||
'\u1D35': 'I',
|
||||
'\u1D36': 'J',
|
||||
'\u1D37': 'K',
|
||||
'\u1D38': 'L',
|
||||
'\u1D39': 'M',
|
||||
'\u1D3A': 'N',
|
||||
'\u1D3C': 'O',
|
||||
'\u1D3E': 'P',
|
||||
'\u1D3F': 'R',
|
||||
'\u1D40': 'T',
|
||||
'\u1D41': 'U',
|
||||
'\u2C7D': 'V',
|
||||
'\u1D42': 'W',
|
||||
'\u1D43': 'a',
|
||||
'\u1D47': 'b',
|
||||
'\u1D9C': 'c',
|
||||
'\u1D48': 'd',
|
||||
'\u1D49': 'e',
|
||||
'\u1DA0': 'f',
|
||||
'\u1D4D': 'g',
|
||||
'\u02B0': 'h',
|
||||
'\u2071': 'i',
|
||||
'\u02B2': 'j',
|
||||
'\u1D4F': 'k',
|
||||
'\u02E1': 'l',
|
||||
'\u1D50': 'm',
|
||||
'\u207F': 'n',
|
||||
'\u1D52': 'o',
|
||||
'\u1D56': 'p',
|
||||
'\u02B3': 'r',
|
||||
'\u02E2': 's',
|
||||
'\u1D57': 't',
|
||||
'\u1D58': 'u',
|
||||
'\u1D5B': 'v',
|
||||
'\u02B7': 'w',
|
||||
'\u02E3': 'x',
|
||||
'\u02B8': 'y',
|
||||
'\u1DBB': 'z',
|
||||
'\u1D5D': 'β',
|
||||
'\u1D5E': 'γ',
|
||||
'\u1D5F': 'δ',
|
||||
'\u1D60': '\u03d5',
|
||||
'\u1D61': 'χ',
|
||||
'\u1DBF': 'θ',
|
||||
});
|
||||
Reference in New Issue
Block a user