mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-10 21:48:41 +00:00
Adds math commands, HTML rendering, and screenshotter tests.
This is part 2 of 3. Part 1 added new fonts metrics. Part 2 will add MathML support and unit tests.
This commit is contained in:
committed by
Kevin Barabash
parent
f32d615813
commit
fd2d58fd80
@@ -6,9 +6,9 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is the main options class. It contains the style, size, and color of the
|
||||
* current parse level. It also contains the style and size of the parent parse
|
||||
* level, so size changes can be handled efficiently.
|
||||
* This is the main options class. It contains the style, size, color and font
|
||||
* of the current parse level. It also contains the style and size of the parent
|
||||
* parse level, so size changes can be handled efficiently.
|
||||
*
|
||||
* Each of the `.with*` and `.reset` functions passes its current style and size
|
||||
* as the parentStyle and parentSize of the new options class, so parent
|
||||
@@ -19,6 +19,7 @@ function Options(data) {
|
||||
this.color = data.color;
|
||||
this.size = data.size;
|
||||
this.phantom = data.phantom;
|
||||
this.font = data.font;
|
||||
|
||||
if (data.parentStyle === undefined) {
|
||||
this.parentStyle = data.style;
|
||||
@@ -44,7 +45,8 @@ Options.prototype.extend = function(extension) {
|
||||
color: this.color,
|
||||
parentStyle: this.style,
|
||||
parentSize: this.size,
|
||||
phantom: this.phantom
|
||||
phantom: this.phantom,
|
||||
font: this.font
|
||||
};
|
||||
|
||||
for (var key in extension) {
|
||||
@@ -92,6 +94,15 @@ Options.prototype.withPhantom = function() {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new options objects with the give font.
|
||||
*/
|
||||
Options.prototype.withFont = function(font) {
|
||||
return this.extend({
|
||||
font: font
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new options object with the same style, size, and color. This is
|
||||
* used so that parent style and size changes are handled correctly.
|
||||
|
@@ -6,6 +6,26 @@
|
||||
var domTree = require("./domTree");
|
||||
var fontMetrics = require("./fontMetrics");
|
||||
var symbols = require("./symbols");
|
||||
var utils = require("./utils");
|
||||
|
||||
var greekCapitals = [
|
||||
"\\Gamma",
|
||||
"\\Delta",
|
||||
"\\Theta",
|
||||
"\\Lambda",
|
||||
"\\Xi",
|
||||
"\\Pi",
|
||||
"\\Sigma",
|
||||
"\\Upsilon",
|
||||
"\\Phi",
|
||||
"\\Psi",
|
||||
"\\Omega"
|
||||
];
|
||||
|
||||
var dotlessLetters = [
|
||||
"\u0131", // dotless i, \imath
|
||||
"\u0237" // dotless j, \jmath
|
||||
];
|
||||
|
||||
/**
|
||||
* Makes a symbolNode after translation via the list of symbols in symbols.js.
|
||||
@@ -41,17 +61,10 @@ var makeSymbol = function(value, style, mode, color, classes) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a symbol in the italic math font.
|
||||
* Makes a symbol in Main-Regular or AMS-Regular.
|
||||
* Used for rel, bin, open, close, inner, and punct.
|
||||
*/
|
||||
var mathit = function(value, mode, color, classes) {
|
||||
return makeSymbol(
|
||||
value, "Math-Italic", mode, color, classes.concat(["mathit"]));
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a symbol in the upright roman font.
|
||||
*/
|
||||
var mathrm = function(value, mode, color, classes) {
|
||||
var mathsym = function(value, mode, color, classes) {
|
||||
// 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
|
||||
@@ -66,6 +79,67 @@ var mathrm = function(value, mode, color, classes) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a symbol in the default font for mathords and textords.
|
||||
*/
|
||||
var mathDefault = function(value, mode, color, classes, type) {
|
||||
if (type === "mathord") {
|
||||
return mathit(value, mode, color, classes);
|
||||
} else if (type === "textord") {
|
||||
return makeSymbol(
|
||||
value, "Main-Regular", mode, color, classes.concat(["mathrm"]));
|
||||
} else {
|
||||
throw new Error("unexpected type: " + type + " in mathDefault");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a symbol in the italic math font.
|
||||
*/
|
||||
var mathit = function(value, mode, color, classes) {
|
||||
if (/[0-9]/.test(value.charAt(0)) ||
|
||||
// glyphs for \imath and \jmath do not exist in Math-Italic so we
|
||||
// need to use Main-Italic instead
|
||||
utils.contains(dotlessLetters, value) ||
|
||||
utils.contains(greekCapitals, value)) {
|
||||
return makeSymbol(
|
||||
value, "Main-Italic", mode, color, classes.concat(["mainit"]));
|
||||
} else {
|
||||
return makeSymbol(
|
||||
value, "Math-Italic", mode, color, classes.concat(["mathit"]));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes either a mathord or textord in the correct font and color.
|
||||
*/
|
||||
var makeOrd = function(group, options, type) {
|
||||
var mode = group.mode;
|
||||
var value = group.value;
|
||||
if (symbols[mode][value] && symbols[mode][value].replace) {
|
||||
value = symbols[mode][value].replace;
|
||||
}
|
||||
|
||||
var classes = ["mord"];
|
||||
var color = options.getColor();
|
||||
|
||||
var font = options.font;
|
||||
if (font) {
|
||||
if (font === "mathit" || utils.contains(dotlessLetters, value)) {
|
||||
return mathit(value, mode, color, classes);
|
||||
} else {
|
||||
var fontName = fontMap[font].fontName;
|
||||
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
||||
return makeSymbol(value, fontName, mode, color, classes.concat([font]));
|
||||
} else {
|
||||
return mathDefault(value, mode, color, classes, type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return mathDefault(value, mode, color, classes, type);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the height, depth, and maxFontSize of an element based on its
|
||||
* children.
|
||||
@@ -312,13 +386,61 @@ var spacingFunctions = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
var fontMap = {
|
||||
// styles
|
||||
"mathbf": {
|
||||
variant: "bold",
|
||||
fontName: "Main-Bold"
|
||||
},
|
||||
"mathrm": {
|
||||
variant: "normal",
|
||||
fontName: "Main-Regular"
|
||||
},
|
||||
|
||||
// "mathit" is missing because it requires the use of two fonts: Main-Italic
|
||||
// and Math-Italic. This is handled by a special case in makeOrd which ends
|
||||
// up calling mathit.
|
||||
|
||||
// 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"
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
makeSymbol: makeSymbol,
|
||||
mathit: mathit,
|
||||
mathrm: mathrm,
|
||||
mathsym: mathsym,
|
||||
makeSpan: makeSpan,
|
||||
makeFragment: makeFragment,
|
||||
makeVList: makeVList,
|
||||
makeOrd: makeOrd,
|
||||
sizingMultiplier: sizingMultiplier,
|
||||
spacingFunctions: spacingFunctions
|
||||
};
|
||||
|
@@ -171,13 +171,11 @@ var makeNullDelimiter = function(options) {
|
||||
*/
|
||||
var groupTypes = {
|
||||
mathord: function(group, options, prev) {
|
||||
return buildCommon.mathit(
|
||||
group.value, group.mode, options.getColor(), ["mord"]);
|
||||
return buildCommon.makeOrd(group, options, "mathord");
|
||||
},
|
||||
|
||||
textord: function(group, options, prev) {
|
||||
return buildCommon.mathrm(
|
||||
group.value, group.mode, options.getColor(), ["mord"]);
|
||||
return buildCommon.makeOrd(group, options, "textord");
|
||||
},
|
||||
|
||||
bin: function(group, options, prev) {
|
||||
@@ -199,32 +197,32 @@ var groupTypes = {
|
||||
className = "mord";
|
||||
}
|
||||
|
||||
return buildCommon.mathrm(
|
||||
return buildCommon.mathsym(
|
||||
group.value, group.mode, options.getColor(), [className]);
|
||||
},
|
||||
|
||||
rel: function(group, options, prev) {
|
||||
return buildCommon.mathrm(
|
||||
return buildCommon.mathsym(
|
||||
group.value, group.mode, options.getColor(), ["mrel"]);
|
||||
},
|
||||
|
||||
open: function(group, options, prev) {
|
||||
return buildCommon.mathrm(
|
||||
return buildCommon.mathsym(
|
||||
group.value, group.mode, options.getColor(), ["mopen"]);
|
||||
},
|
||||
|
||||
close: function(group, options, prev) {
|
||||
return buildCommon.mathrm(
|
||||
return buildCommon.mathsym(
|
||||
group.value, group.mode, options.getColor(), ["mclose"]);
|
||||
},
|
||||
|
||||
inner: function(group, options, prev) {
|
||||
return buildCommon.mathrm(
|
||||
return buildCommon.mathsym(
|
||||
group.value, group.mode, options.getColor(), ["minner"]);
|
||||
},
|
||||
|
||||
punct: function(group, options, prev) {
|
||||
return buildCommon.mathrm(
|
||||
return buildCommon.mathsym(
|
||||
group.value, group.mode, options.getColor(), ["mpunct"]);
|
||||
},
|
||||
|
||||
@@ -628,7 +626,7 @@ var groupTypes = {
|
||||
// into appropriate outputs.
|
||||
return makeSpan(
|
||||
["mord", "mspace"],
|
||||
[buildCommon.mathrm(group.value, group.mode)]
|
||||
[buildCommon.mathsym(group.value, group.mode)]
|
||||
);
|
||||
} else {
|
||||
// Other kinds of spaces are of arbitrary width. We use CSS to
|
||||
@@ -712,7 +710,7 @@ var groupTypes = {
|
||||
// operators, like \limsup
|
||||
var output = [];
|
||||
for (var i = 1; i < group.value.body.length; i++) {
|
||||
output.push(buildCommon.mathrm(group.value.body[i], group.mode));
|
||||
output.push(buildCommon.mathsym(group.value.body[i], group.mode));
|
||||
}
|
||||
base = makeSpan(["mop"], output, options.getColor());
|
||||
}
|
||||
@@ -819,26 +817,26 @@ var groupTypes = {
|
||||
// good, but the offsets for the T, E, and X were taken from the
|
||||
// definition of \TeX in TeX (see TeXbook pg. 356)
|
||||
var k = makeSpan(
|
||||
["k"], [buildCommon.mathrm("K", group.mode)]);
|
||||
["k"], [buildCommon.mathsym("K", group.mode)]);
|
||||
var a = makeSpan(
|
||||
["a"], [buildCommon.mathrm("A", group.mode)]);
|
||||
["a"], [buildCommon.mathsym("A", group.mode)]);
|
||||
|
||||
a.height = (a.height + 0.2) * 0.75;
|
||||
a.depth = (a.height - 0.2) * 0.75;
|
||||
|
||||
var t = makeSpan(
|
||||
["t"], [buildCommon.mathrm("T", group.mode)]);
|
||||
["t"], [buildCommon.mathsym("T", group.mode)]);
|
||||
var e = makeSpan(
|
||||
["e"], [buildCommon.mathrm("E", group.mode)]);
|
||||
["e"], [buildCommon.mathsym("E", group.mode)]);
|
||||
|
||||
e.height = (e.height - 0.2155);
|
||||
e.depth = (e.depth + 0.2155);
|
||||
|
||||
var x = makeSpan(
|
||||
["x"], [buildCommon.mathrm("X", group.mode)]);
|
||||
["x"], [buildCommon.mathsym("X", group.mode)]);
|
||||
|
||||
return makeSpan(
|
||||
["katex-logo"], [k, a, t, e, x], options.getColor());
|
||||
["katex-logo", "mord"], [k, a, t, e, x], options.getColor());
|
||||
},
|
||||
|
||||
overline: function(group, options, prev) {
|
||||
@@ -1006,6 +1004,11 @@ var groupTypes = {
|
||||
return makeSpan([options.style.reset(), newStyle.cls()], inner);
|
||||
},
|
||||
|
||||
font: function(group, options, prev) {
|
||||
var font = group.value.font;
|
||||
return buildGroup(group.value.body, options.withFont(font), prev);
|
||||
},
|
||||
|
||||
delimsizing: function(group, options, prev) {
|
||||
var delim = group.value.value;
|
||||
|
||||
|
@@ -252,6 +252,11 @@ var groupTypes = {
|
||||
|
||||
return node;
|
||||
},
|
||||
|
||||
font: function(group) {
|
||||
// pass through so we can render something without throwing
|
||||
return buildGroup(group.value.body);
|
||||
},
|
||||
|
||||
spacing: function(group) {
|
||||
var node;
|
||||
|
@@ -215,6 +215,12 @@ var delimiters = [
|
||||
"."
|
||||
];
|
||||
|
||||
var fontAliases = {
|
||||
"\\Bbb": "\\mathbb",
|
||||
"\\bold": "\\mathbf",
|
||||
"\\frak": "\\mathfrak"
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a list of functions which each have the same function but have
|
||||
* different names so that we don't have to duplicate the data a bunch of times.
|
||||
@@ -476,6 +482,33 @@ var duplicatedFunctions = [
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
funcs: [
|
||||
// styles
|
||||
"\\mathrm", "\\mathit", "\\mathbf",
|
||||
|
||||
// families
|
||||
"\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
|
||||
"\\mathtt",
|
||||
|
||||
// aliases
|
||||
"\\Bbb", "\\bold", "\\frak"
|
||||
],
|
||||
data: {
|
||||
numArgs: 1,
|
||||
handler: function (func, body) {
|
||||
if (func in fontAliases) {
|
||||
func = fontAliases[func];
|
||||
}
|
||||
return {
|
||||
type: "font",
|
||||
font: func.slice(1),
|
||||
body: body
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Accents
|
||||
{
|
||||
funcs: [
|
||||
|
@@ -2514,6 +2514,17 @@ var symbols = {
|
||||
font: "main",
|
||||
group: "accent",
|
||||
replace: "\u02d9"
|
||||
},
|
||||
|
||||
"\\imath": {
|
||||
font: "main",
|
||||
group: "mathord",
|
||||
replace: "\u0131"
|
||||
},
|
||||
"\\jmath": {
|
||||
font: "main",
|
||||
group: "mathord",
|
||||
replace: "\u0237"
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
|
Reference in New Issue
Block a user