Support \colorbox and \fcolorbox (#886)

* Support \colorbox and \\fcolorbox

These are functions from the `color` package. They accept text, not math. They also have padding similar to `\fbox`.

Because of the padding, the code in `buildHTML` is intermixed with the `\fbox` code. I have not (yet) created a new file in the functions folder. This way, the reviewer gets a cleaner diff.

* Fix lint error

* colorbox screenshots

* Pick up review comments
This commit is contained in:
Ron Kok
2017-09-15 21:55:13 -07:00
committed by Kevin Barabash
parent 9b63ddabb4
commit db1cccdeab
11 changed files with 194 additions and 22 deletions

View File

@@ -1533,43 +1533,63 @@ groupTypes.accentUnder = function(group, options) {
};
groupTypes.enclose = function(group, options) {
// \cancel, \bcancel, \xcancel, \sout, \fbox
// \cancel, \bcancel, \xcancel, \sout, \fbox, \colorbox, \fcolorbox
const inner = buildGroup(group.value.body, options);
const label = group.value.label.substr(1);
const scale = options.sizeMultiplier;
let img;
let pad = 0;
let imgShift = 0;
const isColorbox = /color/.test(label);
if (label === "sout") {
img = makeSpan(["stretchy", "sout"]);
img.height = options.fontMetrics().defaultRuleThickness / scale;
imgShift = -0.5 * options.fontMetrics().xHeight;
} else {
// Add horizontal padding
inner.classes.push((label === "fbox" ? "boxpad" : "cancel-pad"));
inner.classes.push(/cancel/.test(label) ? "cancel-pad" : "boxpad");
// Add vertical padding
const isCharBox = (isCharacterBox(group.value.body));
let vertPad = 0;
// ref: LaTeX source2e: \fboxsep = 3pt; \fboxrule = .4pt
// ref: cancel package: \advance\totalheight2\p@ % "+2"
pad = (label === "fbox" ? 0.34 : (isCharBox ? 0.2 : 0));
imgShift = inner.depth + pad;
if (/box/.test(label)) {
vertPad = label === "colorbox" ? 0.3 : 0.34;
} else {
vertPad = isCharacterBox(group.value.body) ? 0.2 : 0;
}
img = stretchy.encloseSpan(inner, label, pad, options);
img = stretchy.encloseSpan(inner, label, vertPad, options);
imgShift = inner.depth + vertPad;
if (isColorbox) {
img.style.backgroundColor = group.value.backgroundColor.value;
if (label === "fcolorbox") {
img.style.borderColor = group.value.borderColor.value;
}
}
}
const vlist = buildCommon.makeVList([
{type: "elem", elem: inner, shift: 0},
{type: "elem", elem: img, shift: imgShift},
], "individualShift", null, options);
if (label !== "fbox") {
vlist.children[0].children[0].children[1].classes.push("svg-align");
let vlist;
if (isColorbox) {
vlist = buildCommon.makeVList([
// Put the color background behind inner;
{type: "elem", elem: img, shift: imgShift},
{type: "elem", elem: inner, shift: 0},
], "individualShift", null, options);
} else {
vlist = buildCommon.makeVList([
// Write the \cancel stroke on top of inner.
{type: "elem", elem: inner, shift: 0},
{type: "elem", elem: img, shift: imgShift},
], "individualShift", null, options);
}
if (/cancel/.test(label)) {
vlist.children[0].children[0].children[1].classes.push("svg-align");
// cancel does not create horiz space for its line extension.
// That is, not when adjacent to a mord.
return makeSpan(["mord", "cancel-lap"], [vlist], options);

View File

@@ -505,21 +505,33 @@ groupTypes.accentUnder = function(group, options) {
groupTypes.enclose = function(group, options) {
const node = new mathMLTree.MathNode(
"menclose", [buildGroup(group.value.body, options)]);
let notation = "";
switch (group.value.label) {
case "\\cancel":
node.setAttribute("notation", "updiagonalstrike");
break;
case "\\bcancel":
notation = "downdiagonalstrike";
node.setAttribute("notation", "downdiagonalstrike");
break;
case "\\sout":
notation = "horizontalstrike";
node.setAttribute("notation", "horizontalstrike");
break;
case "\\fbox":
notation = "box";
node.setAttribute("notation", "box");
break;
case "\\colorbox":
node.setAttribute("mathbackground",
group.value.backgroundColor.value);
break;
case "\\fcolorbox":
node.setAttribute("mathbackground",
group.value.backgroundColor.value);
// TODO(ron): I don't know any way to set the border color.
node.setAttribute("notation", "box");
break;
default:
notation = "updiagonalstrike";
// xcancel
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
}
node.setAttribute("notation", notation);
return node;
};

View File

@@ -88,6 +88,42 @@ defineFunction(["\\color"], {
argTypes: ["color"],
}, null);
// colorbox
defineFunction(["\\colorbox"], {
numArgs: 2,
allowedInText: true,
greediness: 3,
argTypes: ["color", "text"],
}, function(context, args) {
const color = args[0];
const body = args[1];
return {
type: "enclose",
label: context.funcName,
backgroundColor: color,
body: body,
};
});
// fcolorbox
defineFunction(["\\fcolorbox"], {
numArgs: 3,
allowedInText: true,
greediness: 3,
argTypes: ["color", "color", "text"],
}, function(context, args) {
const borderColor = args[0];
const backgroundColor = args[1];
const body = args[2];
return {
type: "enclose",
label: context.funcName,
backgroundColor: backgroundColor,
borderColor: borderColor,
body: body,
};
});
// An overline
defineFunction(["\\overline"], {
numArgs: 1,

View File

@@ -254,11 +254,13 @@ const encloseSpan = function(inner, label, pad, options) {
let img;
const totalHeight = inner.height + inner.depth + 2 * pad;
if (label === "fbox") {
if (/(fbox)|(color)/.test(label)) {
img = buildCommon.makeSpan(["stretchy", label], [], options);
if (options.color) {
if (label === "fbox" && options.color) {
img.style.borderColor = options.getColor();
}
} else {
// \cancel, \bcancel, or \xcancel
// Since \cancel's SVG is inline and it omits the viewBox attribute,