Fix spacing between groups to match TeX spacing (#567)
* Internal: Pass full `options` objects to makeSpan/makeSymbol. Not just the current color. This will facilitate applying options to built nodes in a standardized way, rather than changing all callsites. * Add style switching test: text and scriptstyle in the same group. * Apply style-specific spacing using different CSS coding. Specifically, infer style from a class on the *current* element, rather than the parent element. Use "mtight" class to denote elements with tight spacing (scriptstyle or scriptscriptstyle). Apply that class automatically based on options. * Fix #533, #534, #541. - #534: Implement getTypeOfGroup for font groups. - #533, #541: Improve the ways spaces are applied to lists. Since CSS adjacency implements mathematical spacing, it's incorrect to introduce "convenience spans" for spaces and display changes into the generated HTML -- those spans break adjacency. Apply display changes directly, and shift space spans into adjacent atoms. Requires updates to two screenshotter tests, LimitControls and SupSubLeftAlignReset. The new results for these tests are closer to TeX output than the old results. Also requires updates to Jasmine tests, since those assumed output structures that have changed. * Fix #136: Size commands generate fragments, not spans. This is so the size commands don't hide the types of their enclosed atoms. Addresses #136. This slightly changes the vertical position of the Sizing test. Not sure the vertical position matters, so change the test.
@@ -87,6 +87,13 @@ Style.prototype.reset = function() {
|
|||||||
return resetNames[this.size];
|
return resetNames[this.size];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return if this style is tightly spaced (scriptstyle/scriptscriptstyle)
|
||||||
|
*/
|
||||||
|
Style.prototype.isTight = function() {
|
||||||
|
return this.size >= 2;
|
||||||
|
};
|
||||||
|
|
||||||
// IDs of the different styles
|
// IDs of the different styles
|
||||||
var D = 0;
|
var D = 0;
|
||||||
var Dc = 1;
|
var Dc = 1;
|
||||||
|
@@ -34,14 +34,16 @@ var mainitLetters = [
|
|||||||
* Makes a symbolNode after translation via the list of symbols in symbols.js.
|
* 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
|
* Correctly pulls out metrics for the character, and optionally takes a list of
|
||||||
* classes to be attached to the node.
|
* classes to be attached to the node.
|
||||||
|
*
|
||||||
|
* TODO: make argument order closer to makeSpan
|
||||||
*/
|
*/
|
||||||
var makeSymbol = function(value, style, mode, color, classes) {
|
var makeSymbol = function(value, fontFamily, mode, options, classes) {
|
||||||
// Replace the value with its replaced value from symbol.js
|
// Replace the value with its replaced value from symbol.js
|
||||||
if (symbols[mode][value] && symbols[mode][value].replace) {
|
if (symbols[mode][value] && symbols[mode][value].replace) {
|
||||||
value = symbols[mode][value].replace;
|
value = symbols[mode][value].replace;
|
||||||
}
|
}
|
||||||
|
|
||||||
var metrics = fontMetrics.getCharacterMetrics(value, style);
|
var metrics = fontMetrics.getCharacterMetrics(value, fontFamily);
|
||||||
|
|
||||||
var symbolNode;
|
var symbolNode;
|
||||||
if (metrics) {
|
if (metrics) {
|
||||||
@@ -52,12 +54,17 @@ var makeSymbol = function(value, style, mode, color, classes) {
|
|||||||
// TODO(emily): Figure out a good way to only print this in development
|
// TODO(emily): Figure out a good way to only print this in development
|
||||||
typeof console !== "undefined" && console.warn(
|
typeof console !== "undefined" && console.warn(
|
||||||
"No character metrics for '" + value + "' in style '" +
|
"No character metrics for '" + value + "' in style '" +
|
||||||
style + "'");
|
fontFamily + "'");
|
||||||
symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes);
|
symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color) {
|
if (options) {
|
||||||
symbolNode.style.color = color;
|
if (options.style.isTight()) {
|
||||||
|
symbolNode.classes.push("mtight");
|
||||||
|
}
|
||||||
|
if (options.getColor()) {
|
||||||
|
symbolNode.style.color = options.getColor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbolNode;
|
return symbolNode;
|
||||||
@@ -67,7 +74,7 @@ var makeSymbol = function(value, style, mode, color, classes) {
|
|||||||
* Makes a symbol in Main-Regular or AMS-Regular.
|
* Makes a symbol in Main-Regular or AMS-Regular.
|
||||||
* Used for rel, bin, open, close, inner, and punct.
|
* Used for rel, bin, open, close, inner, and punct.
|
||||||
*/
|
*/
|
||||||
var mathsym = function(value, mode, color, classes) {
|
var mathsym = function(value, mode, options, classes) {
|
||||||
// Decide what font to render the symbol in by its entry in the symbols
|
// Decide what font to render the symbol in by its entry in the symbols
|
||||||
// table.
|
// table.
|
||||||
// Have a special case for when the value = \ because the \ is used as a
|
// Have a special case for when the value = \ because the \ is used as a
|
||||||
@@ -75,22 +82,22 @@ var mathsym = function(value, mode, color, classes) {
|
|||||||
// text ordinal and is therefore not present as a symbol in the symbols
|
// text ordinal and is therefore not present as a symbol in the symbols
|
||||||
// table for text
|
// table for text
|
||||||
if (value === "\\" || symbols[mode][value].font === "main") {
|
if (value === "\\" || symbols[mode][value].font === "main") {
|
||||||
return makeSymbol(value, "Main-Regular", mode, color, classes);
|
return makeSymbol(value, "Main-Regular", mode, options, classes);
|
||||||
} else {
|
} else {
|
||||||
return makeSymbol(
|
return makeSymbol(
|
||||||
value, "AMS-Regular", mode, color, classes.concat(["amsrm"]));
|
value, "AMS-Regular", mode, options, classes.concat(["amsrm"]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a symbol in the default font for mathords and textords.
|
* Makes a symbol in the default font for mathords and textords.
|
||||||
*/
|
*/
|
||||||
var mathDefault = function(value, mode, color, classes, type) {
|
var mathDefault = function(value, mode, options, classes, type) {
|
||||||
if (type === "mathord") {
|
if (type === "mathord") {
|
||||||
return mathit(value, mode, color, classes);
|
return mathit(value, mode, options, classes);
|
||||||
} else if (type === "textord") {
|
} else if (type === "textord") {
|
||||||
return makeSymbol(
|
return makeSymbol(
|
||||||
value, "Main-Regular", mode, color, classes.concat(["mathrm"]));
|
value, "Main-Regular", mode, options, classes.concat(["mathrm"]));
|
||||||
} else {
|
} else {
|
||||||
throw new Error("unexpected type: " + type + " in mathDefault");
|
throw new Error("unexpected type: " + type + " in mathDefault");
|
||||||
}
|
}
|
||||||
@@ -99,17 +106,17 @@ var mathDefault = function(value, mode, color, classes, type) {
|
|||||||
/**
|
/**
|
||||||
* Makes a symbol in the italic math font.
|
* Makes a symbol in the italic math font.
|
||||||
*/
|
*/
|
||||||
var mathit = function(value, mode, color, classes) {
|
var mathit = function(value, mode, options, classes) {
|
||||||
if (/[0-9]/.test(value.charAt(0)) ||
|
if (/[0-9]/.test(value.charAt(0)) ||
|
||||||
// glyphs for \imath and \jmath do not exist in Math-Italic so we
|
// glyphs for \imath and \jmath do not exist in Math-Italic so we
|
||||||
// need to use Main-Italic instead
|
// need to use Main-Italic instead
|
||||||
utils.contains(mainitLetters, value) ||
|
utils.contains(mainitLetters, value) ||
|
||||||
utils.contains(greekCapitals, value)) {
|
utils.contains(greekCapitals, value)) {
|
||||||
return makeSymbol(
|
return makeSymbol(
|
||||||
value, "Main-Italic", mode, color, classes.concat(["mainit"]));
|
value, "Main-Italic", mode, options, classes.concat(["mainit"]));
|
||||||
} else {
|
} else {
|
||||||
return makeSymbol(
|
return makeSymbol(
|
||||||
value, "Math-Italic", mode, color, classes.concat(["mathit"]));
|
value, "Math-Italic", mode, options, classes.concat(["mathit"]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -124,23 +131,22 @@ var makeOrd = function(group, options, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var classes = ["mord"];
|
var classes = ["mord"];
|
||||||
var color = options.getColor();
|
|
||||||
|
|
||||||
var font = options.font;
|
var font = options.font;
|
||||||
if (font) {
|
if (font) {
|
||||||
if (font === "mathit" || utils.contains(mainitLetters, value)) {
|
if (font === "mathit" || utils.contains(mainitLetters, value)) {
|
||||||
return mathit(value, mode, color, classes);
|
return mathit(value, mode, options, classes);
|
||||||
} else {
|
} else {
|
||||||
var fontName = fontMap[font].fontName;
|
var fontName = fontMap[font].fontName;
|
||||||
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
||||||
return makeSymbol(
|
return makeSymbol(
|
||||||
value, fontName, mode, color, classes.concat([font]));
|
value, fontName, mode, options, classes.concat([font]));
|
||||||
} else {
|
} else {
|
||||||
return mathDefault(value, mode, color, classes, type);
|
return mathDefault(value, mode, options, classes, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return mathDefault(value, mode, color, classes, type);
|
return mathDefault(value, mode, options, classes, type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -173,20 +179,29 @@ var sizeElementFromChildren = function(elem) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a span with the given list of classes, list of children, and color.
|
* Makes a span with the given list of classes, list of children, and options.
|
||||||
|
*
|
||||||
|
* TODO: Ensure that `options` is always provided (currently some call sites
|
||||||
|
* don't pass it).
|
||||||
*/
|
*/
|
||||||
var makeSpan = function(classes, children, color) {
|
var makeSpan = function(classes, children, options) {
|
||||||
var span = new domTree.span(classes, children);
|
var span = new domTree.span(classes, children, options);
|
||||||
|
|
||||||
sizeElementFromChildren(span);
|
sizeElementFromChildren(span);
|
||||||
|
|
||||||
if (color) {
|
|
||||||
span.style.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
return span;
|
return span;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepends the given children to the given span, updating height, depth, and
|
||||||
|
* maxFontSize.
|
||||||
|
*/
|
||||||
|
var prependChildren = function(span, children) {
|
||||||
|
span.children = children.concat(span.children);
|
||||||
|
|
||||||
|
sizeElementFromChildren(span);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a document fragment with the given list of children.
|
* Makes a document fragment with the given list of children.
|
||||||
*/
|
*/
|
||||||
@@ -447,6 +462,7 @@ module.exports = {
|
|||||||
makeFragment: makeFragment,
|
makeFragment: makeFragment,
|
||||||
makeVList: makeVList,
|
makeVList: makeVList,
|
||||||
makeOrd: makeOrd,
|
makeOrd: makeOrd,
|
||||||
|
prependChildren: prependChildren,
|
||||||
sizingMultiplier: sizingMultiplier,
|
sizingMultiplier: sizingMultiplier,
|
||||||
spacingFunctions: spacingFunctions,
|
spacingFunctions: spacingFunctions,
|
||||||
};
|
};
|
||||||
|
230
src/buildHTML.js
@@ -17,18 +17,57 @@ var utils = require("./utils");
|
|||||||
|
|
||||||
var makeSpan = buildCommon.makeSpan;
|
var makeSpan = buildCommon.makeSpan;
|
||||||
|
|
||||||
|
var isSpace = function(node) {
|
||||||
|
return node instanceof domTree.span && node.classes[0] === "mspace";
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a list of nodes, build them in order, and return a list of the built
|
* Take a list of nodes, build them in order, and return a list of the built
|
||||||
* nodes. This function handles the `prev` node correctly, and passes the
|
* nodes. This function handles the `prev` node correctly, and passes the
|
||||||
* previous element from the list as the prev of the next element.
|
* previous element from the list as the prev of the next element, ignoring
|
||||||
|
* spaces. documentFragments are flattened into their contents, so the
|
||||||
|
* returned list contains no fragments.
|
||||||
*/
|
*/
|
||||||
var buildExpression = function(expression, options, prev) {
|
var buildExpression = function(expression, options, prev) {
|
||||||
|
// Parse expressions into `groups`.
|
||||||
var groups = [];
|
var groups = [];
|
||||||
for (var i = 0; i < expression.length; i++) {
|
for (var i = 0; i < expression.length; i++) {
|
||||||
var group = expression[i];
|
var group = expression[i];
|
||||||
groups.push(buildGroup(group, options, prev));
|
var output = buildGroup(group, options, prev);
|
||||||
|
if (output instanceof domTree.documentFragment) {
|
||||||
|
Array.prototype.push.apply(groups, output.children);
|
||||||
|
} else {
|
||||||
|
groups.push(output);
|
||||||
|
}
|
||||||
|
if (!isSpace(output)) {
|
||||||
prev = group;
|
prev = group;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// At this point `groups` consists entirely of `symbolNode`s and `span`s.
|
||||||
|
|
||||||
|
// Explicit spaces (e.g., \;, \,) should be ignored with respect to atom
|
||||||
|
// spacing (e.g., "add thick space between mord and mrel"). Since CSS
|
||||||
|
// adjacency rules implement atom spacing, spaces should be invisible to
|
||||||
|
// CSS. So we splice them out of `groups` and into the atoms themselves.
|
||||||
|
var spaces = null;
|
||||||
|
for (i = 0; i < groups.length; i++) {
|
||||||
|
if (isSpace(groups[i])) {
|
||||||
|
spaces = spaces || [];
|
||||||
|
spaces.push(groups[i]);
|
||||||
|
groups.splice(i, 1);
|
||||||
|
i--;
|
||||||
|
} else if (spaces) {
|
||||||
|
if (groups[i] instanceof domTree.symbolNode) {
|
||||||
|
groups[i] = makeSpan(groups[i].classes, [groups[i]]);
|
||||||
|
}
|
||||||
|
buildCommon.prependChildren(groups[i], spaces);
|
||||||
|
spaces = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spaces) {
|
||||||
|
Array.prototype.push.apply(groups, spaces);
|
||||||
|
}
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,12 +119,13 @@ var getTypeOfGroup = function(group) {
|
|||||||
return getTypeOfGroup(group.value.base);
|
return getTypeOfGroup(group.value.base);
|
||||||
} else if (group.type === "llap" || group.type === "rlap") {
|
} else if (group.type === "llap" || group.type === "rlap") {
|
||||||
return getTypeOfGroup(group.value);
|
return getTypeOfGroup(group.value);
|
||||||
} else if (group.type === "color") {
|
} else if (group.type === "color" || group.type === "sizing"
|
||||||
return getTypeOfGroup(group.value.value);
|
|| group.type === "styling") {
|
||||||
} else if (group.type === "sizing") {
|
// Return type of rightmost element of group.
|
||||||
return getTypeOfGroup(group.value.value);
|
var atoms = group.value.value;
|
||||||
} else if (group.type === "styling") {
|
return getTypeOfGroup(atoms[atoms.length - 1]);
|
||||||
return getTypeOfGroup(group.value.value);
|
} else if (group.type === "font") {
|
||||||
|
return getTypeOfGroup(group.value.body);
|
||||||
} else if (group.type === "delimsizing") {
|
} else if (group.type === "delimsizing") {
|
||||||
return groupToType[group.value.delimType];
|
return groupToType[group.value.delimType];
|
||||||
} else {
|
} else {
|
||||||
@@ -203,44 +243,46 @@ groupTypes.bin = function(group, options, prev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return buildCommon.mathsym(
|
return buildCommon.mathsym(
|
||||||
group.value, group.mode, options.getColor(), [className]);
|
group.value, group.mode, options, [className]);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.rel = function(group, options, prev) {
|
groupTypes.rel = function(group, options, prev) {
|
||||||
return buildCommon.mathsym(
|
return buildCommon.mathsym(
|
||||||
group.value, group.mode, options.getColor(), ["mrel"]);
|
group.value, group.mode, options, ["mrel"]);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.open = function(group, options, prev) {
|
groupTypes.open = function(group, options, prev) {
|
||||||
return buildCommon.mathsym(
|
return buildCommon.mathsym(
|
||||||
group.value, group.mode, options.getColor(), ["mopen"]);
|
group.value, group.mode, options, ["mopen"]);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.close = function(group, options, prev) {
|
groupTypes.close = function(group, options, prev) {
|
||||||
return buildCommon.mathsym(
|
return buildCommon.mathsym(
|
||||||
group.value, group.mode, options.getColor(), ["mclose"]);
|
group.value, group.mode, options, ["mclose"]);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.inner = function(group, options, prev) {
|
groupTypes.inner = function(group, options, prev) {
|
||||||
return buildCommon.mathsym(
|
return buildCommon.mathsym(
|
||||||
group.value, group.mode, options.getColor(), ["minner"]);
|
group.value, group.mode, options, ["minner"]);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.punct = function(group, options, prev) {
|
groupTypes.punct = function(group, options, prev) {
|
||||||
return buildCommon.mathsym(
|
return buildCommon.mathsym(
|
||||||
group.value, group.mode, options.getColor(), ["mpunct"]);
|
group.value, group.mode, options, ["mpunct"]);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.ordgroup = function(group, options, prev) {
|
groupTypes.ordgroup = function(group, options, prev) {
|
||||||
return makeSpan(
|
return makeSpan(
|
||||||
["mord", options.style.cls()],
|
["mord", options.style.cls()],
|
||||||
buildExpression(group.value, options.reset())
|
buildExpression(group.value, options.reset()),
|
||||||
|
options
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.text = function(group, options, prev) {
|
groupTypes.text = function(group, options, prev) {
|
||||||
return makeSpan(["text", "mord", options.style.cls()],
|
return makeSpan(["mord", "text", options.style.cls()],
|
||||||
buildExpression(group.value.body, options.reset()));
|
buildExpression(group.value.body, options.reset()),
|
||||||
|
options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.color = function(group, options, prev) {
|
groupTypes.color = function(group, options, prev) {
|
||||||
@@ -274,15 +316,20 @@ groupTypes.supsub = function(group, options, prev) {
|
|||||||
var sub;
|
var sub;
|
||||||
|
|
||||||
var style = options.style;
|
var style = options.style;
|
||||||
|
var newOptions;
|
||||||
|
|
||||||
if (group.value.sup) {
|
if (group.value.sup) {
|
||||||
sup = buildGroup(group.value.sup, options.withStyle(style.sup()));
|
newOptions = options.withStyle(style.sup());
|
||||||
supmid = makeSpan([style.reset(), style.sup().cls()], [sup]);
|
sup = buildGroup(group.value.sup, newOptions);
|
||||||
|
supmid = makeSpan([style.reset(), style.sup().cls()],
|
||||||
|
[sup], newOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group.value.sub) {
|
if (group.value.sub) {
|
||||||
sub = buildGroup(group.value.sub, options.withStyle(style.sub()));
|
newOptions = options.withStyle(style.sub());
|
||||||
submid = makeSpan([style.reset(), style.sub().cls()], [sub]);
|
sub = buildGroup(group.value.sub, newOptions);
|
||||||
|
submid = makeSpan([style.reset(), style.sub().cls()],
|
||||||
|
[sub], newOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule 18a
|
// Rule 18a
|
||||||
@@ -376,7 +423,8 @@ groupTypes.supsub = function(group, options, prev) {
|
|||||||
|
|
||||||
// We ensure to wrap the supsub vlist in a span.msupsub to reset text-align
|
// We ensure to wrap the supsub vlist in a span.msupsub to reset text-align
|
||||||
return makeSpan([getTypeOfGroup(group.value.base)],
|
return makeSpan([getTypeOfGroup(group.value.base)],
|
||||||
[base, makeSpan(["msupsub"], [supsub])]);
|
[base, makeSpan(["msupsub"], [supsub])],
|
||||||
|
options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.genfrac = function(group, options, prev) {
|
groupTypes.genfrac = function(group, options, prev) {
|
||||||
@@ -392,12 +440,17 @@ groupTypes.genfrac = function(group, options, prev) {
|
|||||||
|
|
||||||
var nstyle = style.fracNum();
|
var nstyle = style.fracNum();
|
||||||
var dstyle = style.fracDen();
|
var dstyle = style.fracDen();
|
||||||
|
var newOptions;
|
||||||
|
|
||||||
var numer = buildGroup(group.value.numer, options.withStyle(nstyle));
|
newOptions = options.withStyle(nstyle);
|
||||||
var numerreset = makeSpan([style.reset(), nstyle.cls()], [numer]);
|
var numer = buildGroup(group.value.numer, newOptions);
|
||||||
|
var numerreset = makeSpan([style.reset(), nstyle.cls()],
|
||||||
|
[numer], newOptions);
|
||||||
|
|
||||||
var denom = buildGroup(group.value.denom, options.withStyle(dstyle));
|
newOptions = options.withStyle(dstyle);
|
||||||
var denomreset = makeSpan([style.reset(), dstyle.cls()], [denom]);
|
var denom = buildGroup(group.value.denom, newOptions);
|
||||||
|
var denomreset = makeSpan([style.reset(), dstyle.cls()],
|
||||||
|
[denom], newOptions);
|
||||||
|
|
||||||
var ruleWidth;
|
var ruleWidth;
|
||||||
if (group.value.hasBarLine) {
|
if (group.value.hasBarLine) {
|
||||||
@@ -510,7 +563,7 @@ groupTypes.genfrac = function(group, options, prev) {
|
|||||||
return makeSpan(
|
return makeSpan(
|
||||||
["mord", options.style.reset(), style.cls()],
|
["mord", options.style.reset(), style.cls()],
|
||||||
[leftDelim, makeSpan(["mfrac"], [frac]), rightDelim],
|
[leftDelim, makeSpan(["mfrac"], [frac]), rightDelim],
|
||||||
options.getColor());
|
options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.array = function(group, options, prev) {
|
groupTypes.array = function(group, options, prev) {
|
||||||
@@ -674,7 +727,7 @@ groupTypes.array = function(group, options, prev) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
body = makeSpan(["mtable"], cols);
|
body = makeSpan(["mtable"], cols);
|
||||||
return makeSpan(["mord"], [body], options.getColor());
|
return makeSpan(["mord"], [body], options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.spacing = function(group, options, prev) {
|
groupTypes.spacing = function(group, options, prev) {
|
||||||
@@ -684,14 +737,14 @@ groupTypes.spacing = function(group, options, prev) {
|
|||||||
// things has an entry in the symbols table, so these will be turned
|
// things has an entry in the symbols table, so these will be turned
|
||||||
// into appropriate outputs.
|
// into appropriate outputs.
|
||||||
return makeSpan(
|
return makeSpan(
|
||||||
["mord", "mspace"],
|
["mspace"],
|
||||||
[buildCommon.mathsym(group.value, group.mode)]
|
[buildCommon.mathsym(group.value, group.mode)]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Other kinds of spaces are of arbitrary width. We use CSS to
|
// Other kinds of spaces are of arbitrary width. We use CSS to
|
||||||
// generate these.
|
// generate these.
|
||||||
return makeSpan(
|
return makeSpan(
|
||||||
["mord", "mspace",
|
["mspace",
|
||||||
buildCommon.spacingFunctions[group.value].className]);
|
buildCommon.spacingFunctions[group.value].className]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -701,7 +754,7 @@ groupTypes.llap = function(group, options, prev) {
|
|||||||
["inner"], [buildGroup(group.value.body, options.reset())]);
|
["inner"], [buildGroup(group.value.body, options.reset())]);
|
||||||
var fix = makeSpan(["fix"], []);
|
var fix = makeSpan(["fix"], []);
|
||||||
return makeSpan(
|
return makeSpan(
|
||||||
["llap", options.style.cls()], [inner, fix]);
|
["llap", options.style.cls()], [inner, fix], options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.rlap = function(group, options, prev) {
|
groupTypes.rlap = function(group, options, prev) {
|
||||||
@@ -709,7 +762,7 @@ groupTypes.rlap = function(group, options, prev) {
|
|||||||
["inner"], [buildGroup(group.value.body, options.reset())]);
|
["inner"], [buildGroup(group.value.body, options.reset())]);
|
||||||
var fix = makeSpan(["fix"], []);
|
var fix = makeSpan(["fix"], []);
|
||||||
return makeSpan(
|
return makeSpan(
|
||||||
["rlap", options.style.cls()], [inner, fix]);
|
["rlap", options.style.cls()], [inner, fix], options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.op = function(group, options, prev) {
|
groupTypes.op = function(group, options, prev) {
|
||||||
@@ -750,8 +803,8 @@ groupTypes.op = function(group, options, prev) {
|
|||||||
// If this is a symbol, create the symbol.
|
// If this is a symbol, create the symbol.
|
||||||
var fontName = large ? "Size2-Regular" : "Size1-Regular";
|
var fontName = large ? "Size2-Regular" : "Size1-Regular";
|
||||||
base = buildCommon.makeSymbol(
|
base = buildCommon.makeSymbol(
|
||||||
group.value.body, fontName, "math", options.getColor(),
|
group.value.body, fontName, "math", options,
|
||||||
["op-symbol", large ? "large-op" : "small-op", "mop"]);
|
["mop", "op-symbol", large ? "large-op" : "small-op"]);
|
||||||
|
|
||||||
// Shift the symbol so its center lies on the axis (rule 13). It
|
// Shift the symbol so its center lies on the axis (rule 13). It
|
||||||
// appears that our fonts have the centers of the symbols already
|
// appears that our fonts have the centers of the symbols already
|
||||||
@@ -772,7 +825,7 @@ groupTypes.op = function(group, options, prev) {
|
|||||||
for (var i = 1; i < group.value.body.length; i++) {
|
for (var i = 1; i < group.value.body.length; i++) {
|
||||||
output.push(buildCommon.mathsym(group.value.body[i], group.mode));
|
output.push(buildCommon.mathsym(group.value.body[i], group.mode));
|
||||||
}
|
}
|
||||||
base = makeSpan(["mop"], output, options.getColor());
|
base = makeSpan(["mop"], output, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasLimits) {
|
if (hasLimits) {
|
||||||
@@ -784,11 +837,14 @@ groupTypes.op = function(group, options, prev) {
|
|||||||
var supKern;
|
var supKern;
|
||||||
var submid;
|
var submid;
|
||||||
var subKern;
|
var subKern;
|
||||||
|
var newOptions;
|
||||||
// We manually have to handle the superscripts and subscripts. This,
|
// We manually have to handle the superscripts and subscripts. This,
|
||||||
// aside from the kern calculations, is copied from supsub.
|
// aside from the kern calculations, is copied from supsub.
|
||||||
if (supGroup) {
|
if (supGroup) {
|
||||||
var sup = buildGroup(supGroup, options.withStyle(style.sup()));
|
newOptions = options.withStyle(style.sup());
|
||||||
supmid = makeSpan([style.reset(), style.sup().cls()], [sup]);
|
var sup = buildGroup(supGroup, newOptions);
|
||||||
|
supmid = makeSpan([style.reset(), style.sup().cls()],
|
||||||
|
[sup], newOptions);
|
||||||
|
|
||||||
supKern = Math.max(
|
supKern = Math.max(
|
||||||
fontMetrics.metrics.bigOpSpacing1,
|
fontMetrics.metrics.bigOpSpacing1,
|
||||||
@@ -796,8 +852,10 @@ groupTypes.op = function(group, options, prev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (subGroup) {
|
if (subGroup) {
|
||||||
var sub = buildGroup(subGroup, options.withStyle(style.sub()));
|
newOptions = options.withStyle(style.sub());
|
||||||
submid = makeSpan([style.reset(), style.sub().cls()], [sub]);
|
var sub = buildGroup(subGroup, newOptions);
|
||||||
|
submid = makeSpan([style.reset(), style.sub().cls()],
|
||||||
|
[sub], newOptions);
|
||||||
|
|
||||||
subKern = Math.max(
|
subKern = Math.max(
|
||||||
fontMetrics.metrics.bigOpSpacing2,
|
fontMetrics.metrics.bigOpSpacing2,
|
||||||
@@ -862,7 +920,7 @@ groupTypes.op = function(group, options, prev) {
|
|||||||
finalGroup.children[2].style.marginLeft = slant + "em";
|
finalGroup.children[2].style.marginLeft = slant + "em";
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeSpan(["mop", "op-limits"], [finalGroup]);
|
return makeSpan(["mop", "op-limits"], [finalGroup], options);
|
||||||
} else {
|
} else {
|
||||||
if (group.value.symbol) {
|
if (group.value.symbol) {
|
||||||
base.style.top = baseShift + "em";
|
base.style.top = baseShift + "em";
|
||||||
@@ -877,26 +935,26 @@ groupTypes.katex = function(group, options, prev) {
|
|||||||
// good, but the offsets for the T, E, and X were taken from the
|
// good, but the offsets for the T, E, and X were taken from the
|
||||||
// definition of \TeX in TeX (see TeXbook pg. 356)
|
// definition of \TeX in TeX (see TeXbook pg. 356)
|
||||||
var k = makeSpan(
|
var k = makeSpan(
|
||||||
["k"], [buildCommon.mathsym("K", group.mode)]);
|
["k"], [buildCommon.mathsym("K", group.mode)], options);
|
||||||
var a = makeSpan(
|
var a = makeSpan(
|
||||||
["a"], [buildCommon.mathsym("A", group.mode)]);
|
["a"], [buildCommon.mathsym("A", group.mode)], options);
|
||||||
|
|
||||||
a.height = (a.height + 0.2) * 0.75;
|
a.height = (a.height + 0.2) * 0.75;
|
||||||
a.depth = (a.height - 0.2) * 0.75;
|
a.depth = (a.height - 0.2) * 0.75;
|
||||||
|
|
||||||
var t = makeSpan(
|
var t = makeSpan(
|
||||||
["t"], [buildCommon.mathsym("T", group.mode)]);
|
["t"], [buildCommon.mathsym("T", group.mode)], options);
|
||||||
var e = makeSpan(
|
var e = makeSpan(
|
||||||
["e"], [buildCommon.mathsym("E", group.mode)]);
|
["e"], [buildCommon.mathsym("E", group.mode)], options);
|
||||||
|
|
||||||
e.height = (e.height - 0.2155);
|
e.height = (e.height - 0.2155);
|
||||||
e.depth = (e.depth + 0.2155);
|
e.depth = (e.depth + 0.2155);
|
||||||
|
|
||||||
var x = makeSpan(
|
var x = makeSpan(
|
||||||
["x"], [buildCommon.mathsym("X", group.mode)]);
|
["x"], [buildCommon.mathsym("X", group.mode)], options);
|
||||||
|
|
||||||
return makeSpan(
|
return makeSpan(
|
||||||
["katex-logo", "mord"], [k, a, t, e, x], options.getColor());
|
["mord", "katex-logo"], [k, a, t, e, x], options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.overline = function(group, options, prev) {
|
groupTypes.overline = function(group, options, prev) {
|
||||||
@@ -924,7 +982,7 @@ groupTypes.overline = function(group, options, prev) {
|
|||||||
{type: "kern", size: ruleWidth},
|
{type: "kern", size: ruleWidth},
|
||||||
], "firstBaseline", null, options);
|
], "firstBaseline", null, options);
|
||||||
|
|
||||||
return makeSpan(["overline", "mord"], [vlist], options.getColor());
|
return makeSpan(["mord", "overline"], [vlist], options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.underline = function(group, options, prev) {
|
groupTypes.underline = function(group, options, prev) {
|
||||||
@@ -950,7 +1008,7 @@ groupTypes.underline = function(group, options, prev) {
|
|||||||
{type: "elem", elem: innerGroup},
|
{type: "elem", elem: innerGroup},
|
||||||
], "top", innerGroup.height, options);
|
], "top", innerGroup.height, options);
|
||||||
|
|
||||||
return makeSpan(["underline", "mord"], [vlist], options.getColor());
|
return makeSpan(["mord", "underline"], [vlist], options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.sqrt = function(group, options, prev) {
|
groupTypes.sqrt = function(group, options, prev) {
|
||||||
@@ -966,7 +1024,7 @@ groupTypes.sqrt = function(group, options, prev) {
|
|||||||
|
|
||||||
var line = makeSpan(
|
var line = makeSpan(
|
||||||
[style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
|
[style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
|
||||||
options.getColor());
|
options);
|
||||||
line.height = ruleWidth;
|
line.height = ruleWidth;
|
||||||
line.maxFontSize = 1.0;
|
line.maxFontSize = 1.0;
|
||||||
|
|
||||||
@@ -985,7 +1043,7 @@ groupTypes.sqrt = function(group, options, prev) {
|
|||||||
var delim = makeSpan(["sqrt-sign"], [
|
var delim = makeSpan(["sqrt-sign"], [
|
||||||
delimiter.customSizedDelim("\\surd", minDelimiterHeight,
|
delimiter.customSizedDelim("\\surd", minDelimiterHeight,
|
||||||
false, options, group.mode)],
|
false, options, group.mode)],
|
||||||
options.getColor());
|
options);
|
||||||
|
|
||||||
var delimDepth = (delim.height + delim.depth) - ruleWidth;
|
var delimDepth = (delim.height + delim.depth) - ruleWidth;
|
||||||
|
|
||||||
@@ -1019,17 +1077,17 @@ groupTypes.sqrt = function(group, options, prev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!group.value.index) {
|
if (!group.value.index) {
|
||||||
return makeSpan(["sqrt", "mord"], [delim, body]);
|
return makeSpan(["mord", "sqrt"], [delim, body], options);
|
||||||
} else {
|
} else {
|
||||||
// Handle the optional root index
|
// Handle the optional root index
|
||||||
|
|
||||||
// The index is always in scriptscript style
|
// The index is always in scriptscript style
|
||||||
var root = buildGroup(
|
var newOptions = options.withStyle(Style.SCRIPTSCRIPT);
|
||||||
group.value.index,
|
var root = buildGroup(group.value.index, newOptions);
|
||||||
options.withStyle(Style.SCRIPTSCRIPT));
|
|
||||||
var rootWrap = makeSpan(
|
var rootWrap = makeSpan(
|
||||||
[style.reset(), Style.SCRIPTSCRIPT.cls()],
|
[style.reset(), Style.SCRIPTSCRIPT.cls()],
|
||||||
[root]);
|
[root],
|
||||||
|
newOptions);
|
||||||
|
|
||||||
// Figure out the height and depth of the inner part
|
// Figure out the height and depth of the inner part
|
||||||
var innerRootHeight = Math.max(delim.height, body.height);
|
var innerRootHeight = Math.max(delim.height, body.height);
|
||||||
@@ -1047,7 +1105,8 @@ groupTypes.sqrt = function(group, options, prev) {
|
|||||||
// kerning
|
// kerning
|
||||||
var rootVListWrap = makeSpan(["root"], [rootVList]);
|
var rootVListWrap = makeSpan(["root"], [rootVList]);
|
||||||
|
|
||||||
return makeSpan(["sqrt", "mord"], [rootVListWrap, delim, body]);
|
return makeSpan(["mord", "sqrt"],
|
||||||
|
[rootVListWrap, delim, body], options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1058,17 +1117,28 @@ groupTypes.sizing = function(group, options, prev) {
|
|||||||
var inner = buildExpression(group.value.value,
|
var inner = buildExpression(group.value.value,
|
||||||
options.withSize(group.value.size), prev);
|
options.withSize(group.value.size), prev);
|
||||||
|
|
||||||
|
// Compute the correct maxFontSize.
|
||||||
var style = options.style;
|
var style = options.style;
|
||||||
var span = makeSpan(["mord"],
|
|
||||||
[makeSpan(["sizing", "reset-" + options.size, group.value.size,
|
|
||||||
style.cls()],
|
|
||||||
inner)]);
|
|
||||||
|
|
||||||
// Calculate the correct maxFontSize manually
|
|
||||||
var fontSize = buildCommon.sizingMultiplier[group.value.size];
|
var fontSize = buildCommon.sizingMultiplier[group.value.size];
|
||||||
span.maxFontSize = fontSize * style.sizeMultiplier;
|
fontSize = fontSize * style.sizeMultiplier;
|
||||||
|
|
||||||
return span;
|
// Add size-resetting classes to the inner list and set maxFontSize
|
||||||
|
// manually. Handle nested size changes.
|
||||||
|
for (var i = 0; i < inner.length; i++) {
|
||||||
|
var pos = utils.indexOf(inner[i].classes, "sizing");
|
||||||
|
if (pos < 0) {
|
||||||
|
inner[i].classes.push("sizing", "reset-" + options.size,
|
||||||
|
group.value.size, style.cls());
|
||||||
|
inner[i].maxFontSize = fontSize;
|
||||||
|
} else if (inner[i].classes[pos + 1] === "reset-" + group.value.size) {
|
||||||
|
// This is a nested size change: e.g., inner[i] is the "b" in
|
||||||
|
// `\Huge a \small b`. Override the old size (the `reset-` class)
|
||||||
|
// but not the new size.
|
||||||
|
inner[i].classes[pos + 1] = "reset-" + options.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildCommon.makeFragment(inner);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.styling = function(group, options, prev) {
|
groupTypes.styling = function(group, options, prev) {
|
||||||
@@ -1083,12 +1153,25 @@ groupTypes.styling = function(group, options, prev) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var newStyle = styleMap[group.value.style];
|
var newStyle = styleMap[group.value.style];
|
||||||
|
var newOptions = options.withStyle(newStyle);
|
||||||
|
|
||||||
// Build the inner expression in the new style.
|
// Build the inner expression in the new style.
|
||||||
var inner = buildExpression(
|
var inner = buildExpression(
|
||||||
group.value.value, options.withStyle(newStyle), prev);
|
group.value.value, newOptions, prev);
|
||||||
|
|
||||||
return makeSpan([options.style.reset(), newStyle.cls()], inner);
|
// Add style-resetting classes to the inner list. Handle nested changes.
|
||||||
|
for (var i = 0; i < inner.length; i++) {
|
||||||
|
var pos = utils.indexOf(inner[i].classes, newStyle.reset());
|
||||||
|
if (pos < 0) {
|
||||||
|
inner[i].classes.push(options.style.reset(), newStyle.cls());
|
||||||
|
} else {
|
||||||
|
// This is a nested style change, as `\textstyle a\scriptstyle b`.
|
||||||
|
// Only override the old style (the reset class).
|
||||||
|
inner[i].classes[pos] = options.style.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new buildCommon.makeFragment(inner);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.font = function(group, options, prev) {
|
groupTypes.font = function(group, options, prev) {
|
||||||
@@ -1109,7 +1192,8 @@ groupTypes.delimsizing = function(group, options, prev) {
|
|||||||
return makeSpan(
|
return makeSpan(
|
||||||
[groupToType[group.value.delimType]],
|
[groupToType[group.value.delimType]],
|
||||||
[delimiter.sizedDelim(
|
[delimiter.sizedDelim(
|
||||||
delim, group.value.size, options, group.mode)]);
|
delim, group.value.size, options, group.mode)],
|
||||||
|
options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.leftright = function(group, options, prev) {
|
groupTypes.leftright = function(group, options, prev) {
|
||||||
@@ -1160,12 +1244,12 @@ groupTypes.leftright = function(group, options, prev) {
|
|||||||
inner.push(rightDelim);
|
inner.push(rightDelim);
|
||||||
|
|
||||||
return makeSpan(
|
return makeSpan(
|
||||||
["minner", style.cls()], inner, options.getColor());
|
["minner", style.cls()], inner, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
groupTypes.rule = function(group, options, prev) {
|
groupTypes.rule = function(group, options, prev) {
|
||||||
// Make an empty span for the rule
|
// Make an empty span for the rule
|
||||||
var rule = makeSpan(["mord", "rule"], [], options.getColor());
|
var rule = makeSpan(["mord", "rule"], [], options);
|
||||||
var style = options.style;
|
var style = options.style;
|
||||||
|
|
||||||
// Calculate the shift, width, and height of the rule, and account for units
|
// Calculate the shift, width, and height of the rule, and account for units
|
||||||
@@ -1208,7 +1292,7 @@ groupTypes.rule = function(group, options, prev) {
|
|||||||
|
|
||||||
groupTypes.kern = function(group, options, prev) {
|
groupTypes.kern = function(group, options, prev) {
|
||||||
// Make an empty span for the rule
|
// Make an empty span for the rule
|
||||||
var rule = makeSpan(["mord", "rule"], [], options.getColor());
|
var rule = makeSpan(["mord", "rule"], [], options);
|
||||||
var style = options.style;
|
var style = options.style;
|
||||||
|
|
||||||
var dimension = 0;
|
var dimension = 0;
|
||||||
@@ -1290,7 +1374,7 @@ groupTypes.accent = function(group, options, prev) {
|
|||||||
|
|
||||||
// Build the accent
|
// Build the accent
|
||||||
var accent = buildCommon.makeSymbol(
|
var accent = buildCommon.makeSymbol(
|
||||||
group.value.accent, "Main-Regular", "math", options.getColor());
|
group.value.accent, "Main-Regular", "math", options);
|
||||||
// Remove the italic correction of the accent, because it only serves to
|
// Remove the italic correction of the accent, because it only serves to
|
||||||
// shift the accent over to a place we don't want.
|
// shift the accent over to a place we don't want.
|
||||||
accent.italic = 0;
|
accent.italic = 0;
|
||||||
@@ -1315,7 +1399,7 @@ groupTypes.accent = function(group, options, prev) {
|
|||||||
// we shift it to the right by 1*skew.
|
// we shift it to the right by 1*skew.
|
||||||
accentBody.children[1].style.marginLeft = 2 * skew + "em";
|
accentBody.children[1].style.marginLeft = 2 * skew + "em";
|
||||||
|
|
||||||
var accentWrap = makeSpan(["mord", "accent"], [accentBody]);
|
var accentWrap = makeSpan(["mord", "accent"], [accentBody], options);
|
||||||
|
|
||||||
if (supsubGroup) {
|
if (supsubGroup) {
|
||||||
// Here, we replace the "base" child of the supsub with our newly
|
// Here, we replace the "base" child of the supsub with our newly
|
||||||
@@ -1400,7 +1484,7 @@ var buildHTML = function(tree, options) {
|
|||||||
|
|
||||||
// Build the expression contained in the tree
|
// Build the expression contained in the tree
|
||||||
var expression = buildExpression(tree, options);
|
var expression = buildExpression(tree, options);
|
||||||
var body = makeSpan(["base", options.style.cls()], expression);
|
var body = makeSpan(["base", options.style.cls()], expression, options);
|
||||||
|
|
||||||
// Add struts, which ensure that the top of the HTML element falls at the
|
// Add struts, which ensure that the top of the HTML element falls at the
|
||||||
// height of the expression, and the bottom of the HTML element falls at the
|
// height of the expression, and the bottom of the HTML element falls at the
|
||||||
|
@@ -47,8 +47,9 @@ var getMetrics = function(symbol, font) {
|
|||||||
/**
|
/**
|
||||||
* Builds a symbol in the given font size (note size is an integer)
|
* Builds a symbol in the given font size (note size is an integer)
|
||||||
*/
|
*/
|
||||||
var mathrmSize = function(value, size, mode) {
|
var mathrmSize = function(value, size, mode, options) {
|
||||||
return buildCommon.makeSymbol(value, "Size" + size + "-Regular", mode);
|
return buildCommon.makeSymbol(value, "Size" + size + "-Regular",
|
||||||
|
mode, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,7 +58,7 @@ var mathrmSize = function(value, size, mode) {
|
|||||||
*/
|
*/
|
||||||
var styleWrap = function(delim, toStyle, options) {
|
var styleWrap = function(delim, toStyle, options) {
|
||||||
var span = makeSpan(
|
var span = makeSpan(
|
||||||
["style-wrap", options.style.reset(), toStyle.cls()], [delim]);
|
["style-wrap", options.style.reset(), toStyle.cls()], [delim], options);
|
||||||
|
|
||||||
var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
|
var multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ var styleWrap = function(delim, toStyle, options) {
|
|||||||
* scriptscriptstyle.
|
* scriptscriptstyle.
|
||||||
*/
|
*/
|
||||||
var makeSmallDelim = function(delim, style, center, options, mode) {
|
var makeSmallDelim = function(delim, style, center, options, mode) {
|
||||||
var text = buildCommon.makeSymbol(delim, "Main-Regular", mode);
|
var text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options);
|
||||||
|
|
||||||
var span = styleWrap(text, style, options);
|
var span = styleWrap(text, style, options);
|
||||||
|
|
||||||
@@ -96,11 +97,11 @@ var makeSmallDelim = function(delim, style, center, options, mode) {
|
|||||||
* Size3, or Size4 fonts. It is always rendered in textstyle.
|
* Size3, or Size4 fonts. It is always rendered in textstyle.
|
||||||
*/
|
*/
|
||||||
var makeLargeDelim = function(delim, size, center, options, mode) {
|
var makeLargeDelim = function(delim, size, center, options, mode) {
|
||||||
var inner = mathrmSize(delim, size, mode);
|
var inner = mathrmSize(delim, size, mode, options);
|
||||||
|
|
||||||
var span = styleWrap(
|
var span = styleWrap(
|
||||||
makeSpan(["delimsizing", "size" + size],
|
makeSpan(["delimsizing", "size" + size],
|
||||||
[inner], options.getColor()),
|
[inner], options),
|
||||||
Style.TEXT, options);
|
Style.TEXT, options);
|
||||||
|
|
||||||
if (center) {
|
if (center) {
|
||||||
@@ -318,7 +319,7 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
|
|||||||
var inner = buildCommon.makeVList(inners, "bottom", depth, options);
|
var inner = buildCommon.makeVList(inners, "bottom", depth, options);
|
||||||
|
|
||||||
return styleWrap(
|
return styleWrap(
|
||||||
makeSpan(["delimsizing", "mult"], [inner], options.getColor()),
|
makeSpan(["delimsizing", "mult"], [inner], options),
|
||||||
Style.TEXT, options);
|
Style.TEXT, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -30,14 +30,22 @@ var createClass = function(classes) {
|
|||||||
* an inline style. It also contains information about its height, depth, and
|
* an inline style. It also contains information about its height, depth, and
|
||||||
* maxFontSize.
|
* maxFontSize.
|
||||||
*/
|
*/
|
||||||
function span(classes, children, height, depth, maxFontSize, style) {
|
function span(classes, children, options) {
|
||||||
this.classes = classes || [];
|
this.classes = classes || [];
|
||||||
this.children = children || [];
|
this.children = children || [];
|
||||||
this.height = height || 0;
|
this.height = 0;
|
||||||
this.depth = depth || 0;
|
this.depth = 0;
|
||||||
this.maxFontSize = maxFontSize || 0;
|
this.maxFontSize = 0;
|
||||||
this.style = style || {};
|
this.style = {};
|
||||||
this.attributes = {};
|
this.attributes = {};
|
||||||
|
if (options) {
|
||||||
|
if (options.style.isTight()) {
|
||||||
|
this.classes.push("mtight");
|
||||||
|
}
|
||||||
|
if (options.getColor()) {
|
||||||
|
this.style.color = options.getColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,11 +141,11 @@ span.prototype.toMarkup = function() {
|
|||||||
* contains children and doesn't have any HTML properties. It also keeps track
|
* contains children and doesn't have any HTML properties. It also keeps track
|
||||||
* of a height, depth, and maxFontSize.
|
* of a height, depth, and maxFontSize.
|
||||||
*/
|
*/
|
||||||
function documentFragment(children, height, depth, maxFontSize) {
|
function documentFragment(children) {
|
||||||
this.children = children || [];
|
this.children = children || [];
|
||||||
this.height = height || 0;
|
this.height = 0;
|
||||||
this.depth = depth || 0;
|
this.depth = 0;
|
||||||
this.maxFontSize = maxFontSize || 0;
|
this.maxFontSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -101,8 +101,8 @@
|
|||||||
@mediumspace: 0.22222em;
|
@mediumspace: 0.22222em;
|
||||||
@thickspace: 0.27778em;
|
@thickspace: 0.27778em;
|
||||||
|
|
||||||
.textstyle {
|
// These spacings apply in textstyle and displaystyle.
|
||||||
> .mord {
|
.mord {
|
||||||
& + .mord {}
|
& + .mord {}
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop { margin-left: @thinspace; }
|
||||||
& + .mbin { margin-left: @mediumspace; }
|
& + .mbin { margin-left: @mediumspace; }
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
& + .minner { margin-left: @thinspace; }
|
& + .minner { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mop {
|
.mop {
|
||||||
& + .mord { margin-left: @thinspace; }
|
& + .mord { margin-left: @thinspace; }
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop { margin-left: @thinspace; }
|
||||||
& + .mbin {}
|
& + .mbin {}
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
& + .minner { margin-left: @thinspace; }
|
& + .minner { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mbin {
|
.mbin {
|
||||||
& + .mord { margin-left: @mediumspace; }
|
& + .mord { margin-left: @mediumspace; }
|
||||||
& + .mop { margin-left: @mediumspace; }
|
& + .mop { margin-left: @mediumspace; }
|
||||||
& + .mbin {}
|
& + .mbin {}
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
& + .minner { margin-left: @mediumspace; }
|
& + .minner { margin-left: @mediumspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mrel {
|
.mrel {
|
||||||
& + .mord { margin-left: @thickspace; }
|
& + .mord { margin-left: @thickspace; }
|
||||||
& + .mop { margin-left: @thickspace; }
|
& + .mop { margin-left: @thickspace; }
|
||||||
& + .mbin {}
|
& + .mbin {}
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
& + .minner { margin-left: @thickspace; }
|
& + .minner { margin-left: @thickspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mopen {
|
.mopen {
|
||||||
& + .mord {}
|
& + .mord {}
|
||||||
& + .mop {}
|
& + .mop {}
|
||||||
& + .mbin {}
|
& + .mbin {}
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
& + .minner {}
|
& + .minner {}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mclose {
|
.mclose {
|
||||||
& + .mord {}
|
& + .mord {}
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop { margin-left: @thinspace; }
|
||||||
& + .mbin { margin-left: @mediumspace; }
|
& + .mbin { margin-left: @mediumspace; }
|
||||||
@@ -168,7 +168,7 @@
|
|||||||
& + .minner { margin-left: @thinspace; }
|
& + .minner { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mpunct {
|
.mpunct {
|
||||||
& + .mord { margin-left: @thinspace; }
|
& + .mord { margin-left: @thinspace; }
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop { margin-left: @thinspace; }
|
||||||
& + .mbin {}
|
& + .mbin {}
|
||||||
@@ -179,7 +179,7 @@
|
|||||||
& + .minner { margin-left: @thinspace; }
|
& + .minner { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
> .minner {
|
.minner {
|
||||||
& + .mord { margin-left: @thinspace; }
|
& + .mord { margin-left: @thinspace; }
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop { margin-left: @thinspace; }
|
||||||
& + .mbin { margin-left: @mediumspace; }
|
& + .mbin { margin-left: @mediumspace; }
|
||||||
@@ -189,23 +189,32 @@
|
|||||||
& + .mpunct { margin-left: @thinspace; }
|
& + .mpunct { margin-left: @thinspace; }
|
||||||
& + .minner { margin-left: @thinspace; }
|
& + .minner { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// These tighter spacings apply in scriptstyle and scriptscriptstyle.
|
||||||
|
.mord.mtight { margin-left: 0; }
|
||||||
|
.mop.mtight { margin-left: 0; }
|
||||||
|
.mbin.mtight { margin-left: 0; }
|
||||||
|
.mrel.mtight { margin-left: 0; }
|
||||||
|
.mopen.mtight { margin-left: 0; }
|
||||||
|
.mclose.mtight { margin-left: 0; }
|
||||||
|
.mpunct.mtight { margin-left: 0; }
|
||||||
|
.minner.mtight { margin-left: 0; }
|
||||||
|
|
||||||
.mord {
|
.mord {
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop.mtight { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.mop {
|
.mop {
|
||||||
& + .mord { margin-left: @thinspace; }
|
& + .mord.mtight { margin-left: @thinspace; }
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop.mtight { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.mclose {
|
.mclose {
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop.mtight { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.minner {
|
.minner {
|
||||||
& + .mop { margin-left: @thinspace; }
|
& + .mop.mtight { margin-left: @thinspace; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.reset-textstyle.textstyle { font-size: 1em; }
|
.reset-textstyle.textstyle { font-size: 1em; }
|
||||||
|
@@ -1581,7 +1581,8 @@ describe("A bin builder", function() {
|
|||||||
|
|
||||||
it("should correctly interact with color objects", function() {
|
it("should correctly interact with color objects", function() {
|
||||||
expect(getBuilt("\\blue{x}+y")[1].classes).toContain("mbin");
|
expect(getBuilt("\\blue{x}+y")[1].classes).toContain("mbin");
|
||||||
expect(getBuilt("\\blue{x+}+y")[1].classes).toContain("mord");
|
expect(getBuilt("\\blue{x+}+y")[1].classes).toContain("mbin");
|
||||||
|
expect(getBuilt("\\blue{x+}+y")[2].classes).toContain("mord");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1695,17 +1696,17 @@ describe("A phantom builder", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should make the children transparent", function() {
|
it("should make the children transparent", function() {
|
||||||
var children = getBuilt("\\phantom{x+1}")[0].children;
|
var children = getBuilt("\\phantom{x+1}");
|
||||||
expect(children[0].style.color).toBe("transparent");
|
expect(children[0].style.color).toBe("transparent");
|
||||||
expect(children[1].style.color).toBe("transparent");
|
expect(children[1].style.color).toBe("transparent");
|
||||||
expect(children[2].style.color).toBe("transparent");
|
expect(children[2].style.color).toBe("transparent");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should make all descendants transparent", function() {
|
it("should make all descendants transparent", function() {
|
||||||
var children = getBuilt("\\phantom{x+\\blue{1}}")[0].children;
|
var children = getBuilt("\\phantom{x+\\blue{1}}");
|
||||||
expect(children[0].style.color).toBe("transparent");
|
expect(children[0].style.color).toBe("transparent");
|
||||||
expect(children[1].style.color).toBe("transparent");
|
expect(children[1].style.color).toBe("transparent");
|
||||||
expect(children[2].children[0].style.color).toBe("transparent");
|
expect(children[2].style.color).toBe("transparent");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BIN
test/screenshotter/images/BoldSpacing-chrome.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
test/screenshotter/images/BoldSpacing-firefox.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
test/screenshotter/images/ColorSpacing-chrome.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
test/screenshotter/images/ColorSpacing-firefox.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
test/screenshotter/images/NegativeSpaceBetweenRel-chrome.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
test/screenshotter/images/NegativeSpaceBetweenRel-firefox.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
BIN
test/screenshotter/images/StyleSwitching-chrome.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
test/screenshotter/images/StyleSwitching-firefox.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
@@ -27,6 +27,7 @@ ArrayType: 1\begin{array}{c}2\\3\end{array}4
|
|||||||
Baseline: a+b-c\cdot d/e
|
Baseline: a+b-c\cdot d/e
|
||||||
BasicTest: a
|
BasicTest: a
|
||||||
BinomTest: \dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17}
|
BinomTest: \dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17}
|
||||||
|
BoldSpacing: \mathbf{A}^2+\mathbf{B}_3*\mathscr{C}'
|
||||||
Cases: |
|
Cases: |
|
||||||
f(a,b)=\begin{cases}
|
f(a,b)=\begin{cases}
|
||||||
a+1&\text{if }b\text{ is odd} \\
|
a+1&\text{if }b\text{ is odd} \\
|
||||||
@@ -36,6 +37,7 @@ Cases: |
|
|||||||
Colors:
|
Colors:
|
||||||
tex: \blue{a}\color{#0f0}{b}\color{red}{c}
|
tex: \blue{a}\color{#0f0}{b}\color{red}{c}
|
||||||
nolatex: different syntax and different scope
|
nolatex: different syntax and different scope
|
||||||
|
ColorSpacing: \color{red}{\displaystyle \int x} + 1
|
||||||
DashesAndQuotes: \text{``a'' b---c -- d----`e'-{-}-f}--``x''
|
DashesAndQuotes: \text{``a'' b---c -- d----`e'-{-}-f}--``x''
|
||||||
DeepFontSizing:
|
DeepFontSizing:
|
||||||
tex: |
|
tex: |
|
||||||
@@ -82,6 +84,7 @@ MathRm: \mathrm{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
|||||||
MathSf: \mathsf{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}
|
MathScr: \mathscr{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||||
MathTt: \mathtt{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
MathTt: \mathtt{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
|
||||||
|
NegativeSpaceBetweenRel: A =\!= B
|
||||||
NestedFractions: |
|
NestedFractions: |
|
||||||
\dfrac{\frac{a}{b}}{\frac{c}{d}}\dfrac{\dfrac{a}{b}}
|
\dfrac{\frac{a}{b}}{\frac{c}{d}}\dfrac{\dfrac{a}{b}}
|
||||||
{\dfrac{c}{d}}\frac{\frac{a}{b}}{\frac{c}{d}}
|
{\dfrac{c}{d}}\frac{\frac{a}{b}}{\frac{c}{d}}
|
||||||
@@ -106,6 +109,7 @@ Sqrt: |
|
|||||||
^{\sqrt{\sqrt{\sqrt{x}}}}}
|
^{\sqrt{\sqrt{\sqrt{x}}}}}
|
||||||
SqrtRoot: |
|
SqrtRoot: |
|
||||||
1+\sqrt[3]{2}+\sqrt[1923^234]{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}}
|
1+\sqrt[3]{2}+\sqrt[1923^234]{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}}
|
||||||
|
StyleSwitching: a\cdot b\scriptstyle a\cdot ba\textstyle\cdot ba\scriptstyle\cdot b
|
||||||
SupSubCharacterBox: a_2f_2{f}_2{aa}_2{af}_2\mathbf{y}_Ay_A
|
SupSubCharacterBox: a_2f_2{f}_2{aa}_2{af}_2\mathbf{y}_Ay_A
|
||||||
SupSubHorizSpacing: |
|
SupSubHorizSpacing: |
|
||||||
x^{x^{x}}\Big|x_{x_{x_{x_{x}}}}\bigg|x^{x^{x_{x_{x_{x_{x}}}}}}\bigg|
|
x^{x^{x}}\Big|x_{x_{x_{x_{x}}}}\bigg|x^{x^{x_{x_{x_{x_{x}}}}}}\bigg|
|
||||||
|