完成世界书、骰子、apiconfig页面处理
This commit is contained in:
114
frontend/node_modules/katex/cli.js
generated
vendored
Normal file
114
frontend/node_modules/katex/cli.js
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env node
|
||||
// Simple CLI for KaTeX.
|
||||
// Reads TeX from stdin, outputs HTML to stdout.
|
||||
// To run this from the repository, you must first build KaTeX by running
|
||||
// `yarn` and `yarn build`.
|
||||
|
||||
/* eslint no-console:0 */
|
||||
|
||||
let katex;
|
||||
try {
|
||||
katex = require("./");
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"KaTeX could not import, likely because dist/katex.js is missing.");
|
||||
console.error("Please run 'yarn' and 'yarn build' before running");
|
||||
console.error("cli.js from the KaTeX repository.");
|
||||
console.error();
|
||||
throw e;
|
||||
}
|
||||
const {version} = require("./package.json");
|
||||
const fs = require("fs");
|
||||
|
||||
const {program} = require("commander");
|
||||
program.version(version);
|
||||
|
||||
for (const prop in katex.SETTINGS_SCHEMA) {
|
||||
if (katex.SETTINGS_SCHEMA.hasOwnProperty(prop)) {
|
||||
const opt = katex.SETTINGS_SCHEMA[prop];
|
||||
if (opt.cli !== false) {
|
||||
program.option(opt.cli || "--" + prop, opt.cliDescription ||
|
||||
opt.description, opt.cliProcessor, opt.cliDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
program.option("-f, --macro-file <path>",
|
||||
"Read macro definitions, one per line, from the given file.")
|
||||
.option("-i, --input <path>", "Read LaTeX input from the given file.")
|
||||
.option("-o, --output <path>", "Write html output to the given file.");
|
||||
|
||||
let options;
|
||||
|
||||
function readMacros() {
|
||||
if (options.macroFile) {
|
||||
fs.readFile(options.macroFile, "utf-8", function(err, data) {
|
||||
if (err) {throw err;}
|
||||
splitMacros(data.toString().split('\n'));
|
||||
});
|
||||
} else {
|
||||
splitMacros([]);
|
||||
}
|
||||
}
|
||||
|
||||
function splitMacros(macroStrings) {
|
||||
// Override macros from macro file (if any)
|
||||
// with macros from command line (if any)
|
||||
macroStrings = macroStrings.concat(options.macro);
|
||||
|
||||
const macros = {};
|
||||
|
||||
for (const m of macroStrings) {
|
||||
const i = m.search(":");
|
||||
if (i !== -1) {
|
||||
macros[m.substring(0, i).trim()] = m.substring(i + 1).trim();
|
||||
}
|
||||
}
|
||||
|
||||
options.macros = macros;
|
||||
readInput();
|
||||
}
|
||||
|
||||
function readInput() {
|
||||
let input = "";
|
||||
|
||||
if (options.input) {
|
||||
fs.readFile(options.input, "utf-8", function(err, data) {
|
||||
if (err) {throw err;}
|
||||
input = data.toString();
|
||||
writeOutput(input);
|
||||
});
|
||||
} else {
|
||||
process.stdin.on("data", function(chunk) {
|
||||
input += chunk.toString();
|
||||
});
|
||||
|
||||
process.stdin.on("end", function() {
|
||||
writeOutput(input);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function writeOutput(input) {
|
||||
// --format specifies the KaTeX output
|
||||
const outputFile = options.output;
|
||||
options.output = options.format;
|
||||
|
||||
const output = katex.renderToString(input, options) + "\n";
|
||||
|
||||
if (outputFile) {
|
||||
fs.writeFile(outputFile, output, function(err) {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(output);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main !== module) {
|
||||
module.exports = program;
|
||||
} else {
|
||||
options = program.parse(process.argv).opts();
|
||||
readMacros();
|
||||
}
|
||||
8
frontend/node_modules/katex/contrib/auto-render/README.md
generated
vendored
Normal file
8
frontend/node_modules/katex/contrib/auto-render/README.md
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Auto-render extension
|
||||
|
||||
This is an extension to automatically render all of the math inside of text. It
|
||||
searches all of the text nodes in a given element for the given delimiters, and
|
||||
renders the math in place.
|
||||
|
||||
See [Auto-render extension documentation](https://katex.org/docs/autorender.html)
|
||||
for more information.
|
||||
38
frontend/node_modules/katex/contrib/mathtex-script-type/README.md
generated
vendored
Normal file
38
frontend/node_modules/katex/contrib/mathtex-script-type/README.md
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# `math/tex` Custom Script Type Extension
|
||||
|
||||
This is an extension to automatically display code inside `script` tags with `type=math/tex` using KaTeX.
|
||||
This script type is commonly used by MathJax, so this can be used to support compatibility with MathJax.
|
||||
|
||||
### Usage
|
||||
|
||||
This extension isn't part of KaTeX proper, so the script should be separately
|
||||
included in the page, in addition to KaTeX.
|
||||
|
||||
Load the extension by adding the following line to your HTML file.
|
||||
|
||||
```html
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.38/dist/contrib/mathtex-script-type.min.js" integrity="sha384-Va76RKpsqLRTaW8meIebMfcIo7cxNDc0uKaZNSuZzckwzNtDa3Xf77LciJ0CAjIC" crossorigin="anonymous"></script>
|
||||
```
|
||||
You can download the script and use it locally, or from a local KaTeX installation instead.
|
||||
|
||||
For example, in the following simple page, we first load KaTeX as usual.
|
||||
Then, in the body, we use a `math/tex` script to typeset the equation `x+\sqrt{1-x^2}`.
|
||||
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.38/dist/katex.min.css" integrity="sha384-/L6i+LN3dyoaK2jYG5ZLh5u13cjdsPDcFOSNJeFBFa/KgVXR5kOfTdiN3ft1uMAq" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.38/dist/katex.min.js" integrity="sha384-H6s1ZrH2CKpFpqR680poRdStIRJGXty7fSkxAcIfxwl9iu6A4BOPtTk7vQ58Ovio" crossorigin="anonymous"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.38/dist/contrib/mathtex-script-type.min.js" integrity="sha384-Va76RKpsqLRTaW8meIebMfcIo7cxNDc0uKaZNSuZzckwzNtDa3Xf77LciJ0CAjIC" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="math/tex">x+\sqrt{1-x^2}</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
ECMAScript module is also available:
|
||||
```html
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/katex@0.16.38/dist/contrib/mathtex-script-type.mjs" integrity="sha384-NG25TLm9zCgNw3KKNK+Ks1i5zmDB4v17CYL2TVA06JcpsALdnFs/0TabnkhyjbQb" crossorigin="anonymous"></script>
|
||||
23
frontend/node_modules/katex/contrib/mhchem/README.md
generated
vendored
Normal file
23
frontend/node_modules/katex/contrib/mhchem/README.md
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# mhchem extension
|
||||
|
||||
This extension adds to KaTeX the `\ce` and `\pu` functions from the [mhchem](https://mhchem.github.io/MathJax-mhchem/) package.
|
||||
|
||||
### Usage
|
||||
|
||||
This extension isn't part of core KaTeX, so the script should be separately included. Write the following line into the HTML page's `<head>`. Place it *after* the line that calls `katex.js`, and if you make use of the [auto-render](https://katex.org/docs/autorender.html) extension, place it *before* the line that calls `auto-render.js`.
|
||||
|
||||
```html
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.38/dist/contrib/mhchem.min.js" integrity="sha384-fB8BH//9nBzROkMUsu/Dr35jWHIbnKesUo9rW0hfEgw8mZGnkAyBAjKX9F98OVuo" crossorigin="anonymous"></script>
|
||||
```
|
||||
|
||||
If you remove the `defer` attribute from this tag, then you must also remove the `defer` attribute from the `<script src="https://../katex.min.js">` tag.
|
||||
|
||||
### Syntax
|
||||
|
||||
See the [mhchem Manual](https://mhchem.github.io/MathJax-mhchem/) for a full explanation of the input syntax, with working examples. The manual also includes a demonstration box.
|
||||
|
||||
Note that old versions of `mhchem.sty` used `\cf` for chemical formula and `\ce` for chemical equations, but `\cf` has been deprecated in place of `\ce`. This extension supports only `\ce`. You can define a macro mapping `\cf` to `\ce` if needed.
|
||||
|
||||
### Browser Support
|
||||
|
||||
This extension has been tested on Chrome, Firefox, Opera, and Edge.
|
||||
305
frontend/node_modules/katex/dist/contrib/auto-render.js
generated
vendored
Normal file
305
frontend/node_modules/katex/dist/contrib/auto-render.js
generated
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory(require("katex"));
|
||||
else if(typeof define === 'function' && define.amd)
|
||||
define(["katex"], factory);
|
||||
else if(typeof exports === 'object')
|
||||
exports["renderMathInElement"] = factory(require("katex"));
|
||||
else
|
||||
root["renderMathInElement"] = factory(root["katex"]);
|
||||
})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__757__) {
|
||||
return /******/ (function() { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/******/ var __webpack_modules__ = ({
|
||||
|
||||
/***/ 757:
|
||||
/***/ (function(module) {
|
||||
|
||||
module.exports = __WEBPACK_EXTERNAL_MODULE__757__;
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||
/******/ if (cachedModule !== undefined) {
|
||||
/******/ return cachedModule.exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||
/******/ // no module.id needed
|
||||
/******/ // no module.loaded needed
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/compat get default export */
|
||||
/******/ !function() {
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function() { return module['default']; } :
|
||||
/******/ function() { return module; };
|
||||
/******/ __webpack_require__.d(getter, { a: getter });
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/ }();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ !function() {
|
||||
/******/ // define getter functions for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, definition) {
|
||||
/******/ for(var key in definition) {
|
||||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ }();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ !function() {
|
||||
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
|
||||
/******/ }();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
var __webpack_exports__ = {};
|
||||
|
||||
// EXPORTS
|
||||
__webpack_require__.d(__webpack_exports__, {
|
||||
"default": function() { return /* binding */ auto_render; }
|
||||
});
|
||||
|
||||
// EXTERNAL MODULE: external "katex"
|
||||
var external_katex_ = __webpack_require__(757);
|
||||
var external_katex_default = /*#__PURE__*/__webpack_require__.n(external_katex_);
|
||||
;// ./contrib/auto-render/splitAtDelimiters.ts
|
||||
/* eslint no-constant-condition:0 */
|
||||
|
||||
const findEndOfMath = function (delimiter, text, startIndex) {
|
||||
// Adapted from
|
||||
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
|
||||
let index = startIndex;
|
||||
let braceLevel = 0;
|
||||
const delimLength = delimiter.length;
|
||||
while (index < text.length) {
|
||||
const character = text[index];
|
||||
if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) {
|
||||
return index;
|
||||
} else if (character === "\\") {
|
||||
index++;
|
||||
} else if (character === "{") {
|
||||
braceLevel++;
|
||||
} else if (character === "}") {
|
||||
braceLevel--;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
const escapeRegex = function (string) {
|
||||
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
};
|
||||
const amsRegex = /^\\begin{/;
|
||||
const splitAtDelimiters = function (text, delimiters) {
|
||||
let index;
|
||||
const data = [];
|
||||
const regexLeft = new RegExp("(" + delimiters.map(x => escapeRegex(x.left)).join("|") + ")");
|
||||
while (true) {
|
||||
index = text.search(regexLeft);
|
||||
if (index === -1) {
|
||||
break;
|
||||
}
|
||||
if (index > 0) {
|
||||
data.push({
|
||||
type: "text",
|
||||
data: text.slice(0, index)
|
||||
});
|
||||
text = text.slice(index); // now text starts with delimiter
|
||||
}
|
||||
// ... so this always succeeds:
|
||||
const i = delimiters.findIndex(delim => text.startsWith(delim.left));
|
||||
index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
|
||||
if (index === -1) {
|
||||
break;
|
||||
}
|
||||
const rawData = text.slice(0, index + delimiters[i].right.length);
|
||||
const math = amsRegex.test(rawData) ? rawData : text.slice(delimiters[i].left.length, index);
|
||||
data.push({
|
||||
type: "math",
|
||||
data: math,
|
||||
rawData,
|
||||
display: delimiters[i].display
|
||||
});
|
||||
text = text.slice(index + delimiters[i].right.length);
|
||||
}
|
||||
if (text !== "") {
|
||||
data.push({
|
||||
type: "text",
|
||||
data: text
|
||||
});
|
||||
}
|
||||
return data;
|
||||
};
|
||||
/* harmony default export */ var auto_render_splitAtDelimiters = (splitAtDelimiters);
|
||||
;// ./contrib/auto-render/auto-render.ts
|
||||
/* eslint no-console:0 */
|
||||
|
||||
|
||||
|
||||
/* Note: optionsCopy is mutated by this method. If it is ever exposed in the
|
||||
* API, we should copy it before mutating.
|
||||
*/
|
||||
const renderMathInText = function (text, optionsCopy) {
|
||||
const data = auto_render_splitAtDelimiters(text, optionsCopy.delimiters);
|
||||
if (data.length === 1 && data[0].type === 'text') {
|
||||
// There is no formula in the text.
|
||||
// Let's return null which means there is no need to replace
|
||||
// the current text node with a new one.
|
||||
return null;
|
||||
}
|
||||
const fragment = document.createDocumentFragment();
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].type === "text") {
|
||||
fragment.appendChild(document.createTextNode(data[i].data));
|
||||
} else {
|
||||
const span = document.createElement("span");
|
||||
let math = data[i].data;
|
||||
// Override any display mode defined in the settings with that
|
||||
// defined by the text itself
|
||||
optionsCopy.displayMode = data[i].display;
|
||||
try {
|
||||
if (optionsCopy.preProcess) {
|
||||
math = optionsCopy.preProcess(math);
|
||||
}
|
||||
external_katex_default().render(math, span, optionsCopy);
|
||||
} catch (e) {
|
||||
if (!(e instanceof (external_katex_default()).ParseError)) {
|
||||
throw e;
|
||||
}
|
||||
optionsCopy.errorCallback("KaTeX auto-render: Failed to parse `" + data[i].data + "` with ", e);
|
||||
fragment.appendChild(document.createTextNode(data[i].rawData));
|
||||
continue;
|
||||
}
|
||||
fragment.appendChild(span);
|
||||
}
|
||||
}
|
||||
return fragment;
|
||||
};
|
||||
const renderElem = function (elem, optionsCopy) {
|
||||
for (let i = 0; i < elem.childNodes.length; i++) {
|
||||
const childNode = elem.childNodes[i];
|
||||
if (childNode.nodeType === 3) {
|
||||
var _childNode$textConten;
|
||||
// Text node
|
||||
// Concatenate all sibling text nodes.
|
||||
// Webkit browsers split very large text nodes into smaller ones,
|
||||
// so the delimiters may be split across different nodes.
|
||||
let textContentConcat = (_childNode$textConten = childNode.textContent) != null ? _childNode$textConten : "";
|
||||
let sibling = childNode.nextSibling;
|
||||
let nSiblings = 0;
|
||||
while (sibling && sibling.nodeType === Node.TEXT_NODE) {
|
||||
var _sibling$textContent;
|
||||
textContentConcat += (_sibling$textContent = sibling.textContent) != null ? _sibling$textContent : "";
|
||||
sibling = sibling.nextSibling;
|
||||
nSiblings++;
|
||||
}
|
||||
const frag = renderMathInText(textContentConcat, optionsCopy);
|
||||
if (frag) {
|
||||
// Remove extra text nodes
|
||||
for (let j = 0; j < nSiblings; j++) {
|
||||
childNode.nextSibling.remove();
|
||||
}
|
||||
i += frag.childNodes.length - 1;
|
||||
elem.replaceChild(frag, childNode);
|
||||
} else {
|
||||
// If the concatenated text does not contain math
|
||||
// the siblings will not either
|
||||
i += nSiblings;
|
||||
}
|
||||
} else if (childNode.nodeType === 1) {
|
||||
// Element node
|
||||
const className = ' ' + childNode.className + ' ';
|
||||
const shouldRender = !optionsCopy.ignoredTags.has(childNode.nodeName.toLowerCase()) && optionsCopy.ignoredClasses.every(x => !className.includes(' ' + x + ' '));
|
||||
if (shouldRender) {
|
||||
renderElem(childNode, optionsCopy);
|
||||
}
|
||||
}
|
||||
// Otherwise, it's something else, and ignore it.
|
||||
}
|
||||
};
|
||||
const renderMathInElement = function (elem, options) {
|
||||
if (!elem) {
|
||||
throw new Error("No element provided to render");
|
||||
}
|
||||
const optionsCopy = {};
|
||||
Object.assign(optionsCopy, options);
|
||||
|
||||
// default options
|
||||
optionsCopy.delimiters = optionsCopy.delimiters || [{
|
||||
left: "$$",
|
||||
right: "$$",
|
||||
display: true
|
||||
}, {
|
||||
left: "\\(",
|
||||
right: "\\)",
|
||||
display: false
|
||||
},
|
||||
// LaTeX uses $…$, but it ruins the display of normal `$` in text:
|
||||
// {left: "$", right: "$", display: false},
|
||||
// $ must come after $$
|
||||
|
||||
// Render AMS environments even if outside $$…$$ delimiters.
|
||||
{
|
||||
left: "\\begin{equation}",
|
||||
right: "\\end{equation}",
|
||||
display: true
|
||||
}, {
|
||||
left: "\\begin{align}",
|
||||
right: "\\end{align}",
|
||||
display: true
|
||||
}, {
|
||||
left: "\\begin{alignat}",
|
||||
right: "\\end{alignat}",
|
||||
display: true
|
||||
}, {
|
||||
left: "\\begin{gather}",
|
||||
right: "\\end{gather}",
|
||||
display: true
|
||||
}, {
|
||||
left: "\\begin{CD}",
|
||||
right: "\\end{CD}",
|
||||
display: true
|
||||
}, {
|
||||
left: "\\[",
|
||||
right: "\\]",
|
||||
display: true
|
||||
}];
|
||||
optionsCopy.ignoredTags = new Set((options == null ? void 0 : options.ignoredTags) || ["script", "noscript", "style", "textarea", "pre", "code", "option"]);
|
||||
optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || [];
|
||||
optionsCopy.errorCallback = optionsCopy.errorCallback || console.error;
|
||||
|
||||
// Enable sharing of global macros defined via `\gdef` between different
|
||||
// math elements within a single call to `renderMathInElement`.
|
||||
optionsCopy.macros = optionsCopy.macros || {};
|
||||
renderElem(elem, optionsCopy);
|
||||
};
|
||||
/* harmony default export */ var auto_render = (renderMathInElement);
|
||||
__webpack_exports__ = __webpack_exports__["default"];
|
||||
/******/ return __webpack_exports__;
|
||||
/******/ })()
|
||||
;
|
||||
});
|
||||
113
frontend/node_modules/katex/dist/contrib/copy-tex.js
generated
vendored
Normal file
113
frontend/node_modules/katex/dist/contrib/copy-tex.js
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory();
|
||||
else if(typeof define === 'function' && define.amd)
|
||||
define([], factory);
|
||||
else {
|
||||
var a = factory();
|
||||
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
|
||||
}
|
||||
})((typeof self !== 'undefined' ? self : this), function() {
|
||||
return /******/ (function() { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
var __webpack_exports__ = {};
|
||||
|
||||
;// ./contrib/copy-tex/katex2tex.ts
|
||||
// Set these to how you want inline and display math to be delimited.
|
||||
const defaultCopyDelimiters = {
|
||||
inline: ['$', '$'],
|
||||
// alternative: ['\(', '\)']
|
||||
display: ['$$', '$$'] // alternative: ['\[', '\]']
|
||||
};
|
||||
|
||||
// Replace .katex elements with their TeX source (<annotation> element).
|
||||
// Modifies fragment in-place. Useful for writing your own 'copy' handler,
|
||||
// as in copy-tex.js.
|
||||
function katexReplaceWithTex(fragment, copyDelimiters) {
|
||||
if (copyDelimiters === void 0) {
|
||||
copyDelimiters = defaultCopyDelimiters;
|
||||
}
|
||||
// Remove .katex-html blocks that are preceded by .katex-mathml blocks
|
||||
// (which will get replaced below).
|
||||
const katexHtml = fragment.querySelectorAll('.katex-mathml + .katex-html');
|
||||
for (let i = 0; i < katexHtml.length; i++) {
|
||||
const element = katexHtml[i];
|
||||
if (element.remove) {
|
||||
element.remove();
|
||||
} else if (element.parentNode) {
|
||||
element.parentNode.removeChild(element);
|
||||
}
|
||||
}
|
||||
// Replace .katex-mathml elements with their annotation (TeX source)
|
||||
// descendant, with inline delimiters.
|
||||
const katexMathml = fragment.querySelectorAll('.katex-mathml');
|
||||
for (let i = 0; i < katexMathml.length; i++) {
|
||||
const element = katexMathml[i];
|
||||
const texSource = element.querySelector('annotation');
|
||||
if (texSource) {
|
||||
if (element.replaceWith) {
|
||||
element.replaceWith(texSource);
|
||||
} else if (element.parentNode) {
|
||||
element.parentNode.replaceChild(texSource, element);
|
||||
}
|
||||
texSource.innerHTML = copyDelimiters.inline[0] + texSource.innerHTML + copyDelimiters.inline[1];
|
||||
}
|
||||
}
|
||||
// Switch display math to display delimiters.
|
||||
const displays = fragment.querySelectorAll('.katex-display annotation');
|
||||
for (let i = 0; i < displays.length; i++) {
|
||||
const element = displays[i];
|
||||
element.innerHTML = copyDelimiters.display[0] + element.innerHTML.substr(copyDelimiters.inline[0].length, element.innerHTML.length - copyDelimiters.inline[0].length - copyDelimiters.inline[1].length) + copyDelimiters.display[1];
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
/* harmony default export */ var katex2tex = (katexReplaceWithTex);
|
||||
;// ./contrib/copy-tex/copy-tex.ts
|
||||
|
||||
|
||||
// Return <div class="katex"> element containing node, or null if not found.
|
||||
function closestKatex(node) {
|
||||
// If node is a Text Node, for example, go up to containing Element,
|
||||
// where we can apply the `closest` method.
|
||||
const element = node instanceof Element ? node : node.parentElement;
|
||||
return element && element.closest('.katex');
|
||||
}
|
||||
|
||||
// Global copy handler to modify behavior on/within .katex elements.
|
||||
document.addEventListener('copy', function (event) {
|
||||
const selection = window.getSelection();
|
||||
if (!selection || selection.isCollapsed || !event.clipboardData) {
|
||||
return; // default action OK if selection is empty or unchangeable
|
||||
}
|
||||
const clipboardData = event.clipboardData;
|
||||
const range = selection.getRangeAt(0);
|
||||
|
||||
// When start point is within a formula, expand to entire formula.
|
||||
const startKatex = closestKatex(range.startContainer);
|
||||
if (startKatex) {
|
||||
range.setStartBefore(startKatex);
|
||||
}
|
||||
|
||||
// Similarly, when end point is within a formula, expand to entire formula.
|
||||
const endKatex = closestKatex(range.endContainer);
|
||||
if (endKatex) {
|
||||
range.setEndAfter(endKatex);
|
||||
}
|
||||
const fragment = range.cloneContents();
|
||||
if (!fragment.querySelector('.katex-mathml')) {
|
||||
return; // default action OK if no .katex-mathml elements
|
||||
}
|
||||
const htmlContents = Array.prototype.map.call(fragment.childNodes, el => el instanceof Text ? el.textContent : el.outerHTML).join('');
|
||||
|
||||
// Preserve usual HTML copy/paste behavior.
|
||||
clipboardData.setData('text/html', htmlContents);
|
||||
// Rewrite plain-text version.
|
||||
clipboardData.setData('text/plain', katex2tex(fragment).textContent);
|
||||
// Prevent normal copy handling.
|
||||
event.preventDefault();
|
||||
});
|
||||
__webpack_exports__ = __webpack_exports__["default"];
|
||||
/******/ return __webpack_exports__;
|
||||
/******/ })()
|
||||
;
|
||||
});
|
||||
85
frontend/node_modules/katex/dist/contrib/copy-tex.mjs
generated
vendored
Normal file
85
frontend/node_modules/katex/dist/contrib/copy-tex.mjs
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// Set these to how you want inline and display math to be delimited.
|
||||
var defaultCopyDelimiters = {
|
||||
inline: ['$', '$'],
|
||||
// alternative: ['\(', '\)']
|
||||
display: ['$$', '$$'] // alternative: ['\[', '\]']
|
||||
};
|
||||
// Replace .katex elements with their TeX source (<annotation> element).
|
||||
// Modifies fragment in-place. Useful for writing your own 'copy' handler,
|
||||
// as in copy-tex.js.
|
||||
function katexReplaceWithTex(fragment, copyDelimiters) {
|
||||
if (copyDelimiters === void 0) {
|
||||
copyDelimiters = defaultCopyDelimiters;
|
||||
}
|
||||
// Remove .katex-html blocks that are preceded by .katex-mathml blocks
|
||||
// (which will get replaced below).
|
||||
var katexHtml = fragment.querySelectorAll('.katex-mathml + .katex-html');
|
||||
for (var i = 0; i < katexHtml.length; i++) {
|
||||
var element = katexHtml[i];
|
||||
if (element.remove) {
|
||||
element.remove();
|
||||
} else if (element.parentNode) {
|
||||
element.parentNode.removeChild(element);
|
||||
}
|
||||
}
|
||||
// Replace .katex-mathml elements with their annotation (TeX source)
|
||||
// descendant, with inline delimiters.
|
||||
var katexMathml = fragment.querySelectorAll('.katex-mathml');
|
||||
for (var _i = 0; _i < katexMathml.length; _i++) {
|
||||
var _element = katexMathml[_i];
|
||||
var texSource = _element.querySelector('annotation');
|
||||
if (texSource) {
|
||||
if (_element.replaceWith) {
|
||||
_element.replaceWith(texSource);
|
||||
} else if (_element.parentNode) {
|
||||
_element.parentNode.replaceChild(texSource, _element);
|
||||
}
|
||||
texSource.innerHTML = copyDelimiters.inline[0] + texSource.innerHTML + copyDelimiters.inline[1];
|
||||
}
|
||||
}
|
||||
// Switch display math to display delimiters.
|
||||
var displays = fragment.querySelectorAll('.katex-display annotation');
|
||||
for (var _i2 = 0; _i2 < displays.length; _i2++) {
|
||||
var _element2 = displays[_i2];
|
||||
_element2.innerHTML = copyDelimiters.display[0] + _element2.innerHTML.substr(copyDelimiters.inline[0].length, _element2.innerHTML.length - copyDelimiters.inline[0].length - copyDelimiters.inline[1].length) + copyDelimiters.display[1];
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
|
||||
// Return <div class="katex"> element containing node, or null if not found.
|
||||
function closestKatex(node) {
|
||||
// If node is a Text Node, for example, go up to containing Element,
|
||||
// where we can apply the `closest` method.
|
||||
var element = node instanceof Element ? node : node.parentElement;
|
||||
return element && element.closest('.katex');
|
||||
}
|
||||
// Global copy handler to modify behavior on/within .katex elements.
|
||||
document.addEventListener('copy', function (event) {
|
||||
var selection = window.getSelection();
|
||||
if (!selection || selection.isCollapsed || !event.clipboardData) {
|
||||
return; // default action OK if selection is empty or unchangeable
|
||||
}
|
||||
var clipboardData = event.clipboardData;
|
||||
var range = selection.getRangeAt(0);
|
||||
// When start point is within a formula, expand to entire formula.
|
||||
var startKatex = closestKatex(range.startContainer);
|
||||
if (startKatex) {
|
||||
range.setStartBefore(startKatex);
|
||||
}
|
||||
// Similarly, when end point is within a formula, expand to entire formula.
|
||||
var endKatex = closestKatex(range.endContainer);
|
||||
if (endKatex) {
|
||||
range.setEndAfter(endKatex);
|
||||
}
|
||||
var fragment = range.cloneContents();
|
||||
if (!fragment.querySelector('.katex-mathml')) {
|
||||
return; // default action OK if no .katex-mathml elements
|
||||
}
|
||||
var htmlContents = Array.prototype.map.call(fragment.childNodes, el => el instanceof Text ? el.textContent : el.outerHTML).join('');
|
||||
// Preserve usual HTML copy/paste behavior.
|
||||
clipboardData.setData('text/html', htmlContents);
|
||||
// Rewrite plain-text version.
|
||||
clipboardData.setData('text/plain', katexReplaceWithTex(fragment).textContent);
|
||||
// Prevent normal copy handling.
|
||||
event.preventDefault();
|
||||
});
|
||||
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_AMS-Regular.woff2
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_AMS-Regular.woff2
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff2
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Caligraphic-Regular.woff2
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Bold.woff
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Bold.woff
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Bold.woff2
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Bold.woff2
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Regular.ttf
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Regular.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Regular.woff
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Fraktur-Regular.woff
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Main-Bold.ttf
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Main-Bold.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Main-BoldItalic.ttf
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Main-BoldItalic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Main-Regular.woff2
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Main-Regular.woff2
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Math-BoldItalic.ttf
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Math-BoldItalic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Math-BoldItalic.woff2
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Math-BoldItalic.woff2
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Math-Italic.woff
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Math-Italic.woff
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_SansSerif-Bold.ttf
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_SansSerif-Bold.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Script-Regular.woff2
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Script-Regular.woff2
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size1-Regular.ttf
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size1-Regular.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size1-Regular.woff
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size1-Regular.woff
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size1-Regular.woff2
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size1-Regular.woff2
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size2-Regular.woff
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size2-Regular.woff
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size3-Regular.woff
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Size3-Regular.woff
generated
vendored
Normal file
Binary file not shown.
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Typewriter-Regular.woff
generated
vendored
Normal file
BIN
frontend/node_modules/katex/dist/fonts/KaTeX_Typewriter-Regular.woff
generated
vendored
Normal file
Binary file not shown.
1
frontend/node_modules/katex/dist/katex-swap.min.css
generated
vendored
Normal file
1
frontend/node_modules/katex/dist/katex-swap.min.css
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1237
frontend/node_modules/katex/dist/katex.css
generated
vendored
Normal file
1237
frontend/node_modules/katex/dist/katex.css
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/katex/dist/katex.min.css
generated
vendored
Normal file
1
frontend/node_modules/katex/dist/katex.min.css
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/katex/dist/katex.min.js
generated
vendored
Normal file
1
frontend/node_modules/katex/dist/katex.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
16461
frontend/node_modules/katex/dist/katex.mjs
generated
vendored
Normal file
16461
frontend/node_modules/katex/dist/katex.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
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': 'θ',
|
||||
});
|
||||
259
frontend/node_modules/katex/types/katex.d.ts
generated
vendored
Normal file
259
frontend/node_modules/katex/types/katex.d.ts
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
// Adapted from
|
||||
// - https://katex.org/docs/options
|
||||
// - https://katex.org/docs/api
|
||||
// - https://katex.org/docs/error
|
||||
// for v0.16.11 on 2024/12/01
|
||||
// with some references from https://www.npmjs.com/package/@types/katex
|
||||
|
||||
/**
|
||||
* For the `trust` option in `KatexOptions`, a custom function
|
||||
* `handler(context)` can be provided to customize behavior depending on the
|
||||
* context (command, arguments e.g. a URL, etc.)
|
||||
* @see https://katex.org/docs/options
|
||||
*/
|
||||
export type TrustContext =
|
||||
| { command: "\\url", url: string, protocol?: string }
|
||||
| { command: "\\href", url: string, protocol?: string }
|
||||
| { command: "\\includegraphics", url: string, protocol?: string }
|
||||
| { command: "\\htmlClass", class: string }
|
||||
| { command: "\\htmlId", id: string }
|
||||
| { command: "\\htmlStyle", style: string }
|
||||
| { command: "\\htmlData", attributes: Record<string, string> }
|
||||
|
||||
|
||||
export type Catcodes = Record<string, number>;
|
||||
|
||||
export interface Lexer {
|
||||
input: string;
|
||||
tokenRegex: RegExp;
|
||||
settings: Required<KatexOptions>;
|
||||
catcodes: Catcodes;
|
||||
}
|
||||
|
||||
export interface SourceLocation {
|
||||
start: number;
|
||||
end: number;
|
||||
lexer: Lexer;
|
||||
}
|
||||
|
||||
export interface Token {
|
||||
text: string;
|
||||
loc: SourceLocation | undefined;
|
||||
noexpand?: boolean;
|
||||
treatAsRelax?: boolean;
|
||||
}
|
||||
|
||||
|
||||
export type StrictFunction = (
|
||||
errorCode:
|
||||
| "unknownSymbol"
|
||||
| "unicodeTextInMathMode"
|
||||
| "mathVsTextUnits"
|
||||
| "commentAtEnd"
|
||||
| "htmlExtension"
|
||||
| "newLineInDisplayMode",
|
||||
errorMsg: string,
|
||||
token: Token,
|
||||
) => boolean | "error" | "warn" | "ignore" | undefined;
|
||||
|
||||
|
||||
/**
|
||||
* Options for `katex.render` and `katex.renderToString`.
|
||||
* @see https://katex.org/docs/options
|
||||
*/
|
||||
export interface KatexOptions {
|
||||
/**
|
||||
* If `true` the math will be rendered in display mode.
|
||||
* If `false` the math will be rendered in inline mode.
|
||||
* @see https://katex.org/docs/options
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
displayMode?: boolean;
|
||||
/**
|
||||
* Determines the markup language of the output. The valid choices are:
|
||||
* - `html`: Outputs KaTeX in HTML only.
|
||||
* - `mathml`: Outputs KaTeX in MathML only.
|
||||
* - `htmlAndMathml`: Outputs HTML for visual rendering and includes MathML
|
||||
* for accessibility.
|
||||
*
|
||||
* @default "htmlAndMathml"
|
||||
*/
|
||||
output?: "html" | "mathml" | "htmlAndMathml";
|
||||
/**
|
||||
* If `true`, display math has `\tag`s rendered on the left instead of the
|
||||
* right, like `\usepackage[leqno]{amsmath}` in LaTeX.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
leqno?: boolean;
|
||||
/**
|
||||
* If `true`, display math renders flush left with a `2em` left margin,
|
||||
* like `\documentclass[fleqn]` in LaTeX with the `amsmath` package.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
fleqn?: boolean;
|
||||
/**
|
||||
* If `true`, KaTeX will throw a `ParseError` when it encounters an
|
||||
* unsupported command or invalid LaTeX.
|
||||
* If `false`, KaTeX will render unsupported commands as text, and render
|
||||
* invalid LaTeX as its source code with hover text giving the error, in
|
||||
* the color given by `errorColor`.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
throwOnError?: boolean;
|
||||
/**
|
||||
* A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option
|
||||
* determines the color that unsupported commands and invalid LaTeX are
|
||||
* rendered in when `throwOnError` is set to `false`.
|
||||
*
|
||||
* @default "#cc0000"
|
||||
*/
|
||||
errorColor?: string;
|
||||
/**
|
||||
* A collection of custom macros.
|
||||
* @see https://katex.org/docs/options
|
||||
*/
|
||||
macros?: Record<string, string | object | ((macroExpander:object)
|
||||
=> string | object)>;
|
||||
/**
|
||||
* Specifies a minimum thickness, in ems, for fraction lines, `\sqrt` top
|
||||
* lines, `{array}` vertical lines, `\hline`, `\hdashline`, `\underline`,
|
||||
* `\overline`, and the borders of `\fbox`, `\boxed`, and `\fcolorbox`.
|
||||
* The usual value for these items is `0.04`, so for `minRuleThickness`
|
||||
* to be effective it should probably take a value slightly above `0.04`,
|
||||
* say `0.05` or `0.06`. Negative values will be ignored.
|
||||
*/
|
||||
minRuleThickness?: number;
|
||||
/**
|
||||
* In early versions of both KaTeX (<0.8.0) and MathJax, the `\color`
|
||||
* function expected the content to be a function argument, as in
|
||||
* `\color{blue}{hello}`. In current KaTeX, `\color` is a switch, as in
|
||||
* `\color{blue}` hello. This matches LaTeX behavior. If you want the old
|
||||
* `\color` behavior, set option colorIsTextColor to true.
|
||||
*/
|
||||
colorIsTextColor?: boolean;
|
||||
/**
|
||||
* All user-specified sizes, e.g. in `\rule{500em}{500em}`, will be capped
|
||||
* to `maxSize` ems. If set to `Infinity` (the default), users can make
|
||||
* elements and spaces arbitrarily large.
|
||||
*
|
||||
* @default Infinity
|
||||
*/
|
||||
maxSize?: number;
|
||||
/**
|
||||
* Limit the number of macro expansions to the specified number, to prevent
|
||||
* e.g. infinite macro loops. `\edef` expansion counts all expanded tokens.
|
||||
* If set to `Infinity`, the macro expander will try to fully expand as in
|
||||
* LaTeX.
|
||||
*
|
||||
* @default 1000
|
||||
*/
|
||||
maxExpand?: number;
|
||||
/**
|
||||
* If `false` or `"ignore"`, allow features that make writing LaTeX
|
||||
* convenient but are not actually supported by (Xe)LaTeX
|
||||
* (similar to MathJax).
|
||||
* If `true` or `"error"` (LaTeX faithfulness mode), throw an error for any
|
||||
* such transgressions.
|
||||
* If `"warn"` (the default), warn about such behavior via `console.warn`.
|
||||
* Provide a custom function `handler(errorCode, errorMsg, token)` to
|
||||
* customize behavior depending on the type of transgression (summarized by
|
||||
* the string code `errorCode` and detailed in `errorMsg`); this function
|
||||
* can also return `"ignore"`, `"error"`, or `"warn"` to use a built-in
|
||||
* behavior.
|
||||
* @see https://katex.org/docs/options
|
||||
*
|
||||
* @default "warn"
|
||||
*/
|
||||
strict?:
|
||||
| boolean
|
||||
| "ignore" | "warn" | "error"
|
||||
| StrictFunction;
|
||||
/**
|
||||
* If `false` (do not trust input), prevent any commands like
|
||||
* `\includegraphics` that could enable adverse behavior, rendering them
|
||||
* instead in `errorColor`.
|
||||
* If `true` (trust input), allow all such commands.
|
||||
* Provide a custom function `handler(context)` to customize behavior
|
||||
* depending on the context (command, arguments e.g. a URL, etc.).
|
||||
* @see https://katex.org/docs/options
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
trust?: boolean | ((context: TrustContext) => boolean);
|
||||
/**
|
||||
* Run KaTeX code in the global group. As a consequence, macros defined at
|
||||
* the top level by `\def` and `\newcommand` are added to the macros
|
||||
* argument and can be used in subsequent render calls. In LaTeX,
|
||||
* constructs such as `\begin{equation}` and `$$` create a local group and
|
||||
* prevent definitions other than `\gdef` from becoming visible outside of
|
||||
* those blocks, so this is KaTeX's default behavior.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
globalGroup?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* In-browser rendering
|
||||
*
|
||||
* Call the `render` function with a TeX expression and a DOM element to
|
||||
* render into.
|
||||
*
|
||||
* @param {string} tex A TeX expression.
|
||||
* @param {HTMLElement} element A HTML DOM element.
|
||||
* @param {KatexOptions} options An options object.
|
||||
* @returns {void}
|
||||
* @see https://katex.org/docs/api
|
||||
*/
|
||||
export function render(
|
||||
tex: string,
|
||||
element: HTMLElement,
|
||||
options?: KatexOptions,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* Server-side rendering or rendering to a string
|
||||
*
|
||||
* Use the `renderToString` function to generate HTML on the server or to
|
||||
* generate an HTML string of the rendered math.
|
||||
*
|
||||
* @param {string} tex A TeX expression.
|
||||
* @param {KatexOptions} options An options object.
|
||||
* @returns {string} The HTML string of the rendered math.
|
||||
* @see https://katex.org/docs/api
|
||||
*/
|
||||
export function renderToString(tex: string, options?: KatexOptions): string;
|
||||
|
||||
/**
|
||||
* If KaTeX encounters an error (invalid or unsupported LaTeX) and
|
||||
* `throwOnError` hasn't been set to `false`, then `katex.render` and
|
||||
* `katex.renderToString` will throw an exception of type
|
||||
* `ParseError`. The message in this error includes some of the LaTeX source
|
||||
* code, so needs to be escaped if you want to render it to HTML.
|
||||
* @see https://katex.org/docs/error
|
||||
*/
|
||||
export class ParseError implements Error {
|
||||
constructor(message: string, token?: object);
|
||||
name: "ParseError";
|
||||
position: number;
|
||||
length: number;
|
||||
rawMessage: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export const version: string;
|
||||
|
||||
export as namespace katex;
|
||||
|
||||
declare const katex: {
|
||||
version: string;
|
||||
render: typeof render;
|
||||
renderToString: typeof renderToString;
|
||||
ParseError: typeof ParseError;
|
||||
};
|
||||
|
||||
export default katex;
|
||||
Reference in New Issue
Block a user