Merge pull request #292 from kevinb7/fonts-p3_mathml
Adds MathML support for math font commands.
This commit is contained in:
commit
c428abca1e
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main options class. It contains the style, size, color and font
|
* 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
|
* of the current parse level. It also contains the style and size of the parent
|
||||||
* parse level, so size changes can be handled efficiently.
|
* parse level, so size changes can be handled efficiently.
|
||||||
*
|
*
|
||||||
|
|
|
@ -435,6 +435,7 @@ var fontMap = {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
fontMap: fontMap,
|
||||||
makeSymbol: makeSymbol,
|
makeSymbol: makeSymbol,
|
||||||
mathsym: mathsym,
|
mathsym: mathsym,
|
||||||
makeSpan: makeSpan,
|
makeSpan: makeSpan,
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
* called, to produce a final HTML tree.
|
* called, to produce a final HTML tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Options = require("./Options");
|
|
||||||
var ParseError = require("./ParseError");
|
var ParseError = require("./ParseError");
|
||||||
var Style = require("./Style");
|
var Style = require("./Style");
|
||||||
|
|
||||||
|
@ -1330,22 +1329,11 @@ var buildGroup = function(group, options, prev) {
|
||||||
* Take an entire parse tree, and build it into an appropriate set of HTML
|
* Take an entire parse tree, and build it into an appropriate set of HTML
|
||||||
* nodes.
|
* nodes.
|
||||||
*/
|
*/
|
||||||
var buildHTML = function(tree, settings) {
|
var buildHTML = function(tree, options) {
|
||||||
// buildExpression is destructive, so we need to make a clone
|
// buildExpression is destructive, so we need to make a clone
|
||||||
// of the incoming tree so that it isn't accidentally changed
|
// of the incoming tree so that it isn't accidentally changed
|
||||||
tree = JSON.parse(JSON.stringify(tree));
|
tree = JSON.parse(JSON.stringify(tree));
|
||||||
|
|
||||||
var startStyle = Style.TEXT;
|
|
||||||
if (settings.displayMode) {
|
|
||||||
startStyle = Style.DISPLAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the default options
|
|
||||||
var options = new Options({
|
|
||||||
style: startStyle,
|
|
||||||
size: "size5"
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
|
@ -5,11 +5,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var buildCommon = require("./buildCommon");
|
var buildCommon = require("./buildCommon");
|
||||||
|
var fontMetrics = require("./fontMetrics");
|
||||||
var mathMLTree = require("./mathMLTree");
|
var mathMLTree = require("./mathMLTree");
|
||||||
var ParseError = require("./ParseError");
|
var ParseError = require("./ParseError");
|
||||||
var symbols = require("./symbols");
|
var symbols = require("./symbols");
|
||||||
|
var utils = require("./utils");
|
||||||
|
|
||||||
var makeSpan = buildCommon.makeSpan;
|
var makeSpan = buildCommon.makeSpan;
|
||||||
|
var fontMap = buildCommon.fontMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a symbol and converts it into a MathML text node after performing
|
* Takes a symbol and converts it into a MathML text node after performing
|
||||||
|
@ -23,28 +26,70 @@ var makeText = function(text, mode) {
|
||||||
return new mathMLTree.TextNode(text);
|
return new mathMLTree.TextNode(text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the math variant as a string or null if none is required.
|
||||||
|
*/
|
||||||
|
var getVariant = function(group, options) {
|
||||||
|
var font = options.font;
|
||||||
|
if (!font) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mode = group.mode;
|
||||||
|
if (font === "mathit") {
|
||||||
|
return "italic";
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = group.value;
|
||||||
|
if (utils.contains(["\\imath", "\\jmath"], value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbols[mode][value] && symbols[mode][value].replace) {
|
||||||
|
value = symbols[mode][value].replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fontName = fontMap[font].fontName;
|
||||||
|
if (fontMetrics.getCharacterMetrics(value, fontName)) {
|
||||||
|
return fontMap[options.font].variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions for handling the different types of groups found in the parse
|
* Functions for handling the different types of groups found in the parse
|
||||||
* tree. Each function should take a parse group and return a MathML node.
|
* tree. Each function should take a parse group and return a MathML node.
|
||||||
*/
|
*/
|
||||||
var groupTypes = {
|
var groupTypes = {
|
||||||
mathord: function(group) {
|
mathord: function(group, options) {
|
||||||
var node = new mathMLTree.MathNode(
|
var node = new mathMLTree.MathNode(
|
||||||
"mi",
|
"mi",
|
||||||
[makeText(group.value, group.mode)]);
|
[makeText(group.value, group.mode)]);
|
||||||
|
|
||||||
|
var variant = getVariant(group, options);
|
||||||
|
if (variant) {
|
||||||
|
node.setAttribute("mathvariant", variant);
|
||||||
|
}
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
textord: function(group) {
|
textord: function(group, options) {
|
||||||
var text = makeText(group.value, group.mode);
|
var text = makeText(group.value, group.mode);
|
||||||
|
|
||||||
|
var variant = getVariant(group, options) || "normal";
|
||||||
|
|
||||||
var node;
|
var node;
|
||||||
if (/[0-9]/.test(group.value)) {
|
if (/[0-9]/.test(group.value)) {
|
||||||
|
// TODO(kevinb) merge adjacent <mn> nodes
|
||||||
|
// do it as a post processing step
|
||||||
node = new mathMLTree.MathNode("mn", [text]);
|
node = new mathMLTree.MathNode("mn", [text]);
|
||||||
|
if (options.font) {
|
||||||
|
node.setAttribute("mathvariant", variant);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
node = new mathMLTree.MathNode("mi", [text]);
|
node = new mathMLTree.MathNode("mi", [text]);
|
||||||
node.setAttribute("mathvariant", "normal");
|
node.setAttribute("mathvariant", variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
@ -94,24 +139,24 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
ordgroup: function(group) {
|
ordgroup: function(group, options) {
|
||||||
var inner = buildExpression(group.value);
|
var inner = buildExpression(group.value, options);
|
||||||
|
|
||||||
var node = new mathMLTree.MathNode("mrow", inner);
|
var node = new mathMLTree.MathNode("mrow", inner);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
text: function(group) {
|
text: function(group, options) {
|
||||||
var inner = buildExpression(group.value.body);
|
var inner = buildExpression(group.value.body, options);
|
||||||
|
|
||||||
var node = new mathMLTree.MathNode("mtext", inner);
|
var node = new mathMLTree.MathNode("mtext", inner);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
color: function(group) {
|
color: function(group, options) {
|
||||||
var inner = buildExpression(group.value.value);
|
var inner = buildExpression(group.value.value, options);
|
||||||
|
|
||||||
var node = new mathMLTree.MathNode("mstyle", inner);
|
var node = new mathMLTree.MathNode("mstyle", inner);
|
||||||
|
|
||||||
|
@ -120,15 +165,15 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
supsub: function(group) {
|
supsub: function(group, options) {
|
||||||
var children = [buildGroup(group.value.base)];
|
var children = [buildGroup(group.value.base, options)];
|
||||||
|
|
||||||
if (group.value.sub) {
|
if (group.value.sub) {
|
||||||
children.push(buildGroup(group.value.sub));
|
children.push(buildGroup(group.value.sub, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group.value.sup) {
|
if (group.value.sup) {
|
||||||
children.push(buildGroup(group.value.sup));
|
children.push(buildGroup(group.value.sup, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodeType;
|
var nodeType;
|
||||||
|
@ -145,11 +190,11 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
genfrac: function(group) {
|
genfrac: function(group, options) {
|
||||||
var node = new mathMLTree.MathNode(
|
var node = new mathMLTree.MathNode(
|
||||||
"mfrac",
|
"mfrac",
|
||||||
[buildGroup(group.value.numer),
|
[buildGroup(group.value.numer, options),
|
||||||
buildGroup(group.value.denom)]);
|
buildGroup(group.value.denom, options)]);
|
||||||
|
|
||||||
if (!group.value.hasBarLine) {
|
if (!group.value.hasBarLine) {
|
||||||
node.setAttribute("linethickness", "0px");
|
node.setAttribute("linethickness", "0px");
|
||||||
|
@ -186,35 +231,35 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
array: function(group) {
|
array: function(group, options) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
"mtable", group.value.body.map(function(row) {
|
"mtable", group.value.body.map(function(row) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
"mtr", row.map(function(cell) {
|
"mtr", row.map(function(cell) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
"mtd", [buildGroup(cell)]);
|
"mtd", [buildGroup(cell, options)]);
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
sqrt: function(group) {
|
sqrt: function(group, options) {
|
||||||
var node;
|
var node;
|
||||||
if (group.value.index) {
|
if (group.value.index) {
|
||||||
node = new mathMLTree.MathNode(
|
node = new mathMLTree.MathNode(
|
||||||
"mroot", [
|
"mroot", [
|
||||||
buildGroup(group.value.body),
|
buildGroup(group.value.body, options),
|
||||||
buildGroup(group.value.index)
|
buildGroup(group.value.index, options)
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
node = new mathMLTree.MathNode(
|
node = new mathMLTree.MathNode(
|
||||||
"msqrt", [buildGroup(group.value.body)]);
|
"msqrt", [buildGroup(group.value.body, options)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
leftright: function(group) {
|
leftright: function(group, options) {
|
||||||
var inner = buildExpression(group.value.body);
|
var inner = buildExpression(group.value.body, options);
|
||||||
|
|
||||||
if (group.value.left !== ".") {
|
if (group.value.left !== ".") {
|
||||||
var leftNode = new mathMLTree.MathNode(
|
var leftNode = new mathMLTree.MathNode(
|
||||||
|
@ -239,24 +284,19 @@ var groupTypes = {
|
||||||
return outerNode;
|
return outerNode;
|
||||||
},
|
},
|
||||||
|
|
||||||
accent: function(group) {
|
accent: function(group, options) {
|
||||||
var accentNode = new mathMLTree.MathNode(
|
var accentNode = new mathMLTree.MathNode(
|
||||||
"mo", [makeText(group.value.accent, group.mode)]);
|
"mo", [makeText(group.value.accent, group.mode)]);
|
||||||
|
|
||||||
var node = new mathMLTree.MathNode(
|
var node = new mathMLTree.MathNode(
|
||||||
"mover",
|
"mover",
|
||||||
[buildGroup(group.value.base),
|
[buildGroup(group.value.base, options),
|
||||||
accentNode]);
|
accentNode]);
|
||||||
|
|
||||||
node.setAttribute("accent", "true");
|
node.setAttribute("accent", "true");
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
font: function(group) {
|
|
||||||
// pass through so we can render something without throwing
|
|
||||||
return buildGroup(group.value.body);
|
|
||||||
},
|
|
||||||
|
|
||||||
spacing: function(group) {
|
spacing: function(group) {
|
||||||
var node;
|
var node;
|
||||||
|
@ -303,6 +343,11 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
font: function(group, options) {
|
||||||
|
var font = group.value.font;
|
||||||
|
return buildGroup(group.value.body, options.withFont(font));
|
||||||
|
},
|
||||||
|
|
||||||
delimsizing: function(group) {
|
delimsizing: function(group) {
|
||||||
var children = [];
|
var children = [];
|
||||||
|
|
||||||
|
@ -326,8 +371,8 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
styling: function(group) {
|
styling: function(group, options) {
|
||||||
var inner = buildExpression(group.value.value, inner);
|
var inner = buildExpression(group.value.value, options);
|
||||||
|
|
||||||
var node = new mathMLTree.MathNode("mstyle", inner);
|
var node = new mathMLTree.MathNode("mstyle", inner);
|
||||||
|
|
||||||
|
@ -346,28 +391,30 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
sizing: function(group) {
|
sizing: function(group, options) {
|
||||||
var inner = buildExpression(group.value.value);
|
var inner = buildExpression(group.value.value, options);
|
||||||
|
|
||||||
var node = new mathMLTree.MathNode("mstyle", inner);
|
var node = new mathMLTree.MathNode("mstyle", inner);
|
||||||
|
|
||||||
// TODO(emily): This doesn't produce the correct size for nested size
|
// TODO(emily): This doesn't produce the correct size for nested size
|
||||||
// changes, because we don't keep state of what style we're currently
|
// changes, because we don't keep state of what style we're currently
|
||||||
// in, so we can't reset the size to normal before changing it.
|
// in, so we can't reset the size to normal before changing it. Now
|
||||||
|
// that we're passing an options parameter we should be able to fix
|
||||||
|
// this.
|
||||||
node.setAttribute(
|
node.setAttribute(
|
||||||
"mathsize", buildCommon.sizingMultiplier[group.value.size] + "em");
|
"mathsize", buildCommon.sizingMultiplier[group.value.size] + "em");
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
overline: function(group) {
|
overline: function(group, options) {
|
||||||
var operator = new mathMLTree.MathNode(
|
var operator = new mathMLTree.MathNode(
|
||||||
"mo", [new mathMLTree.TextNode("\u203e")]);
|
"mo", [new mathMLTree.TextNode("\u203e")]);
|
||||||
operator.setAttribute("stretchy", "true");
|
operator.setAttribute("stretchy", "true");
|
||||||
|
|
||||||
var node = new mathMLTree.MathNode(
|
var node = new mathMLTree.MathNode(
|
||||||
"mover",
|
"mover",
|
||||||
[buildGroup(group.value.body),
|
[buildGroup(group.value.body, options),
|
||||||
operator]);
|
operator]);
|
||||||
node.setAttribute("accent", "true");
|
node.setAttribute("accent", "true");
|
||||||
|
|
||||||
|
@ -382,9 +429,9 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
llap: function(group) {
|
llap: function(group, options) {
|
||||||
var node = new mathMLTree.MathNode(
|
var node = new mathMLTree.MathNode(
|
||||||
"mpadded", [buildGroup(group.value.body)]);
|
"mpadded", [buildGroup(group.value.body, options)]);
|
||||||
|
|
||||||
node.setAttribute("lspace", "-1width");
|
node.setAttribute("lspace", "-1width");
|
||||||
node.setAttribute("width", "0px");
|
node.setAttribute("width", "0px");
|
||||||
|
@ -392,9 +439,9 @@ var groupTypes = {
|
||||||
return node;
|
return node;
|
||||||
},
|
},
|
||||||
|
|
||||||
rlap: function(group) {
|
rlap: function(group, options) {
|
||||||
var node = new mathMLTree.MathNode(
|
var node = new mathMLTree.MathNode(
|
||||||
"mpadded", [buildGroup(group.value.body)]);
|
"mpadded", [buildGroup(group.value.body, options)]);
|
||||||
|
|
||||||
node.setAttribute("width", "0px");
|
node.setAttribute("width", "0px");
|
||||||
|
|
||||||
|
@ -402,7 +449,7 @@ var groupTypes = {
|
||||||
},
|
},
|
||||||
|
|
||||||
phantom: function(group, options, prev) {
|
phantom: function(group, options, prev) {
|
||||||
var inner = buildExpression(group.value.value);
|
var inner = buildExpression(group.value.value, options);
|
||||||
return new mathMLTree.MathNode("mphantom", inner);
|
return new mathMLTree.MathNode("mphantom", inner);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -412,11 +459,11 @@ var groupTypes = {
|
||||||
* MathML nodes. A little simpler than the HTML version because we don't do any
|
* MathML nodes. A little simpler than the HTML version because we don't do any
|
||||||
* previous-node handling.
|
* previous-node handling.
|
||||||
*/
|
*/
|
||||||
var buildExpression = function(expression) {
|
var buildExpression = function(expression, options) {
|
||||||
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));
|
groups.push(buildGroup(group, options));
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
};
|
};
|
||||||
|
@ -425,14 +472,14 @@ var buildExpression = function(expression) {
|
||||||
* Takes a group from the parser and calls the appropriate groupTypes function
|
* Takes a group from the parser and calls the appropriate groupTypes function
|
||||||
* on it to produce a MathML node.
|
* on it to produce a MathML node.
|
||||||
*/
|
*/
|
||||||
var buildGroup = function(group) {
|
var buildGroup = function(group, options) {
|
||||||
if (!group) {
|
if (!group) {
|
||||||
return new mathMLTree.MathNode("mrow");
|
return new mathMLTree.MathNode("mrow");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupTypes[group.type]) {
|
if (groupTypes[group.type]) {
|
||||||
// Call the groupTypes function
|
// Call the groupTypes function
|
||||||
return groupTypes[group.type](group);
|
return groupTypes[group.type](group, options);
|
||||||
} else {
|
} else {
|
||||||
throw new ParseError(
|
throw new ParseError(
|
||||||
"Got group of unknown type: '" + group.type + "'");
|
"Got group of unknown type: '" + group.type + "'");
|
||||||
|
@ -447,8 +494,8 @@ var buildGroup = function(group) {
|
||||||
* Note that we actually return a domTree element with a `<math>` inside it so
|
* Note that we actually return a domTree element with a `<math>` inside it so
|
||||||
* we can do appropriate styling.
|
* we can do appropriate styling.
|
||||||
*/
|
*/
|
||||||
var buildMathML = function(tree, texExpression, settings) {
|
var buildMathML = function(tree, texExpression, options) {
|
||||||
var expression = buildExpression(tree);
|
var expression = buildExpression(tree, options);
|
||||||
|
|
||||||
// Wrap up the expression in an mrow so it is presented in the semantics
|
// Wrap up the expression in an mrow so it is presented in the semantics
|
||||||
// tag correctly.
|
// tag correctly.
|
||||||
|
|
|
@ -1,15 +1,30 @@
|
||||||
|
|
||||||
var buildHTML = require("./buildHTML");
|
var buildHTML = require("./buildHTML");
|
||||||
var buildMathML = require("./buildMathML");
|
var buildMathML = require("./buildMathML");
|
||||||
var buildCommon = require("./buildCommon");
|
var buildCommon = require("./buildCommon");
|
||||||
|
var Options = require("./Options");
|
||||||
|
var Settings = require("./Settings");
|
||||||
|
var Style = require("./Style");
|
||||||
|
|
||||||
var makeSpan = buildCommon.makeSpan;
|
var makeSpan = buildCommon.makeSpan;
|
||||||
|
|
||||||
var buildTree = function(tree, expression, settings) {
|
var buildTree = function(tree, expression, settings) {
|
||||||
|
settings = settings || new Settings({});
|
||||||
|
|
||||||
|
var startStyle = Style.TEXT;
|
||||||
|
if (settings.displayMode) {
|
||||||
|
startStyle = Style.DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the default options
|
||||||
|
var options = new Options({
|
||||||
|
style: startStyle,
|
||||||
|
size: "size5"
|
||||||
|
});
|
||||||
|
|
||||||
// `buildHTML` sometimes messes with the parse tree (like turning bins ->
|
// `buildHTML` sometimes messes with the parse tree (like turning bins ->
|
||||||
// ords), so we build the MathML version first.
|
// ords), so we build the MathML version first.
|
||||||
var mathMLNode = buildMathML(tree, expression, settings);
|
var mathMLNode = buildMathML(tree, expression, options);
|
||||||
var htmlNode = buildHTML(tree, settings);
|
var htmlNode = buildHTML(tree, options);
|
||||||
|
|
||||||
var katexNode = makeSpan(["katex"], [
|
var katexNode = makeSpan(["katex"], [
|
||||||
mathMLNode, htmlNode
|
mathMLNode, htmlNode
|
||||||
|
|
|
@ -4,27 +4,51 @@
|
||||||
/* global it: false */
|
/* global it: false */
|
||||||
/* global describe: false */
|
/* global describe: false */
|
||||||
|
|
||||||
var buildHTML = require("../src/buildHTML");
|
|
||||||
var buildMathML = require("../src/buildMathML");
|
var buildMathML = require("../src/buildMathML");
|
||||||
|
var buildTree = require("../src/buildTree");
|
||||||
var katex = require("../katex");
|
var katex = require("../katex");
|
||||||
var ParseError = require("../src/ParseError");
|
var ParseError = require("../src/ParseError");
|
||||||
var parseTree = require("../src/parseTree");
|
var parseTree = require("../src/parseTree");
|
||||||
|
var Options = require("../src/Options");
|
||||||
var Settings = require("../src/Settings");
|
var Settings = require("../src/Settings");
|
||||||
|
var Style = require("../src/Style");
|
||||||
|
|
||||||
var defaultSettings = new Settings({});
|
var defaultSettings = new Settings({});
|
||||||
|
var defaultOptions = new Options({
|
||||||
|
style: Style.TEXT,
|
||||||
|
size: "size5"
|
||||||
|
});
|
||||||
|
|
||||||
var getBuilt = function(expr, settings) {
|
var _getBuilt = function(expr, settings) {
|
||||||
var usedSettings = settings ? settings : defaultSettings;
|
var usedSettings = settings ? settings : defaultSettings;
|
||||||
|
|
||||||
expect(expr).toBuild(usedSettings);
|
|
||||||
|
|
||||||
var parsedTree = parseTree(expr, usedSettings);
|
var parsedTree = parseTree(expr, usedSettings);
|
||||||
var built = buildHTML(parsedTree, usedSettings);
|
var rootNode = buildTree(parsedTree, expr, usedSettings);
|
||||||
|
|
||||||
|
// grab the root node of the HTML rendering
|
||||||
|
var builtHTML = rootNode.children[1];
|
||||||
|
|
||||||
// Remove the outer .katex and .katex-inner layers
|
// Remove the outer .katex and .katex-inner layers
|
||||||
return built.children[2].children;
|
return builtHTML.children[2].children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the root node of the rendered HTML.
|
||||||
|
* @param expr
|
||||||
|
* @param settings
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
var getBuilt = function(expr, settings) {
|
||||||
|
var usedSettings = settings ? settings : defaultSettings;
|
||||||
|
expect(expr).toBuild(usedSettings);
|
||||||
|
return _getBuilt(expr, settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the root node of the parse tree.
|
||||||
|
* @param expr
|
||||||
|
* @param settings
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
var getParsed = function(expr, settings) {
|
var getParsed = function(expr, settings) {
|
||||||
var usedSettings = settings ? settings : defaultSettings;
|
var usedSettings = settings ? settings : defaultSettings;
|
||||||
|
|
||||||
|
@ -104,7 +128,7 @@ beforeEach(function() {
|
||||||
expect(actual).toParse(usedSettings);
|
expect(actual).toParse(usedSettings);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
buildHTML(parseTree(actual, usedSettings), usedSettings);
|
_getBuilt(actual, settings);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result.pass = false;
|
result.pass = false;
|
||||||
if (e instanceof ParseError) {
|
if (e instanceof ParseError) {
|
||||||
|
@ -1269,6 +1293,152 @@ describe("An HTML font tree-builder", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe("A MathML font tree-builder", function () {
|
||||||
|
var contents = "Ax2k\\omega\\Omega\\imath+";
|
||||||
|
|
||||||
|
it("should render " + contents + " with the correct mathvariants", function () {
|
||||||
|
var tree = getParsed(contents);
|
||||||
|
var markup = buildMathML(tree, contents, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi>A</mi>");
|
||||||
|
expect(markup).toContain("<mi>x</mi>");
|
||||||
|
expect(markup).toContain("<mn>2</mn>");
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathbb{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathbb{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"double-struck\">A</mi>");
|
||||||
|
expect(markup).toContain("<mi>x</mi>");
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"normal\">2</mn>");
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathrm{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathrm{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">A</mi>");
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">x</mi>");
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"normal\">2</mn>");
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathit{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathit{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"italic\">A</mi>");
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"italic\">x</mi>");
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"italic\">2</mn>");
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"italic\">\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"italic\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"italic\">\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathbf{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathbf{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"bold\">A</mi>");
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"bold\">x</mi>");
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"bold\">2</mn>");
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"bold\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathcal{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathcal{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"script\">A</mi>");
|
||||||
|
expect(markup).toContain("<mi>x</mi>"); // script is caps only
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"script\">2</mn>");
|
||||||
|
// MathJax marks everything below as "script" except \omega
|
||||||
|
// We don't have these glyphs in "caligraphic" and neither does MathJax
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathfrak{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathfrak{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"fraktur\">A</mi>");
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"fraktur\">x</mi>");
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"fraktur\">2</mn>");
|
||||||
|
// MathJax marks everything below as "fraktur" except \omega
|
||||||
|
// We don't have these glyphs in "fraktur" and neither does MathJax
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathscr{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathscr{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"script\">A</mi>");
|
||||||
|
// MathJax marks everything below as "script" except \omega
|
||||||
|
// We don't have these glyphs in "script" and neither does MathJax
|
||||||
|
expect(markup).toContain("<mi>x</mi>");
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"normal\">2</mn>");
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"normal\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render \\mathsf{" + contents + "} with the correct mathvariants", function () {
|
||||||
|
var tex = "\\mathsf{" + contents + "}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"sans-serif\">A</mi>");
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"sans-serif\">x</mi>");
|
||||||
|
expect(markup).toContain("<mn mathvariant=\"sans-serif\">2</mn>");
|
||||||
|
expect(markup).toContain("<mi>\u03c9</mi>"); // \omega
|
||||||
|
expect(markup).toContain("<mi mathvariant=\"sans-serif\">\u03A9</mi>"); // \Omega
|
||||||
|
expect(markup).toContain("<mi>\u0131</mi>"); // \imath
|
||||||
|
expect(markup).toContain("<mo>+</mo>");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render a combination of font and color changes", function () {
|
||||||
|
var tex = "\\color{blue}{\\mathbb R}";
|
||||||
|
var tree = getParsed(tex);
|
||||||
|
var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
var node = "<mstyle mathcolor=\"blue\">" +
|
||||||
|
"<mi mathvariant=\"double-struck\">R</mi>" +
|
||||||
|
"</mstyle>";
|
||||||
|
expect(markup).toContain(node);
|
||||||
|
|
||||||
|
// reverse the order of the commands
|
||||||
|
tex = "\\mathbb{\\color{blue}{R}}";
|
||||||
|
tree = getParsed(tex);
|
||||||
|
markup = buildMathML(tree, tex, defaultOptions).toMarkup();
|
||||||
|
node = "<mstyle mathcolor=\"blue\">" +
|
||||||
|
"<mi mathvariant=\"double-struck\">R</mi>" +
|
||||||
|
"</mstyle>";
|
||||||
|
expect(markup).toContain(node);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("A bin builder", function() {
|
describe("A bin builder", function() {
|
||||||
it("should create mbins normally", function() {
|
it("should create mbins normally", function() {
|
||||||
var built = getBuilt("x + y");
|
var built = getBuilt("x + y");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user