
Summary: This adds support for rendering KaTeX to both HTML and MathML with the intent of improving accessibility. To accomplish this, both MathML and HTML are rendered, but with the MathML visually hidden and the HTML spans aria-hidden. Hopefully, this should produce much better accessibility for KaTeX. Should fix/improve #38 Closes #189 Test Plan: - Ensure all the tests, and the new tests, still pass. - Ensure that for each of the group types in `buildHTML.js`, there is a corresponding one in `buildMathML.js`. - Ensure that the huxley screenshots didn't change (except for BinomTest, which changed because I fixed a bug in `buildHTML` where `genfrac` didn't have a `groupToType` mapping). - Run ChromeVox on the test page, render some math. (for example, `\sqrt{x^2}`) - Ensure that a mathy-sounding expression is read. (I hear "group square root of x squared math"). - Ensure that nothing else is read (like no "x" or "2"). - Ensure that MathML markup is generated correctly and is interpreted by the browser correctly by running `document.getElementById("math").innerHTML = katex.renderToString("\\sqrt{x^2}");` and seeing that the same speech is read. Reviewers: john, alpert Reviewed By: john, alpert Subscribers: alpert, john Differential Revision: https://phabricator.khanacademy.org/D16373
103 lines
2.6 KiB
JavaScript
103 lines
2.6 KiB
JavaScript
/**
|
|
* These objects store data about MathML nodes. This is the MathML equivalent
|
|
* of the types in domTree.js. Since MathML handles its own rendering, and
|
|
* since we're mainly using MathML to improve accessibility, we don't manage
|
|
* any of the styling state that the plain DOM nodes do.
|
|
*
|
|
* The `toNode` and `toMarkup` functions work simlarly to how they do in
|
|
* domTree.js, creating namespaced DOM nodes and HTML text markup respectively.
|
|
*/
|
|
|
|
var utils = require("./utils");
|
|
|
|
/**
|
|
* This node represents a general purpose MathML node of any type. The
|
|
* constructor requires the type of node to create (for example, `"mo"` or
|
|
* `"mspace"`, corresponding to `<mo>` and `<mspace>` tags).
|
|
*/
|
|
function MathNode(type, children) {
|
|
this.type = type;
|
|
this.attributes = {};
|
|
this.children = children || [];
|
|
}
|
|
|
|
/**
|
|
* Sets an attribute on a MathML node. MathML depends on attributes to convey a
|
|
* semantic content, so this is used heavily.
|
|
*/
|
|
MathNode.prototype.setAttribute = function(name, value) {
|
|
this.attributes[name] = value;
|
|
};
|
|
|
|
/**
|
|
* Converts the math node into a MathML-namespaced DOM element.
|
|
*/
|
|
MathNode.prototype.toNode = function() {
|
|
var node = document.createElementNS(
|
|
"http://www.w3.org/1998/Math/MathML", this.type);
|
|
|
|
for (var attr in this.attributes) {
|
|
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
|
node.setAttribute(attr, this.attributes[attr]);
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < this.children.length; i++) {
|
|
node.appendChild(this.children[i].toNode());
|
|
}
|
|
|
|
return node;
|
|
};
|
|
|
|
/**
|
|
* Converts the math node into an HTML markup string.
|
|
*/
|
|
MathNode.prototype.toMarkup = function() {
|
|
var markup = "<" + this.type;
|
|
|
|
// Add the attributes
|
|
for (var attr in this.attributes) {
|
|
if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) {
|
|
markup += " " + attr + "=\"";
|
|
markup += utils.escape(this.attributes[attr]);
|
|
markup += "\"";
|
|
}
|
|
}
|
|
|
|
markup += ">";
|
|
|
|
for (var i = 0; i < this.children.length; i++) {
|
|
markup += this.children[i].toMarkup();
|
|
}
|
|
|
|
markup += "</" + this.type + ">";
|
|
|
|
return markup;
|
|
};
|
|
|
|
/**
|
|
* This node represents a piece of text.
|
|
*/
|
|
function TextNode(text) {
|
|
this.text = text;
|
|
}
|
|
|
|
/**
|
|
* Converts the text node into a DOM text node.
|
|
*/
|
|
TextNode.prototype.toNode = function() {
|
|
return document.createTextNode(this.text);
|
|
};
|
|
|
|
/**
|
|
* Converts the text node into HTML markup (which is just the text itself).
|
|
*/
|
|
TextNode.prototype.toMarkup = function() {
|
|
return utils.escape(this.text);
|
|
};
|
|
|
|
module.exports = {
|
|
MathNode: MathNode,
|
|
TextNode: TextNode
|
|
};
|