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.
|
@ -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": {
|
||||
|
|
|
@ -1160,6 +1160,115 @@ describe("A style change parser", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("A font parser", function () {
|
||||
it("should parse \\mathrm, \\mathbb, and \\mathit", function () {
|
||||
expect("\\mathrm x").toParse();
|
||||
expect("\\mathbb x").toParse();
|
||||
expect("\\mathit x").toParse();
|
||||
expect("\\mathrm {x + 1}").toParse();
|
||||
expect("\\mathbb {x + 1}").toParse();
|
||||
expect("\\mathit {x + 1}").toParse();
|
||||
});
|
||||
|
||||
it("should parse \\mathcal and \\mathfrak", function () {
|
||||
expect("\\mathcal{ABC123}").toParse();
|
||||
expect("\\mathfrak{abcABC123}").toParse();
|
||||
});
|
||||
|
||||
it("should produce the correct fonts", function () {
|
||||
var mathbbParse = getParsed("\\mathbb x")[0];
|
||||
expect(mathbbParse.value.font).toMatch("mathbb");
|
||||
expect(mathbbParse.value.type).toMatch("font");
|
||||
|
||||
var mathrmParse = getParsed("\\mathrm x")[0];
|
||||
expect(mathrmParse.value.font).toMatch("mathrm");
|
||||
expect(mathrmParse.value.type).toMatch("font");
|
||||
|
||||
var mathitParse = getParsed("\\mathit x")[0];
|
||||
expect(mathitParse.value.font).toMatch("mathit");
|
||||
expect(mathitParse.value.type).toMatch("font");
|
||||
|
||||
var mathcalParse = getParsed("\\mathcal C")[0];
|
||||
expect(mathcalParse.value.font).toMatch("mathcal");
|
||||
expect(mathcalParse.value.type).toMatch("font");
|
||||
|
||||
var mathfrakParse = getParsed("\\mathfrak C")[0];
|
||||
expect(mathfrakParse.value.font).toMatch("mathfrak");
|
||||
expect(mathfrakParse.value.type).toMatch("font");
|
||||
});
|
||||
|
||||
it("should parse nested font commands", function () {
|
||||
var nestedParse = getParsed("\\mathbb{R \\neq \\mathrm{R}}")[0];
|
||||
expect(nestedParse.value.font).toMatch("mathbb");
|
||||
expect(nestedParse.value.type).toMatch("font");
|
||||
|
||||
expect(nestedParse.value.body.value.length).toMatch(3);
|
||||
var bbBody = nestedParse.value.body.value;
|
||||
expect(bbBody[0].type).toMatch("mathord");
|
||||
expect(bbBody[1].type).toMatch("rel");
|
||||
expect(bbBody[2].type).toMatch("font");
|
||||
expect(bbBody[2].value.font).toMatch("mathrm");
|
||||
expect(bbBody[2].value.type).toMatch("font");
|
||||
});
|
||||
|
||||
it("should work with \\color", function () {
|
||||
var colorMathbbParse = getParsed("\\color{blue}{\\mathbb R}")[0];
|
||||
expect(colorMathbbParse.value.type).toMatch("color");
|
||||
expect(colorMathbbParse.value.color).toMatch("blue");
|
||||
var body = colorMathbbParse.value.value;
|
||||
expect(body.length).toMatch(1);
|
||||
expect(body[0].value.type).toMatch("font");
|
||||
expect(body[0].value.font).toMatch("mathbb");
|
||||
});
|
||||
|
||||
it("should not parse a series of font commands", function () {
|
||||
expect("\\mathbb \\mathrm R").toNotParse();
|
||||
});
|
||||
|
||||
it("should nest fonts correctly", function () {
|
||||
var bf = getParsed("\\mathbf{a\\mathrm{b}c}")[0];
|
||||
expect(bf.value.type).toMatch("font");
|
||||
expect(bf.value.font).toMatch("mathbf");
|
||||
expect(bf.value.body.value.length).toMatch(3);
|
||||
expect(bf.value.body.value[0].value).toMatch("a");
|
||||
expect(bf.value.body.value[1].value.type).toMatch("font");
|
||||
expect(bf.value.body.value[1].value.font).toMatch("mathrm");
|
||||
expect(bf.value.body.value[2].value).toMatch("c");
|
||||
});
|
||||
});
|
||||
|
||||
describe("An HTML font tree-builder", function () {
|
||||
it("should render \\mathbb{R} with the correct font", function () {
|
||||
var markup = katex.renderToString("\\mathbb{R}");
|
||||
expect(markup).toContain("<span class=\"mord mathbb\">R</span>");
|
||||
});
|
||||
|
||||
it("should render \\mathrm{R} with the correct font", function () {
|
||||
var markup = katex.renderToString("\\mathrm{R}");
|
||||
expect(markup).toContain("<span class=\"mord mathrm\">R</span>");
|
||||
});
|
||||
|
||||
it("should render \\mathcal{R} with the correct font", function () {
|
||||
var markup = katex.renderToString("\\mathcal{R}");
|
||||
expect(markup).toContain("<span class=\"mord mathcal\">R</span>");
|
||||
});
|
||||
|
||||
it("should render \\mathfrak{R} with the correct font", function () {
|
||||
var markup = katex.renderToString("\\mathfrak{R}");
|
||||
expect(markup).toContain("<span class=\"mord mathfrak\">R</span>");
|
||||
});
|
||||
|
||||
it("should render a combination of font and color changes", function () {
|
||||
var markup = katex.renderToString("\\color{blue}{\\mathbb R}");
|
||||
var span = "<span class=\"mord mathbb\" style=\"color:blue;\">R</span>";
|
||||
expect(markup).toContain(span);
|
||||
|
||||
markup = katex.renderToString("\\mathbb{\\color{blue}{R}}");
|
||||
span = "<span class=\"mord mathbb\" style=\"color:blue;\">R</span>";
|
||||
expect(markup).toContain(span);
|
||||
});
|
||||
});
|
||||
|
||||
describe("A bin builder", function() {
|
||||
it("should create mbins normally", function() {
|
||||
var built = getBuilt("x + y");
|
||||
|
|
BIN
test/screenshotter/images/MathBb-firefox.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
test/screenshotter/images/MathBf-firefox.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
test/screenshotter/images/MathCal-firefox.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
test/screenshotter/images/MathDefaultFonts-firefox.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
test/screenshotter/images/MathFrak-firefox.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
test/screenshotter/images/MathIt-firefox.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
test/screenshotter/images/MathRm-firefox.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
test/screenshotter/images/MathScr-firefox.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
test/screenshotter/images/MathSf-firefox.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
test/screenshotter/images/MathTt-firefox.png
Normal file
After Width: | Height: | Size: 20 KiB |
|
@ -65,6 +65,16 @@ LeftRightStyleSizing: |
|
|||
LimitControls: |
|
||||
\displaystyle\int\limits_2^3 3x^2\,dx + \sum\nolimits^n_{i=1}i +
|
||||
\textstyle\int\limits_x^y z
|
||||
MathDefaultFonts: Ax2k\breve{a}\omega\Omega\imath+\KaTeX
|
||||
MathBb: \mathbb{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathBf: \mathbf{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathCal: \mathcal{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathFrak: \mathfrak{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathIt: \mathit{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathRm: \mathrm{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathSf: \mathsf{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathScr: \mathscr{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
MathTt: \mathtt{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||
NestedFractions: |
|
||||
\dfrac{\frac{a}{b}}{\frac{c}{d}}\dfrac{\dfrac{a}{b}}
|
||||
{\dfrac{c}{d}}\frac{\frac{a}{b}}{\frac{c}{d}}
|
||||
|
|