@ -0,0 +1,119 @@ |
|||||
|
# [<img src="https://katex.org/img/katex-logo-black.svg" width="130" alt="KaTeX">](https://katex.org/) |
||||
|
[![npm](https://img.shields.io/npm/v/katex.svg)](https://www.npmjs.com/package/katex) |
||||
|
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) |
||||
|
[![CI](https://github.com/KaTeX/KaTeX/workflows/CI/badge.svg?branch=main&event=push)](https://github.com/KaTeX/KaTeX/actions?query=workflow%3ACI) |
||||
|
[![codecov](https://codecov.io/gh/KaTeX/KaTeX/branch/main/graph/badge.svg)](https://codecov.io/gh/KaTeX/KaTeX) |
||||
|
[![Discussions](https://img.shields.io/badge/Discussions-join-brightgreen)](https://github.com/KaTeX/KaTeX/discussions) |
||||
|
[![jsDelivr](https://data.jsdelivr.com/v1/package/npm/katex/badge?style=rounded)](https://www.jsdelivr.com/package/npm/katex) |
||||
|
![katex.min.js size](https://img.badgesize.io/https://unpkg.com/katex/dist/katex.min.js?compression=gzip) |
||||
|
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/KaTeX/KaTeX) |
||||
|
[![Financial Contributors on Open Collective](https://opencollective.com/katex/all/badge.svg?label=financial+contributors)](https://opencollective.com/katex) |
||||
|
|
||||
|
KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web. |
||||
|
|
||||
|
* **Fast:** KaTeX renders its math synchronously and doesn't need to reflow the page. See how it compares to a competitor in [this speed test](http://www.intmath.com/cg5/katex-mathjax-comparison.php). |
||||
|
* **Print quality:** KaTeX's layout is based on Donald Knuth's TeX, the gold standard for math typesetting. |
||||
|
* **Self contained:** KaTeX has no dependencies and can easily be bundled with your website resources. |
||||
|
* **Server side rendering:** KaTeX produces the same output regardless of browser or environment, so you can pre-render expressions using Node.js and send them as plain HTML. |
||||
|
|
||||
|
KaTeX is compatible with all major browsers, including Chrome, Safari, Firefox, Opera, Edge, and IE 11. |
||||
|
|
||||
|
KaTeX supports much (but not all) of LaTeX and many LaTeX packages. See the [list of supported functions](https://katex.org/docs/supported.html). |
||||
|
|
||||
|
Try out KaTeX [on the demo page](https://katex.org/#demo)! |
||||
|
|
||||
|
## Getting started |
||||
|
|
||||
|
### Starter template |
||||
|
|
||||
|
```html |
||||
|
<!DOCTYPE html> |
||||
|
<!-- KaTeX requires the use of the HTML5 doctype. Without it, KaTeX may not render properly --> |
||||
|
<html> |
||||
|
<head> |
||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.css" integrity="sha384-KiWOvVjnN8qwAZbuQyWDIbfCLFhLXNETzBQjA/92pIowpC0d2O3nppDGQVgwd2nB" crossorigin="anonymous"> |
||||
|
|
||||
|
<!-- The loading of KaTeX is deferred to speed up page rendering --> |
||||
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.js" integrity="sha384-0fdwu/T/EQMsQlrHCCHoH10pkPLlKA1jL5dFyUOvB3lfeT2540/2g6YgSi2BL14p" crossorigin="anonymous"></script> |
||||
|
|
||||
|
<!-- To automatically render math in text elements, include the auto-render extension: --> |
||||
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous" |
||||
|
onload="renderMathInElement(document.body);"></script> |
||||
|
</head> |
||||
|
... |
||||
|
</html> |
||||
|
``` |
||||
|
|
||||
|
You can also [download KaTeX](https://github.com/KaTeX/KaTeX/releases) and host it yourself. |
||||
|
|
||||
|
For details on how to configure auto-render extension, refer to [the documentation](https://katex.org/docs/autorender.html). |
||||
|
|
||||
|
### API |
||||
|
|
||||
|
Call `katex.render` to render a TeX expression directly into a DOM element. |
||||
|
For example: |
||||
|
|
||||
|
```js |
||||
|
katex.render("c = \\pm\\sqrt{a^2 + b^2}", element, { |
||||
|
throwOnError: false |
||||
|
}); |
||||
|
``` |
||||
|
|
||||
|
Call `katex.renderToString` to generate an HTML string of the rendered math, |
||||
|
e.g., for server-side rendering. For example: |
||||
|
|
||||
|
```js |
||||
|
var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}", { |
||||
|
throwOnError: false |
||||
|
}); |
||||
|
// '<span class="katex">...</span>' |
||||
|
``` |
||||
|
|
||||
|
Make sure to include the CSS and font files in both cases. |
||||
|
If you are doing all rendering on the server, there is no need to include the |
||||
|
JavaScript on the client. |
||||
|
|
||||
|
The examples above use the `throwOnError: false` option, which renders invalid |
||||
|
inputs as the TeX source code in red (by default), with the error message as |
||||
|
hover text. For other available options, see the |
||||
|
[API documentation](https://katex.org/docs/api.html), |
||||
|
[options documentation](https://katex.org/docs/options.html), and |
||||
|
[handling errors documentation](https://katex.org/docs/error.html). |
||||
|
|
||||
|
## Demo and Documentation |
||||
|
|
||||
|
Learn more about using KaTeX [on the website](https://katex.org)! |
||||
|
|
||||
|
## Contributors |
||||
|
|
||||
|
### Code Contributors |
||||
|
|
||||
|
This project exists thanks to all the people who contribute code. If you'd like to help, see [our guide to contributing code](CONTRIBUTING.md). |
||||
|
<a href="https://github.com/KaTeX/KaTeX/graphs/contributors"><img src="https://contributors-svg.opencollective.com/katex/contributors.svg?width=890&button=false" alt="Code contributors" /></a> |
||||
|
|
||||
|
### Financial Contributors |
||||
|
|
||||
|
Become a financial contributor and help us sustain our community. |
||||
|
|
||||
|
#### Individuals |
||||
|
|
||||
|
<a href="https://opencollective.com/katex"><img src="https://opencollective.com/katex/individuals.svg?width=890" alt="Contribute on Open Collective"></a> |
||||
|
|
||||
|
#### Organizations |
||||
|
|
||||
|
Support this project with your organization. Your logo will show up here with a link to your website. |
||||
|
|
||||
|
<a href="https://opencollective.com/katex/organization/0/website"><img src="https://opencollective.com/katex/organization/0/avatar.svg" alt="Organization 1"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/1/website"><img src="https://opencollective.com/katex/organization/1/avatar.svg" alt="Organization 2"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/2/website"><img src="https://opencollective.com/katex/organization/2/avatar.svg" alt="Organization 3"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/3/website"><img src="https://opencollective.com/katex/organization/3/avatar.svg" alt="Organization 4"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/4/website"><img src="https://opencollective.com/katex/organization/4/avatar.svg" alt="Organization 5"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/5/website"><img src="https://opencollective.com/katex/organization/5/avatar.svg" alt="Organization 6"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/6/website"><img src="https://opencollective.com/katex/organization/6/avatar.svg" alt="Organization 7"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/7/website"><img src="https://opencollective.com/katex/organization/7/avatar.svg" alt="Organization 8"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/8/website"><img src="https://opencollective.com/katex/organization/8/avatar.svg" alt="Organization 9"></a> |
||||
|
<a href="https://opencollective.com/katex/organization/9/website"><img src="https://opencollective.com/katex/organization/9/avatar.svg" alt="Organization 10"></a> |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
KaTeX is licensed under the [MIT License](http://opensource.org/licenses/MIT). |
@ -0,0 +1 @@ |
|||||
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={974:function(t){t.exports=e}},r={};function n(e){var a=r[e];if(void 0!==a)return a.exports;var i=r[e]={exports:{}};return t[e](i,i.exports,n),i.exports}n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,{a:t}),t},n.d=function(e,t){for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var a={};return function(){n.d(a,{default:function(){return s}});var e=n(974),t=n.n(e),r=function(e,t,r){for(var n=r,a=0,i=e.length;n<t.length;){var o=t[n];if(a<=0&&t.slice(n,n+i)===e)return n;"\\"===o?n++:"{"===o?a++:"}"===o&&a--,n++}return-1},i=/^\\begin{/,o=function(e,t){for(var n,a=[],o=new RegExp("("+t.map((function(e){return e.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")})).join("|")+")");-1!==(n=e.search(o));){n>0&&(a.push({type:"text",data:e.slice(0,n)}),e=e.slice(n));var l=t.findIndex((function(t){return e.startsWith(t.left)}));if(-1===(n=r(t[l].right,e,t[l].left.length)))break;var d=e.slice(0,n+t[l].right.length),s=i.test(d)?d:e.slice(t[l].left.length,n);a.push({type:"math",data:s,rawData:d,display:t[l].display}),e=e.slice(n+t[l].right.length)}return""!==e&&a.push({type:"text",data:e}),a},l=function(e,r){var n=o(e,r.delimiters);if(1===n.length&&"text"===n[0].type)return null;for(var a=document.createDocumentFragment(),i=0;i<n.length;i++)if("text"===n[i].type)a.appendChild(document.createTextNode(n[i].data));else{var l=document.createElement("span"),d=n[i].data;r.displayMode=n[i].display;try{r.preProcess&&(d=r.preProcess(d)),t().render(d,l,r)}catch(e){if(!(e instanceof t().ParseError))throw e;r.errorCallback("KaTeX auto-render: Failed to parse `"+n[i].data+"` with ",e),a.appendChild(document.createTextNode(n[i].rawData));continue}a.appendChild(l)}return a},d=function e(t,r){for(var n=0;n<t.childNodes.length;n++){var a=t.childNodes[n];if(3===a.nodeType){var i=l(a.textContent,r);i&&(n+=i.childNodes.length-1,t.replaceChild(i,a))}else 1===a.nodeType&&function(){var t=" "+a.className+" ";-1===r.ignoredTags.indexOf(a.nodeName.toLowerCase())&&r.ignoredClasses.every((function(e){return-1===t.indexOf(" "+e+" ")}))&&e(a,r)}()}},s=function(e,t){if(!e)throw new Error("No element provided to render");var r={};for(var n in t)t.hasOwnProperty(n)&&(r[n]=t[n]);r.delimiters=r.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],r.ignoredTags=r.ignoredTags||["script","noscript","style","textarea","pre","code","option"],r.ignoredClasses=r.ignoredClasses||[],r.errorCallback=r.errorCallback||console.error,r.macros=r.macros||{},d(e,r)}}(),a=a.default}()})); |
@ -0,0 +1,327 @@ |
|||||
|
(function webpackUniversalModuleDefinition(root, factory) { |
||||
|
if(typeof exports === 'object' && typeof module === 'object') |
||||
|
module.exports = factory(require("katex")); |
||||
|
else if(typeof define === 'function' && define.amd) |
||||
|
define(["katex"], factory); |
||||
|
else if(typeof exports === 'object') |
||||
|
exports["renderMathInElement"] = factory(require("katex")); |
||||
|
else |
||||
|
root["renderMathInElement"] = factory(root["katex"]); |
||||
|
})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__771__) { |
||||
|
return /******/ (function() { // webpackBootstrap
|
||||
|
/******/ "use strict"; |
||||
|
/******/ var __webpack_modules__ = ({ |
||||
|
|
||||
|
/***/ 771: |
||||
|
/***/ (function(module) { |
||||
|
|
||||
|
module.exports = __WEBPACK_EXTERNAL_MODULE__771__; |
||||
|
|
||||
|
/***/ }) |
||||
|
|
||||
|
/******/ }); |
||||
|
/************************************************************************/ |
||||
|
/******/ // The module cache
|
||||
|
/******/ var __webpack_module_cache__ = {}; |
||||
|
/******/ |
||||
|
/******/ // The require function
|
||||
|
/******/ function __webpack_require__(moduleId) { |
||||
|
/******/ // Check if module is in cache
|
||||
|
/******/ var cachedModule = __webpack_module_cache__[moduleId]; |
||||
|
/******/ if (cachedModule !== undefined) { |
||||
|
/******/ return cachedModule.exports; |
||||
|
/******/ } |
||||
|
/******/ // Create a new module (and put it into the cache)
|
||||
|
/******/ var module = __webpack_module_cache__[moduleId] = { |
||||
|
/******/ // no module.id needed
|
||||
|
/******/ // no module.loaded needed
|
||||
|
/******/ exports: {} |
||||
|
/******/ }; |
||||
|
/******/ |
||||
|
/******/ // Execute the module function
|
||||
|
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); |
||||
|
/******/ |
||||
|
/******/ // Return the exports of the module
|
||||
|
/******/ return module.exports; |
||||
|
/******/ } |
||||
|
/******/ |
||||
|
/************************************************************************/ |
||||
|
/******/ /* webpack/runtime/compat get default export */ |
||||
|
/******/ !function() { |
||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
|
/******/ __webpack_require__.n = function(module) { |
||||
|
/******/ var getter = module && module.__esModule ? |
||||
|
/******/ function() { return module['default']; } : |
||||
|
/******/ function() { return module; }; |
||||
|
/******/ __webpack_require__.d(getter, { a: getter }); |
||||
|
/******/ return getter; |
||||
|
/******/ }; |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/******/ /* webpack/runtime/define property getters */ |
||||
|
/******/ !function() { |
||||
|
/******/ // define getter functions for harmony exports
|
||||
|
/******/ __webpack_require__.d = function(exports, definition) { |
||||
|
/******/ for(var key in definition) { |
||||
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { |
||||
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); |
||||
|
/******/ } |
||||
|
/******/ } |
||||
|
/******/ }; |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */ |
||||
|
/******/ !function() { |
||||
|
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/************************************************************************/ |
||||
|
var __webpack_exports__ = {}; |
||||
|
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||
|
!function() { |
||||
|
|
||||
|
// EXPORTS
|
||||
|
__webpack_require__.d(__webpack_exports__, { |
||||
|
"default": function() { return /* binding */ auto_render; } |
||||
|
}); |
||||
|
|
||||
|
// EXTERNAL MODULE: external "katex"
|
||||
|
var external_katex_ = __webpack_require__(771); |
||||
|
var external_katex_default = /*#__PURE__*/__webpack_require__.n(external_katex_); |
||||
|
;// CONCATENATED MODULE: ./contrib/auto-render/splitAtDelimiters.js
|
||||
|
/* eslint no-constant-condition:0 */ |
||||
|
var findEndOfMath = function findEndOfMath(delimiter, text, startIndex) { |
||||
|
// Adapted from
|
||||
|
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
|
||||
|
var index = startIndex; |
||||
|
var braceLevel = 0; |
||||
|
var delimLength = delimiter.length; |
||||
|
|
||||
|
while (index < text.length) { |
||||
|
var character = text[index]; |
||||
|
|
||||
|
if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { |
||||
|
return index; |
||||
|
} else if (character === "\\") { |
||||
|
index++; |
||||
|
} else if (character === "{") { |
||||
|
braceLevel++; |
||||
|
} else if (character === "}") { |
||||
|
braceLevel--; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
return -1; |
||||
|
}; |
||||
|
|
||||
|
var escapeRegex = function escapeRegex(string) { |
||||
|
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); |
||||
|
}; |
||||
|
|
||||
|
var amsRegex = /^\\begin{/; |
||||
|
|
||||
|
var splitAtDelimiters = function splitAtDelimiters(text, delimiters) { |
||||
|
var index; |
||||
|
var data = []; |
||||
|
var regexLeft = new RegExp("(" + delimiters.map(function (x) { |
||||
|
return escapeRegex(x.left); |
||||
|
}).join("|") + ")"); |
||||
|
|
||||
|
while (true) { |
||||
|
index = text.search(regexLeft); |
||||
|
|
||||
|
if (index === -1) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (index > 0) { |
||||
|
data.push({ |
||||
|
type: "text", |
||||
|
data: text.slice(0, index) |
||||
|
}); |
||||
|
text = text.slice(index); // now text starts with delimiter
|
||||
|
} // ... so this always succeeds:
|
||||
|
|
||||
|
|
||||
|
var i = delimiters.findIndex(function (delim) { |
||||
|
return text.startsWith(delim.left); |
||||
|
}); |
||||
|
index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length); |
||||
|
|
||||
|
if (index === -1) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
var rawData = text.slice(0, index + delimiters[i].right.length); |
||||
|
var math = amsRegex.test(rawData) ? rawData : text.slice(delimiters[i].left.length, index); |
||||
|
data.push({ |
||||
|
type: "math", |
||||
|
data: math, |
||||
|
rawData: rawData, |
||||
|
display: delimiters[i].display |
||||
|
}); |
||||
|
text = text.slice(index + delimiters[i].right.length); |
||||
|
} |
||||
|
|
||||
|
if (text !== "") { |
||||
|
data.push({ |
||||
|
type: "text", |
||||
|
data: text |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return data; |
||||
|
}; |
||||
|
|
||||
|
/* harmony default export */ var auto_render_splitAtDelimiters = (splitAtDelimiters); |
||||
|
;// CONCATENATED MODULE: ./contrib/auto-render/auto-render.js
|
||||
|
/* eslint no-console:0 */ |
||||
|
|
||||
|
|
||||
|
/* Note: optionsCopy is mutated by this method. If it is ever exposed in the |
||||
|
* API, we should copy it before mutating. |
||||
|
*/ |
||||
|
|
||||
|
var renderMathInText = function renderMathInText(text, optionsCopy) { |
||||
|
var data = auto_render_splitAtDelimiters(text, optionsCopy.delimiters); |
||||
|
|
||||
|
if (data.length === 1 && data[0].type === 'text') { |
||||
|
// There is no formula in the text.
|
||||
|
// Let's return null which means there is no need to replace
|
||||
|
// the current text node with a new one.
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var fragment = document.createDocumentFragment(); |
||||
|
|
||||
|
for (var i = 0; i < data.length; i++) { |
||||
|
if (data[i].type === "text") { |
||||
|
fragment.appendChild(document.createTextNode(data[i].data)); |
||||
|
} else { |
||||
|
var span = document.createElement("span"); |
||||
|
var math = data[i].data; // Override any display mode defined in the settings with that
|
||||
|
// defined by the text itself
|
||||
|
|
||||
|
optionsCopy.displayMode = data[i].display; |
||||
|
|
||||
|
try { |
||||
|
if (optionsCopy.preProcess) { |
||||
|
math = optionsCopy.preProcess(math); |
||||
|
} |
||||
|
|
||||
|
external_katex_default().render(math, span, optionsCopy); |
||||
|
} catch (e) { |
||||
|
if (!(e instanceof (external_katex_default()).ParseError)) { |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
optionsCopy.errorCallback("KaTeX auto-render: Failed to parse `" + data[i].data + "` with ", e); |
||||
|
fragment.appendChild(document.createTextNode(data[i].rawData)); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
fragment.appendChild(span); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return fragment; |
||||
|
}; |
||||
|
|
||||
|
var renderElem = function renderElem(elem, optionsCopy) { |
||||
|
for (var i = 0; i < elem.childNodes.length; i++) { |
||||
|
var childNode = elem.childNodes[i]; |
||||
|
|
||||
|
if (childNode.nodeType === 3) { |
||||
|
// Text node
|
||||
|
var frag = renderMathInText(childNode.textContent, optionsCopy); |
||||
|
|
||||
|
if (frag) { |
||||
|
i += frag.childNodes.length - 1; |
||||
|
elem.replaceChild(frag, childNode); |
||||
|
} |
||||
|
} else if (childNode.nodeType === 1) { |
||||
|
(function () { |
||||
|
// Element node
|
||||
|
var className = ' ' + childNode.className + ' '; |
||||
|
var shouldRender = optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 && optionsCopy.ignoredClasses.every(function (x) { |
||||
|
return className.indexOf(' ' + x + ' ') === -1; |
||||
|
}); |
||||
|
|
||||
|
if (shouldRender) { |
||||
|
renderElem(childNode, optionsCopy); |
||||
|
} |
||||
|
})(); |
||||
|
} // Otherwise, it's something else, and ignore it.
|
||||
|
|
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var renderMathInElement = function renderMathInElement(elem, options) { |
||||
|
if (!elem) { |
||||
|
throw new Error("No element provided to render"); |
||||
|
} |
||||
|
|
||||
|
var optionsCopy = {}; // Object.assign(optionsCopy, option)
|
||||
|
|
||||
|
for (var option in options) { |
||||
|
if (options.hasOwnProperty(option)) { |
||||
|
optionsCopy[option] = options[option]; |
||||
|
} |
||||
|
} // default options
|
||||
|
|
||||
|
|
||||
|
optionsCopy.delimiters = optionsCopy.delimiters || [{ |
||||
|
left: "$$", |
||||
|
right: "$$", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\(", |
||||
|
right: "\\)", |
||||
|
display: false |
||||
|
}, // LaTeX uses $…$, but it ruins the display of normal `$` in text:
|
||||
|
// {left: "$", right: "$", display: false},
|
||||
|
// $ must come after $$
|
||||
|
// Render AMS environments even if outside $$…$$ delimiters.
|
||||
|
{ |
||||
|
left: "\\begin{equation}", |
||||
|
right: "\\end{equation}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{align}", |
||||
|
right: "\\end{align}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{alignat}", |
||||
|
right: "\\end{alignat}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{gather}", |
||||
|
right: "\\end{gather}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{CD}", |
||||
|
right: "\\end{CD}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\[", |
||||
|
right: "\\]", |
||||
|
display: true |
||||
|
}]; |
||||
|
optionsCopy.ignoredTags = optionsCopy.ignoredTags || ["script", "noscript", "style", "textarea", "pre", "code", "option"]; |
||||
|
optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; |
||||
|
optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; // Enable sharing of global macros defined via `\gdef` between different
|
||||
|
// math elements within a single call to `renderMathInElement`.
|
||||
|
|
||||
|
optionsCopy.macros = optionsCopy.macros || {}; |
||||
|
renderElem(elem, optionsCopy); |
||||
|
}; |
||||
|
|
||||
|
/* harmony default export */ var auto_render = (renderMathInElement); |
||||
|
}(); |
||||
|
__webpack_exports__ = __webpack_exports__["default"]; |
||||
|
/******/ return __webpack_exports__; |
||||
|
/******/ })() |
||||
|
; |
||||
|
}); |
@ -0,0 +1 @@ |
|||||
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={771:function(t){t.exports=e}},r={};function n(e){var a=r[e];if(void 0!==a)return a.exports;var i=r[e]={exports:{}};return t[e](i,i.exports,n),i.exports}n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,{a:t}),t},n.d=function(e,t){for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var a={};return function(){n.d(a,{default:function(){return s}});var e=n(771),t=n.n(e),r=function(e,t,r){for(var n=r,a=0,i=e.length;n<t.length;){var o=t[n];if(a<=0&&t.slice(n,n+i)===e)return n;"\\"===o?n++:"{"===o?a++:"}"===o&&a--,n++}return-1},i=/^\\begin{/,o=function(e,t){for(var n,a=[],o=new RegExp("("+t.map((function(e){return e.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")})).join("|")+")");-1!==(n=e.search(o));){n>0&&(a.push({type:"text",data:e.slice(0,n)}),e=e.slice(n));var l=t.findIndex((function(t){return e.startsWith(t.left)}));if(-1===(n=r(t[l].right,e,t[l].left.length)))break;var d=e.slice(0,n+t[l].right.length),s=i.test(d)?d:e.slice(t[l].left.length,n);a.push({type:"math",data:s,rawData:d,display:t[l].display}),e=e.slice(n+t[l].right.length)}return""!==e&&a.push({type:"text",data:e}),a},l=function(e,r){var n=o(e,r.delimiters);if(1===n.length&&"text"===n[0].type)return null;for(var a=document.createDocumentFragment(),i=0;i<n.length;i++)if("text"===n[i].type)a.appendChild(document.createTextNode(n[i].data));else{var l=document.createElement("span"),d=n[i].data;r.displayMode=n[i].display;try{r.preProcess&&(d=r.preProcess(d)),t().render(d,l,r)}catch(e){if(!(e instanceof t().ParseError))throw e;r.errorCallback("KaTeX auto-render: Failed to parse `"+n[i].data+"` with ",e),a.appendChild(document.createTextNode(n[i].rawData));continue}a.appendChild(l)}return a},d=function e(t,r){for(var n=0;n<t.childNodes.length;n++){var a=t.childNodes[n];if(3===a.nodeType){var i=l(a.textContent,r);i&&(n+=i.childNodes.length-1,t.replaceChild(i,a))}else 1===a.nodeType&&function(){var t=" "+a.className+" ";-1===r.ignoredTags.indexOf(a.nodeName.toLowerCase())&&r.ignoredClasses.every((function(e){return-1===t.indexOf(" "+e+" ")}))&&e(a,r)}()}},s=function(e,t){if(!e)throw new Error("No element provided to render");var r={};for(var n in t)t.hasOwnProperty(n)&&(r[n]=t[n]);r.delimiters=r.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],r.ignoredTags=r.ignoredTags||["script","noscript","style","textarea","pre","code","option"],r.ignoredClasses=r.ignoredClasses||[],r.errorCallback=r.errorCallback||console.error,r.macros=r.macros||{},d(e,r)}}(),a=a.default}()})); |
@ -0,0 +1,222 @@ |
|||||
|
import katex from '../katex.mjs'; |
||||
|
|
||||
|
/* eslint no-constant-condition:0 */ |
||||
|
var findEndOfMath = function findEndOfMath(delimiter, text, startIndex) { |
||||
|
// Adapted from |
||||
|
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx |
||||
|
var index = startIndex; |
||||
|
var braceLevel = 0; |
||||
|
var delimLength = delimiter.length; |
||||
|
|
||||
|
while (index < text.length) { |
||||
|
var character = text[index]; |
||||
|
|
||||
|
if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) { |
||||
|
return index; |
||||
|
} else if (character === "\\") { |
||||
|
index++; |
||||
|
} else if (character === "{") { |
||||
|
braceLevel++; |
||||
|
} else if (character === "}") { |
||||
|
braceLevel--; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
return -1; |
||||
|
}; |
||||
|
|
||||
|
var escapeRegex = function escapeRegex(string) { |
||||
|
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); |
||||
|
}; |
||||
|
|
||||
|
var amsRegex = /^\\begin{/; |
||||
|
|
||||
|
var splitAtDelimiters = function splitAtDelimiters(text, delimiters) { |
||||
|
var index; |
||||
|
var data = []; |
||||
|
var regexLeft = new RegExp("(" + delimiters.map(x => escapeRegex(x.left)).join("|") + ")"); |
||||
|
|
||||
|
while (true) { |
||||
|
index = text.search(regexLeft); |
||||
|
|
||||
|
if (index === -1) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (index > 0) { |
||||
|
data.push({ |
||||
|
type: "text", |
||||
|
data: text.slice(0, index) |
||||
|
}); |
||||
|
text = text.slice(index); // now text starts with delimiter |
||||
|
} // ... so this always succeeds: |
||||
|
|
||||
|
|
||||
|
var i = delimiters.findIndex(delim => text.startsWith(delim.left)); |
||||
|
index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length); |
||||
|
|
||||
|
if (index === -1) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
var rawData = text.slice(0, index + delimiters[i].right.length); |
||||
|
var math = amsRegex.test(rawData) ? rawData : text.slice(delimiters[i].left.length, index); |
||||
|
data.push({ |
||||
|
type: "math", |
||||
|
data: math, |
||||
|
rawData, |
||||
|
display: delimiters[i].display |
||||
|
}); |
||||
|
text = text.slice(index + delimiters[i].right.length); |
||||
|
} |
||||
|
|
||||
|
if (text !== "") { |
||||
|
data.push({ |
||||
|
type: "text", |
||||
|
data: text |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return data; |
||||
|
}; |
||||
|
|
||||
|
/* eslint no-console:0 */ |
||||
|
/* Note: optionsCopy is mutated by this method. If it is ever exposed in the |
||||
|
* API, we should copy it before mutating. |
||||
|
*/ |
||||
|
|
||||
|
var renderMathInText = function renderMathInText(text, optionsCopy) { |
||||
|
var data = splitAtDelimiters(text, optionsCopy.delimiters); |
||||
|
|
||||
|
if (data.length === 1 && data[0].type === 'text') { |
||||
|
// There is no formula in the text. |
||||
|
// Let's return null which means there is no need to replace |
||||
|
// the current text node with a new one. |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var fragment = document.createDocumentFragment(); |
||||
|
|
||||
|
for (var i = 0; i < data.length; i++) { |
||||
|
if (data[i].type === "text") { |
||||
|
fragment.appendChild(document.createTextNode(data[i].data)); |
||||
|
} else { |
||||
|
var span = document.createElement("span"); |
||||
|
var math = data[i].data; // Override any display mode defined in the settings with that |
||||
|
// defined by the text itself |
||||
|
|
||||
|
optionsCopy.displayMode = data[i].display; |
||||
|
|
||||
|
try { |
||||
|
if (optionsCopy.preProcess) { |
||||
|
math = optionsCopy.preProcess(math); |
||||
|
} |
||||
|
|
||||
|
katex.render(math, span, optionsCopy); |
||||
|
} catch (e) { |
||||
|
if (!(e instanceof katex.ParseError)) { |
||||
|
throw e; |
||||
|
} |
||||
|
|
||||
|
optionsCopy.errorCallback("KaTeX auto-render: Failed to parse `" + data[i].data + "` with ", e); |
||||
|
fragment.appendChild(document.createTextNode(data[i].rawData)); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
fragment.appendChild(span); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return fragment; |
||||
|
}; |
||||
|
|
||||
|
var renderElem = function renderElem(elem, optionsCopy) { |
||||
|
for (var i = 0; i < elem.childNodes.length; i++) { |
||||
|
var childNode = elem.childNodes[i]; |
||||
|
|
||||
|
if (childNode.nodeType === 3) { |
||||
|
// Text node |
||||
|
var frag = renderMathInText(childNode.textContent, optionsCopy); |
||||
|
|
||||
|
if (frag) { |
||||
|
i += frag.childNodes.length - 1; |
||||
|
elem.replaceChild(frag, childNode); |
||||
|
} |
||||
|
} else if (childNode.nodeType === 1) { |
||||
|
(function () { |
||||
|
// Element node |
||||
|
var className = ' ' + childNode.className + ' '; |
||||
|
var shouldRender = optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 && optionsCopy.ignoredClasses.every(x => className.indexOf(' ' + x + ' ') === -1); |
||||
|
|
||||
|
if (shouldRender) { |
||||
|
renderElem(childNode, optionsCopy); |
||||
|
} |
||||
|
})(); |
||||
|
} // Otherwise, it's something else, and ignore it. |
||||
|
|
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var renderMathInElement = function renderMathInElement(elem, options) { |
||||
|
if (!elem) { |
||||
|
throw new Error("No element provided to render"); |
||||
|
} |
||||
|
|
||||
|
var optionsCopy = {}; // Object.assign(optionsCopy, option) |
||||
|
|
||||
|
for (var option in options) { |
||||
|
if (options.hasOwnProperty(option)) { |
||||
|
optionsCopy[option] = options[option]; |
||||
|
} |
||||
|
} // default options |
||||
|
|
||||
|
|
||||
|
optionsCopy.delimiters = optionsCopy.delimiters || [{ |
||||
|
left: "$$", |
||||
|
right: "$$", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\(", |
||||
|
right: "\\)", |
||||
|
display: false |
||||
|
}, // LaTeX uses $…$, but it ruins the display of normal `$` in text: |
||||
|
// {left: "$", right: "$", display: false}, |
||||
|
// $ must come after $$ |
||||
|
// Render AMS environments even if outside $$…$$ delimiters. |
||||
|
{ |
||||
|
left: "\\begin{equation}", |
||||
|
right: "\\end{equation}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{align}", |
||||
|
right: "\\end{align}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{alignat}", |
||||
|
right: "\\end{alignat}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{gather}", |
||||
|
right: "\\end{gather}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\begin{CD}", |
||||
|
right: "\\end{CD}", |
||||
|
display: true |
||||
|
}, { |
||||
|
left: "\\[", |
||||
|
right: "\\]", |
||||
|
display: true |
||||
|
}]; |
||||
|
optionsCopy.ignoredTags = optionsCopy.ignoredTags || ["script", "noscript", "style", "textarea", "pre", "code", "option"]; |
||||
|
optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || []; |
||||
|
optionsCopy.errorCallback = optionsCopy.errorCallback || console.error; // Enable sharing of global macros defined via `\gdef` between different |
||||
|
// math elements within a single call to `renderMathInElement`. |
||||
|
|
||||
|
optionsCopy.macros = optionsCopy.macros || {}; |
||||
|
renderElem(elem, optionsCopy); |
||||
|
}; |
||||
|
|
||||
|
export { renderMathInElement as default }; |
@ -0,0 +1,13 @@ |
|||||
|
/* Force selection of entire .katex/.katex-display blocks, so that we can |
||||
|
* copy/paste the entire source code. If you omit this CSS, partial |
||||
|
* selections of a formula will work, but will copy the ugly HTML |
||||
|
* representation instead of the LaTeX source code. (Full selections will |
||||
|
* still produce the LaTeX source code.) |
||||
|
*/ |
||||
|
.katex, |
||||
|
.katex-display { |
||||
|
-webkit-user-select: all; |
||||
|
-moz-user-select: all; |
||||
|
user-select: all; |
||||
|
} |
||||
|
|
@ -0,0 +1,116 @@ |
|||||
|
(function webpackUniversalModuleDefinition(root, factory) { |
||||
|
if(typeof exports === 'object' && typeof module === 'object') |
||||
|
module.exports = factory(); |
||||
|
else if(typeof define === 'function' && define.amd) |
||||
|
define([], factory); |
||||
|
else { |
||||
|
var a = factory(); |
||||
|
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; |
||||
|
} |
||||
|
})((typeof self !== 'undefined' ? self : this), function() { |
||||
|
return /******/ (function() { // webpackBootstrap
|
||||
|
/******/ "use strict"; |
||||
|
var __webpack_exports__ = {}; |
||||
|
|
||||
|
;// CONCATENATED MODULE: ./contrib/copy-tex/katex2tex.js
|
||||
|
// Set these to how you want inline and display math to be delimited.
|
||||
|
var defaultCopyDelimiters = { |
||||
|
inline: ['$', '$'], |
||||
|
// alternative: ['\(', '\)']
|
||||
|
display: ['$$', '$$'] // alternative: ['\[', '\]']
|
||||
|
|
||||
|
}; // Replace .katex elements with their TeX source (<annotation> element).
|
||||
|
// Modifies fragment in-place. Useful for writing your own 'copy' handler,
|
||||
|
// as in copy-tex.js.
|
||||
|
|
||||
|
var katexReplaceWithTex = function katexReplaceWithTex(fragment, copyDelimiters) { |
||||
|
if (copyDelimiters === void 0) { |
||||
|
copyDelimiters = defaultCopyDelimiters; |
||||
|
} |
||||
|
|
||||
|
// Remove .katex-html blocks that are preceded by .katex-mathml blocks
|
||||
|
// (which will get replaced below).
|
||||
|
var katexHtml = fragment.querySelectorAll('.katex-mathml + .katex-html'); |
||||
|
|
||||
|
for (var i = 0; i < katexHtml.length; i++) { |
||||
|
var element = katexHtml[i]; |
||||
|
|
||||
|
if (element.remove) { |
||||
|
element.remove(null); |
||||
|
} else { |
||||
|
element.parentNode.removeChild(element); |
||||
|
} |
||||
|
} // Replace .katex-mathml elements with their annotation (TeX source)
|
||||
|
// descendant, with inline delimiters.
|
||||
|
|
||||
|
|
||||
|
var katexMathml = fragment.querySelectorAll('.katex-mathml'); |
||||
|
|
||||
|
for (var _i = 0; _i < katexMathml.length; _i++) { |
||||
|
var _element = katexMathml[_i]; |
||||
|
|
||||
|
var texSource = _element.querySelector('annotation'); |
||||
|
|
||||
|
if (texSource) { |
||||
|
if (_element.replaceWith) { |
||||
|
_element.replaceWith(texSource); |
||||
|
} else { |
||||
|
_element.parentNode.replaceChild(texSource, _element); |
||||
|
} |
||||
|
|
||||
|
texSource.innerHTML = copyDelimiters.inline[0] + texSource.innerHTML + copyDelimiters.inline[1]; |
||||
|
} |
||||
|
} // Switch display math to display delimiters.
|
||||
|
|
||||
|
|
||||
|
var displays = fragment.querySelectorAll('.katex-display annotation'); |
||||
|
|
||||
|
for (var _i2 = 0; _i2 < displays.length; _i2++) { |
||||
|
var _element2 = displays[_i2]; |
||||
|
_element2.innerHTML = copyDelimiters.display[0] + _element2.innerHTML.substr(copyDelimiters.inline[0].length, _element2.innerHTML.length - copyDelimiters.inline[0].length - copyDelimiters.inline[1].length) + copyDelimiters.display[1]; |
||||
|
} |
||||
|
|
||||
|
return fragment; |
||||
|
}; |
||||
|
/* harmony default export */ var katex2tex = (katexReplaceWithTex); |
||||
|
;// CONCATENATED MODULE: ./contrib/copy-tex/copy-tex.js
|
||||
|
// Global copy handler to modify behavior on .katex elements.
|
||||
|
|
||||
|
document.addEventListener('copy', function (event) { |
||||
|
var selection = window.getSelection(); |
||||
|
|
||||
|
if (selection.isCollapsed) { |
||||
|
return; // default action OK if selection is empty
|
||||
|
} |
||||
|
|
||||
|
var fragment = selection.getRangeAt(0).cloneContents(); |
||||
|
|
||||
|
if (!fragment.querySelector('.katex-mathml')) { |
||||
|
return; // default action OK if no .katex-mathml elements
|
||||
|
} // Preserve usual HTML copy/paste behavior.
|
||||
|
|
||||
|
|
||||
|
var html = []; |
||||
|
|
||||
|
for (var i = 0; i < fragment.childNodes.length; i++) { |
||||
|
html.push(fragment.childNodes[i].outerHTML); |
||||
|
} |
||||
|
|
||||
|
event.clipboardData.setData('text/html', html.join('')); // Rewrite plain-text version.
|
||||
|
|
||||
|
event.clipboardData.setData('text/plain', katex2tex(fragment).textContent); // Prevent normal copy handling.
|
||||
|
|
||||
|
event.preventDefault(); |
||||
|
}); |
||||
|
;// CONCATENATED MODULE: ./contrib/copy-tex/copy-tex.webpack.js
|
||||
|
/** |
||||
|
* This is the webpack entry point for KaTeX. As ECMAScript doesn't support |
||||
|
* CSS modules natively, a separate entry point is used. |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
__webpack_exports__ = __webpack_exports__["default"]; |
||||
|
/******/ return __webpack_exports__; |
||||
|
/******/ })() |
||||
|
; |
||||
|
}); |
@ -0,0 +1 @@ |
|||||
|
.katex,.katex-display{-webkit-user-select:all;-moz-user-select:all;user-select:all} |
@ -0,0 +1 @@ |
|||||
|
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var n=t();for(var l in n)("object"==typeof exports?exports:e)[l]=n[l]}}("undefined"!=typeof self?self:this,(function(){return function(){"use strict";var e={},t={inline:["$","$"],display:["$$","$$"]},n=function(e,n){void 0===n&&(n=t);for(var l=e.querySelectorAll(".katex-mathml + .katex-html"),r=0;r<l.length;r++){var i=l[r];i.remove?i.remove(null):i.parentNode.removeChild(i)}for(var o=e.querySelectorAll(".katex-mathml"),a=0;a<o.length;a++){var d=o[a],f=d.querySelector("annotation");f&&(d.replaceWith?d.replaceWith(f):d.parentNode.replaceChild(f,d),f.innerHTML=n.inline[0]+f.innerHTML+n.inline[1])}for(var c=e.querySelectorAll(".katex-display annotation"),s=0;s<c.length;s++){var p=c[s];p.innerHTML=n.display[0]+p.innerHTML.substr(n.inline[0].length,p.innerHTML.length-n.inline[0].length-n.inline[1].length)+n.display[1]}return e};return document.addEventListener("copy",(function(e){var t=window.getSelection();if(!t.isCollapsed){var l=t.getRangeAt(0).cloneContents();if(l.querySelector(".katex-mathml")){for(var r=[],i=0;i<l.childNodes.length;i++)r.push(l.childNodes[i].outerHTML);e.clipboardData.setData("text/html",r.join("")),e.clipboardData.setData("text/plain",n(l).textContent),e.preventDefault()}}})),e=e.default}()})); |
@ -0,0 +1,86 @@ |
|||||
|
// Set these to how you want inline and display math to be delimited. |
||||
|
var defaultCopyDelimiters = { |
||||
|
inline: ['$', '$'], |
||||
|
// alternative: ['\(', '\)'] |
||||
|
display: ['$$', '$$'] // alternative: ['\[', '\]'] |
||||
|
|
||||
|
}; // Replace .katex elements with their TeX source (<annotation> element). |
||||
|
// Modifies fragment in-place. Useful for writing your own 'copy' handler, |
||||
|
// as in copy-tex.js. |
||||
|
|
||||
|
var katexReplaceWithTex = function katexReplaceWithTex(fragment, copyDelimiters) { |
||||
|
if (copyDelimiters === void 0) { |
||||
|
copyDelimiters = defaultCopyDelimiters; |
||||
|
} |
||||
|
|
||||
|
// Remove .katex-html blocks that are preceded by .katex-mathml blocks |
||||
|
// (which will get replaced below). |
||||
|
var katexHtml = fragment.querySelectorAll('.katex-mathml + .katex-html'); |
||||
|
|
||||
|
for (var i = 0; i < katexHtml.length; i++) { |
||||
|
var element = katexHtml[i]; |
||||
|
|
||||
|
if (element.remove) { |
||||
|
element.remove(null); |
||||
|
} else { |
||||
|
element.parentNode.removeChild(element); |
||||
|
} |
||||
|
} // Replace .katex-mathml elements with their annotation (TeX source) |
||||
|
// descendant, with inline delimiters. |
||||
|
|
||||
|
|
||||
|
var katexMathml = fragment.querySelectorAll('.katex-mathml'); |
||||
|
|
||||
|
for (var _i = 0; _i < katexMathml.length; _i++) { |
||||
|
var _element = katexMathml[_i]; |
||||
|
|
||||
|
var texSource = _element.querySelector('annotation'); |
||||
|
|
||||
|
if (texSource) { |
||||
|
if (_element.replaceWith) { |
||||
|
_element.replaceWith(texSource); |
||||
|
} else { |
||||
|
_element.parentNode.replaceChild(texSource, _element); |
||||
|
} |
||||
|
|
||||
|
texSource.innerHTML = copyDelimiters.inline[0] + texSource.innerHTML + copyDelimiters.inline[1]; |
||||
|
} |
||||
|
} // Switch display math to display delimiters. |
||||
|
|
||||
|
|
||||
|
var displays = fragment.querySelectorAll('.katex-display annotation'); |
||||
|
|
||||
|
for (var _i2 = 0; _i2 < displays.length; _i2++) { |
||||
|
var _element2 = displays[_i2]; |
||||
|
_element2.innerHTML = copyDelimiters.display[0] + _element2.innerHTML.substr(copyDelimiters.inline[0].length, _element2.innerHTML.length - copyDelimiters.inline[0].length - copyDelimiters.inline[1].length) + copyDelimiters.display[1]; |
||||
|
} |
||||
|
|
||||
|
return fragment; |
||||
|
}; |
||||
|
|
||||
|
document.addEventListener('copy', function (event) { |
||||
|
var selection = window.getSelection(); |
||||
|
|
||||
|
if (selection.isCollapsed) { |
||||
|
return; // default action OK if selection is empty |
||||
|
} |
||||
|
|
||||
|
var fragment = selection.getRangeAt(0).cloneContents(); |
||||
|
|
||||
|
if (!fragment.querySelector('.katex-mathml')) { |
||||
|
return; // default action OK if no .katex-mathml elements |
||||
|
} // Preserve usual HTML copy/paste behavior. |
||||
|
|
||||
|
|
||||
|
var html = []; |
||||
|
|
||||
|
for (var i = 0; i < fragment.childNodes.length; i++) { |
||||
|
html.push(fragment.childNodes[i].outerHTML); |
||||
|
} |
||||
|
|
||||
|
event.clipboardData.setData('text/html', html.join('')); // Rewrite plain-text version. |
||||
|
|
||||
|
event.clipboardData.setData('text/plain', katexReplaceWithTex(fragment).textContent); // Prevent normal copy handling. |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
}); |
@ -0,0 +1,112 @@ |
|||||
|
(function webpackUniversalModuleDefinition(root, factory) { |
||||
|
if(typeof exports === 'object' && typeof module === 'object') |
||||
|
module.exports = factory(require("katex")); |
||||
|
else if(typeof define === 'function' && define.amd) |
||||
|
define(["katex"], factory); |
||||
|
else { |
||||
|
var a = typeof exports === 'object' ? factory(require("katex")) : factory(root["katex"]); |
||||
|
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; |
||||
|
} |
||||
|
})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__771__) { |
||||
|
return /******/ (function() { // webpackBootstrap
|
||||
|
/******/ "use strict"; |
||||
|
/******/ var __webpack_modules__ = ({ |
||||
|
|
||||
|
/***/ 771: |
||||
|
/***/ (function(module) { |
||||
|
|
||||
|
module.exports = __WEBPACK_EXTERNAL_MODULE__771__; |
||||
|
|
||||
|
/***/ }) |
||||
|
|
||||
|
/******/ }); |
||||
|
/************************************************************************/ |
||||
|
/******/ // The module cache
|
||||
|
/******/ var __webpack_module_cache__ = {}; |
||||
|
/******/ |
||||
|
/******/ // The require function
|
||||
|
/******/ function __webpack_require__(moduleId) { |
||||
|
/******/ // Check if module is in cache
|
||||
|
/******/ var cachedModule = __webpack_module_cache__[moduleId]; |
||||
|
/******/ if (cachedModule !== undefined) { |
||||
|
/******/ return cachedModule.exports; |
||||
|
/******/ } |
||||
|
/******/ // Create a new module (and put it into the cache)
|
||||
|
/******/ var module = __webpack_module_cache__[moduleId] = { |
||||
|
/******/ // no module.id needed
|
||||
|
/******/ // no module.loaded needed
|
||||
|
/******/ exports: {} |
||||
|
/******/ }; |
||||
|
/******/ |
||||
|
/******/ // Execute the module function
|
||||
|
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); |
||||
|
/******/ |
||||
|
/******/ // Return the exports of the module
|
||||
|
/******/ return module.exports; |
||||
|
/******/ } |
||||
|
/******/ |
||||
|
/************************************************************************/ |
||||
|
/******/ /* webpack/runtime/compat get default export */ |
||||
|
/******/ !function() { |
||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
|
/******/ __webpack_require__.n = function(module) { |
||||
|
/******/ var getter = module && module.__esModule ? |
||||
|
/******/ function() { return module['default']; } : |
||||
|
/******/ function() { return module; }; |
||||
|
/******/ __webpack_require__.d(getter, { a: getter }); |
||||
|
/******/ return getter; |
||||
|
/******/ }; |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/******/ /* webpack/runtime/define property getters */ |
||||
|
/******/ !function() { |
||||
|
/******/ // define getter functions for harmony exports
|
||||
|
/******/ __webpack_require__.d = function(exports, definition) { |
||||
|
/******/ for(var key in definition) { |
||||
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { |
||||
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); |
||||
|
/******/ } |
||||
|
/******/ } |
||||
|
/******/ }; |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */ |
||||
|
/******/ !function() { |
||||
|
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/************************************************************************/ |
||||
|
var __webpack_exports__ = {}; |
||||
|
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||
|
!function() { |
||||
|
/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(771); |
||||
|
/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(katex__WEBPACK_IMPORTED_MODULE_0__); |
||||
|
|
||||
|
var scripts = document.body.getElementsByTagName("script"); |
||||
|
scripts = Array.prototype.slice.call(scripts); |
||||
|
scripts.forEach(function (script) { |
||||
|
if (!script.type || !script.type.match(/math\/tex/i)) { |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
var display = script.type.match(/mode\s*=\s*display(;|\s|\n|$)/) != null; |
||||
|
var katexElement = document.createElement(display ? "div" : "span"); |
||||
|
katexElement.setAttribute("class", display ? "equation" : "inline-equation"); |
||||
|
|
||||
|
try { |
||||
|
katex__WEBPACK_IMPORTED_MODULE_0___default().render(script.text, katexElement, { |
||||
|
displayMode: display |
||||
|
}); |
||||
|
} catch (err) { |
||||
|
//console.error(err); linter doesn't like this
|
||||
|
katexElement.textContent = script.text; |
||||
|
} |
||||
|
|
||||
|
script.parentNode.replaceChild(katexElement, script); |
||||
|
}); |
||||
|
}(); |
||||
|
__webpack_exports__ = __webpack_exports__["default"]; |
||||
|
/******/ return __webpack_exports__; |
||||
|
/******/ })() |
||||
|
; |
||||
|
}); |
@ -0,0 +1 @@ |
|||||
|
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("katex"));else if("function"==typeof define&&define.amd)define(["katex"],t);else{var r="object"==typeof exports?t(require("katex")):t(e.katex);for(var n in r)("object"==typeof exports?exports:e)[n]=r[n]}}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={771:function(t){t.exports=e}},r={};function n(e){var o=r[e];if(void 0!==o)return o.exports;var i=r[e]={exports:{}};return t[e](i,i.exports,n),i.exports}n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,{a:t}),t},n.d=function(e,t){for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var o,i,a,u={};return o=n(771),i=n.n(o),a=document.body.getElementsByTagName("script"),(a=Array.prototype.slice.call(a)).forEach((function(e){if(!e.type||!e.type.match(/math\/tex/i))return-1;var t=null!=e.type.match(/mode\s*=\s*display(;|\s|\n|$)/),r=document.createElement(t?"div":"span");r.setAttribute("class",t?"equation":"inline-equation");try{i().render(e.text,r,{displayMode:t})}catch(t){r.textContent=e.text}e.parentNode.replaceChild(r,e)})),u=u.default}()})); |
@ -0,0 +1,24 @@ |
|||||
|
import katex from '../katex.mjs'; |
||||
|
|
||||
|
var scripts = document.body.getElementsByTagName("script"); |
||||
|
scripts = Array.prototype.slice.call(scripts); |
||||
|
scripts.forEach(function (script) { |
||||
|
if (!script.type || !script.type.match(/math\/tex/i)) { |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
var display = script.type.match(/mode\s*=\s*display(;|\s|\n|$)/) != null; |
||||
|
var katexElement = document.createElement(display ? "div" : "span"); |
||||
|
katexElement.setAttribute("class", display ? "equation" : "inline-equation"); |
||||
|
|
||||
|
try { |
||||
|
katex.render(script.text, katexElement, { |
||||
|
displayMode: display |
||||
|
}); |
||||
|
} catch (err) { |
||||
|
//console.error(err); linter doesn't like this |
||||
|
katexElement.textContent = script.text; |
||||
|
} |
||||
|
|
||||
|
script.parentNode.replaceChild(katexElement, script); |
||||
|
}); |
@ -0,0 +1,875 @@ |
|||||
|
(function webpackUniversalModuleDefinition(root, factory) { |
||||
|
if(typeof exports === 'object' && typeof module === 'object') |
||||
|
module.exports = factory(require("katex")); |
||||
|
else if(typeof define === 'function' && define.amd) |
||||
|
define(["katex"], factory); |
||||
|
else { |
||||
|
var a = typeof exports === 'object' ? factory(require("katex")) : factory(root["katex"]); |
||||
|
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; |
||||
|
} |
||||
|
})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__771__) { |
||||
|
return /******/ (function() { // webpackBootstrap
|
||||
|
/******/ "use strict"; |
||||
|
/******/ var __webpack_modules__ = ({ |
||||
|
|
||||
|
/***/ 771: |
||||
|
/***/ (function(module) { |
||||
|
|
||||
|
module.exports = __WEBPACK_EXTERNAL_MODULE__771__; |
||||
|
|
||||
|
/***/ }) |
||||
|
|
||||
|
/******/ }); |
||||
|
/************************************************************************/ |
||||
|
/******/ // The module cache
|
||||
|
/******/ var __webpack_module_cache__ = {}; |
||||
|
/******/ |
||||
|
/******/ // The require function
|
||||
|
/******/ function __webpack_require__(moduleId) { |
||||
|
/******/ // Check if module is in cache
|
||||
|
/******/ var cachedModule = __webpack_module_cache__[moduleId]; |
||||
|
/******/ if (cachedModule !== undefined) { |
||||
|
/******/ return cachedModule.exports; |
||||
|
/******/ } |
||||
|
/******/ // Create a new module (and put it into the cache)
|
||||
|
/******/ var module = __webpack_module_cache__[moduleId] = { |
||||
|
/******/ // no module.id needed
|
||||
|
/******/ // no module.loaded needed
|
||||
|
/******/ exports: {} |
||||
|
/******/ }; |
||||
|
/******/ |
||||
|
/******/ // Execute the module function
|
||||
|
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); |
||||
|
/******/ |
||||
|
/******/ // Return the exports of the module
|
||||
|
/******/ return module.exports; |
||||
|
/******/ } |
||||
|
/******/ |
||||
|
/************************************************************************/ |
||||
|
/******/ /* webpack/runtime/compat get default export */ |
||||
|
/******/ !function() { |
||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
|
/******/ __webpack_require__.n = function(module) { |
||||
|
/******/ var getter = module && module.__esModule ? |
||||
|
/******/ function() { return module['default']; } : |
||||
|
/******/ function() { return module; }; |
||||
|
/******/ __webpack_require__.d(getter, { a: getter }); |
||||
|
/******/ return getter; |
||||
|
/******/ }; |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/******/ /* webpack/runtime/define property getters */ |
||||
|
/******/ !function() { |
||||
|
/******/ // define getter functions for harmony exports
|
||||
|
/******/ __webpack_require__.d = function(exports, definition) { |
||||
|
/******/ for(var key in definition) { |
||||
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { |
||||
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); |
||||
|
/******/ } |
||||
|
/******/ } |
||||
|
/******/ }; |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */ |
||||
|
/******/ !function() { |
||||
|
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } |
||||
|
/******/ }(); |
||||
|
/******/ |
||||
|
/************************************************************************/ |
||||
|
var __webpack_exports__ = {}; |
||||
|
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
||||
|
!function() { |
||||
|
/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(771); |
||||
|
/* harmony import */ var katex__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(katex__WEBPACK_IMPORTED_MODULE_0__); |
||||
|
/** |
||||
|
* renderA11yString returns a readable string. |
||||
|
* |
||||
|
* In some cases the string will have the proper semantic math |
||||
|
* meaning,: |
||||
|
* renderA11yString("\\frac{1}{2}"") |
||||
|
* -> "start fraction, 1, divided by, 2, end fraction" |
||||
|
* |
||||
|
* However, other cases do not: |
||||
|
* renderA11yString("f(x) = x^2") |
||||
|
* -> "f, left parenthesis, x, right parenthesis, equals, x, squared" |
||||
|
* |
||||
|
* The commas in the string aim to increase ease of understanding |
||||
|
* when read by a screenreader. |
||||
|
*/ |
||||
|
// NOTE: since we're importing types here these files won't actually be
|
||||
|
// included in the build.
|
||||
|
// $FlowIgnore: we import the types directly anyways
|
||||
|
|
||||
|
var stringMap = { |
||||
|
"(": "left parenthesis", |
||||
|
")": "right parenthesis", |
||||
|
"[": "open bracket", |
||||
|
"]": "close bracket", |
||||
|
"\\{": "left brace", |
||||
|
"\\}": "right brace", |
||||
|
"\\lvert": "open vertical bar", |
||||
|
"\\rvert": "close vertical bar", |
||||
|
"|": "vertical bar", |
||||
|
"\\uparrow": "up arrow", |
||||
|
"\\Uparrow": "up arrow", |
||||
|
"\\downarrow": "down arrow", |
||||
|
"\\Downarrow": "down arrow", |
||||
|
"\\updownarrow": "up down arrow", |
||||
|
"\\leftarrow": "left arrow", |
||||
|
"\\Leftarrow": "left arrow", |
||||
|
"\\rightarrow": "right arrow", |
||||
|
"\\Rightarrow": "right arrow", |
||||
|
"\\langle": "open angle", |
||||
|
"\\rangle": "close angle", |
||||
|
"\\lfloor": "open floor", |
||||
|
"\\rfloor": "close floor", |
||||
|
"\\int": "integral", |
||||
|
"\\intop": "integral", |
||||
|
"\\lim": "limit", |
||||
|
"\\ln": "natural log", |
||||
|
"\\log": "log", |
||||
|
"\\sin": "sine", |
||||
|
"\\cos": "cosine", |
||||
|
"\\tan": "tangent", |
||||
|
"\\cot": "cotangent", |
||||
|
"\\sum": "sum", |
||||
|
"/": "slash", |
||||
|
",": "comma", |
||||
|
".": "point", |
||||
|
"-": "negative", |
||||
|
"+": "plus", |
||||
|
"~": "tilde", |
||||
|
":": "colon", |
||||
|
"?": "question mark", |
||||
|
"'": "apostrophe", |
||||
|
"\\%": "percent", |
||||
|
" ": "space", |
||||
|
"\\ ": "space", |
||||
|
"\\$": "dollar sign", |
||||
|
"\\angle": "angle", |
||||
|
"\\degree": "degree", |
||||
|
"\\circ": "circle", |
||||
|
"\\vec": "vector", |
||||
|
"\\triangle": "triangle", |
||||
|
"\\pi": "pi", |
||||
|
"\\prime": "prime", |
||||
|
"\\infty": "infinity", |
||||
|
"\\alpha": "alpha", |
||||
|
"\\beta": "beta", |
||||
|
"\\gamma": "gamma", |
||||
|
"\\omega": "omega", |
||||
|
"\\theta": "theta", |
||||
|
"\\sigma": "sigma", |
||||
|
"\\lambda": "lambda", |
||||
|
"\\tau": "tau", |
||||
|
"\\Delta": "delta", |
||||
|
"\\delta": "delta", |
||||
|
"\\mu": "mu", |
||||
|
"\\rho": "rho", |
||||
|
"\\nabla": "del", |
||||
|
"\\ell": "ell", |
||||
|
"\\ldots": "dots", |
||||
|
// TODO: add entries for all accents
|
||||
|
"\\hat": "hat", |
||||
|
"\\acute": "acute" |
||||
|
}; |
||||
|
var powerMap = { |
||||
|
"prime": "prime", |
||||
|
"degree": "degrees", |
||||
|
"circle": "degrees", |
||||
|
"2": "squared", |
||||
|
"3": "cubed" |
||||
|
}; |
||||
|
var openMap = { |
||||
|
"|": "open vertical bar", |
||||
|
".": "" |
||||
|
}; |
||||
|
var closeMap = { |
||||
|
"|": "close vertical bar", |
||||
|
".": "" |
||||
|
}; |
||||
|
var binMap = { |
||||
|
"+": "plus", |
||||
|
"-": "minus", |
||||
|
"\\pm": "plus minus", |
||||
|
"\\cdot": "dot", |
||||
|
"*": "times", |
||||
|
"/": "divided by", |
||||
|
"\\times": "times", |
||||
|
"\\div": "divided by", |
||||
|
"\\circ": "circle", |
||||
|
"\\bullet": "bullet" |
||||
|
}; |
||||
|
var relMap = { |
||||
|
"=": "equals", |
||||
|
"\\approx": "approximately equals", |
||||
|
"≠": "does not equal", |
||||
|
"\\geq": "is greater than or equal to", |
||||
|
"\\ge": "is greater than or equal to", |
||||
|
"\\leq": "is less than or equal to", |
||||
|
"\\le": "is less than or equal to", |
||||
|
">": "is greater than", |
||||
|
"<": "is less than", |
||||
|
"\\leftarrow": "left arrow", |
||||
|
"\\Leftarrow": "left arrow", |
||||
|
"\\rightarrow": "right arrow", |
||||
|
"\\Rightarrow": "right arrow", |
||||
|
":": "colon" |
||||
|
}; |
||||
|
var accentUnderMap = { |
||||
|
"\\underleftarrow": "left arrow", |
||||
|
"\\underrightarrow": "right arrow", |
||||
|
"\\underleftrightarrow": "left-right arrow", |
||||
|
"\\undergroup": "group", |
||||
|
"\\underlinesegment": "line segment", |
||||
|
"\\utilde": "tilde" |
||||
|
}; |
||||
|
|
||||
|
var buildString = function buildString(str, type, a11yStrings) { |
||||
|
if (!str) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var ret; |
||||
|
|
||||
|
if (type === "open") { |
||||
|
ret = str in openMap ? openMap[str] : stringMap[str] || str; |
||||
|
} else if (type === "close") { |
||||
|
ret = str in closeMap ? closeMap[str] : stringMap[str] || str; |
||||
|
} else if (type === "bin") { |
||||
|
ret = binMap[str] || str; |
||||
|
} else if (type === "rel") { |
||||
|
ret = relMap[str] || str; |
||||
|
} else { |
||||
|
ret = stringMap[str] || str; |
||||
|
} // If the text to add is a number and there is already a string
|
||||
|
// in the list and the last string is a number then we should
|
||||
|
// combine them into a single number
|
||||
|
|
||||
|
|
||||
|
if (/^\d+$/.test(ret) && a11yStrings.length > 0 && // TODO(kevinb): check that the last item in a11yStrings is a string
|
||||
|
// I think we might be able to drop the nested arrays, which would make
|
||||
|
// this easier to type
|
||||
|
// $FlowFixMe
|
||||
|
/^\d+$/.test(a11yStrings[a11yStrings.length - 1])) { |
||||
|
a11yStrings[a11yStrings.length - 1] += ret; |
||||
|
} else if (ret) { |
||||
|
a11yStrings.push(ret); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var buildRegion = function buildRegion(a11yStrings, callback) { |
||||
|
var regionStrings = []; |
||||
|
a11yStrings.push(regionStrings); |
||||
|
callback(regionStrings); |
||||
|
}; |
||||
|
|
||||
|
var handleObject = function handleObject(tree, a11yStrings, atomType) { |
||||
|
// Everything else is assumed to be an object...
|
||||
|
switch (tree.type) { |
||||
|
case "accent": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (a11yStrings) { |
||||
|
buildA11yStrings(tree.base, a11yStrings, atomType); |
||||
|
a11yStrings.push("with"); |
||||
|
buildString(tree.label, "normal", a11yStrings); |
||||
|
a11yStrings.push("on top"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "accentUnder": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (a11yStrings) { |
||||
|
buildA11yStrings(tree.base, a11yStrings, atomType); |
||||
|
a11yStrings.push("with"); |
||||
|
buildString(accentUnderMap[tree.label], "normal", a11yStrings); |
||||
|
a11yStrings.push("underneath"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "accent-token": |
||||
|
{ |
||||
|
// Used internally by accent symbols.
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "atom": |
||||
|
{ |
||||
|
var text = tree.text; |
||||
|
|
||||
|
switch (tree.family) { |
||||
|
case "bin": |
||||
|
{ |
||||
|
buildString(text, "bin", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "close": |
||||
|
{ |
||||
|
buildString(text, "close", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
// TODO(kevinb): figure out what should be done for inner
|
||||
|
|
||||
|
case "inner": |
||||
|
{ |
||||
|
buildString(tree.text, "inner", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "open": |
||||
|
{ |
||||
|
buildString(text, "open", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "punct": |
||||
|
{ |
||||
|
buildString(text, "punct", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "rel": |
||||
|
{ |
||||
|
buildString(text, "rel", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
{ |
||||
|
tree.family; |
||||
|
throw new Error("\"" + tree.family + "\" is not a valid atom type"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "color": |
||||
|
{ |
||||
|
var color = tree.color.replace(/katex-/, ""); |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start color " + color); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end color " + color); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "color-token": |
||||
|
{ |
||||
|
// Used by \color, \colorbox, and \fcolorbox but not directly rendered.
|
||||
|
// It's a leaf node and has no children so just break.
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "delimsizing": |
||||
|
{ |
||||
|
if (tree.delim && tree.delim !== ".") { |
||||
|
buildString(tree.delim, "normal", a11yStrings); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "genfrac": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
// genfrac can have unbalanced delimiters
|
||||
|
var leftDelim = tree.leftDelim, |
||||
|
rightDelim = tree.rightDelim; // NOTE: Not sure if this is a safe assumption
|
||||
|
// hasBarLine true -> fraction, false -> binomial
|
||||
|
|
||||
|
if (tree.hasBarLine) { |
||||
|
regionStrings.push("start fraction"); |
||||
|
leftDelim && buildString(leftDelim, "open", regionStrings); |
||||
|
buildA11yStrings(tree.numer, regionStrings, atomType); |
||||
|
regionStrings.push("divided by"); |
||||
|
buildA11yStrings(tree.denom, regionStrings, atomType); |
||||
|
rightDelim && buildString(rightDelim, "close", regionStrings); |
||||
|
regionStrings.push("end fraction"); |
||||
|
} else { |
||||
|
regionStrings.push("start binomial"); |
||||
|
leftDelim && buildString(leftDelim, "open", regionStrings); |
||||
|
buildA11yStrings(tree.numer, regionStrings, atomType); |
||||
|
regionStrings.push("over"); |
||||
|
buildA11yStrings(tree.denom, regionStrings, atomType); |
||||
|
rightDelim && buildString(rightDelim, "close", regionStrings); |
||||
|
regionStrings.push("end binomial"); |
||||
|
} |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "hbox": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "kern": |
||||
|
{ |
||||
|
// No op: we don't attempt to present kerning information
|
||||
|
// to the screen reader.
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "leftright": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
buildString(tree.left, "open", regionStrings); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
buildString(tree.right, "close", regionStrings); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "leftright-right": |
||||
|
{ |
||||
|
// TODO: double check that this is a no-op
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "lap": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "mathord": |
||||
|
{ |
||||
|
buildString(tree.text, "normal", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "op": |
||||
|
{ |
||||
|
var body = tree.body, |
||||
|
name = tree.name; |
||||
|
|
||||
|
if (body) { |
||||
|
buildA11yStrings(body, a11yStrings, atomType); |
||||
|
} else if (name) { |
||||
|
buildString(name, "normal", a11yStrings); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "op-token": |
||||
|
{ |
||||
|
// Used internally by operator symbols.
|
||||
|
buildString(tree.text, atomType, a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "ordgroup": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "overline": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (a11yStrings) { |
||||
|
a11yStrings.push("start overline"); |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
a11yStrings.push("end overline"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "phantom": |
||||
|
{ |
||||
|
a11yStrings.push("empty space"); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "raisebox": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "rule": |
||||
|
{ |
||||
|
a11yStrings.push("rectangle"); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "sizing": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "spacing": |
||||
|
{ |
||||
|
a11yStrings.push("space"); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "styling": |
||||
|
{ |
||||
|
// We ignore the styling and just pass through the contents
|
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "sqrt": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
var body = tree.body, |
||||
|
index = tree.index; |
||||
|
|
||||
|
if (index) { |
||||
|
var indexString = flatten(buildA11yStrings(index, [], atomType)).join(","); |
||||
|
|
||||
|
if (indexString === "3") { |
||||
|
regionStrings.push("cube root of"); |
||||
|
buildA11yStrings(body, regionStrings, atomType); |
||||
|
regionStrings.push("end cube root"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
regionStrings.push("root"); |
||||
|
regionStrings.push("start index"); |
||||
|
buildA11yStrings(index, regionStrings, atomType); |
||||
|
regionStrings.push("end index"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
regionStrings.push("square root of"); |
||||
|
buildA11yStrings(body, regionStrings, atomType); |
||||
|
regionStrings.push("end square root"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "supsub": |
||||
|
{ |
||||
|
var base = tree.base, |
||||
|
sub = tree.sub, |
||||
|
sup = tree.sup; |
||||
|
var isLog = false; |
||||
|
|
||||
|
if (base) { |
||||
|
buildA11yStrings(base, a11yStrings, atomType); |
||||
|
isLog = base.type === "op" && base.name === "\\log"; |
||||
|
} |
||||
|
|
||||
|
if (sub) { |
||||
|
var regionName = isLog ? "base" : "subscript"; |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start " + regionName); |
||||
|
buildA11yStrings(sub, regionStrings, atomType); |
||||
|
regionStrings.push("end " + regionName); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
if (sup) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
var supString = flatten(buildA11yStrings(sup, [], atomType)).join(","); |
||||
|
|
||||
|
if (supString in powerMap) { |
||||
|
regionStrings.push(powerMap[supString]); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
regionStrings.push("start superscript"); |
||||
|
buildA11yStrings(sup, regionStrings, atomType); |
||||
|
regionStrings.push("end superscript"); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "text": |
||||
|
{ |
||||
|
// TODO: handle other fonts
|
||||
|
if (tree.font === "\\textbf") { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start bold text"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end bold text"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start text"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end text"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "textord": |
||||
|
{ |
||||
|
buildString(tree.text, atomType, a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "smash": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "enclose": |
||||
|
{ |
||||
|
// TODO: create a map for these.
|
||||
|
// TODO: differentiate between a body with a single atom, e.g.
|
||||
|
// "cancel a" instead of "start cancel, a, end cancel"
|
||||
|
if (/cancel/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start cancel"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end cancel"); |
||||
|
}); |
||||
|
break; |
||||
|
} else if (/box/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start box"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end box"); |
||||
|
}); |
||||
|
break; |
||||
|
} else if (/sout/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start strikeout"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end strikeout"); |
||||
|
}); |
||||
|
break; |
||||
|
} else if (/phase/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start phase angle"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end phase angle"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
throw new Error("KaTeX-a11y: enclose node with " + tree.label + " not supported yet"); |
||||
|
} |
||||
|
|
||||
|
case "vcenter": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "vphantom": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: vphantom not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "hphantom": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: hphantom not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "operatorname": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "array": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: array not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "raw": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: raw not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "size": |
||||
|
{ |
||||
|
// Although there are nodes of type "size" in the parse tree, they have
|
||||
|
// no semantic meaning and should be ignored.
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "url": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: url not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "tag": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: tag not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "verb": |
||||
|
{ |
||||
|
buildString("start verbatim", "normal", a11yStrings); |
||||
|
buildString(tree.body, "normal", a11yStrings); |
||||
|
buildString("end verbatim", "normal", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "environment": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: environment not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "horizBrace": |
||||
|
{ |
||||
|
buildString("start " + tree.label.slice(1), "normal", a11yStrings); |
||||
|
buildA11yStrings(tree.base, a11yStrings, atomType); |
||||
|
buildString("end " + tree.label.slice(1), "normal", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "infix": |
||||
|
{ |
||||
|
// All infix nodes are replace with other nodes.
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "includegraphics": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: includegraphics not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "font": |
||||
|
{ |
||||
|
// TODO: callout the start/end of specific fonts
|
||||
|
// TODO: map \BBb{N} to "the naturals" or something like that
|
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "href": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: href not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "cr": |
||||
|
{ |
||||
|
// This is used by environments.
|
||||
|
throw new Error("KaTeX-a11y: cr not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "underline": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (a11yStrings) { |
||||
|
a11yStrings.push("start underline"); |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
a11yStrings.push("end underline"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "xArrow": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: xArrow not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "cdlabel": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: cdlabel not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "cdlabelparent": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: cdlabelparent not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "mclass": |
||||
|
{ |
||||
|
// \neq and \ne are macros so we let "htmlmathml" render the mathmal
|
||||
|
// side of things and extract the text from that.
|
||||
|
var _atomType = tree.mclass.slice(1); // $FlowFixMe: drop the leading "m" from the values in mclass
|
||||
|
|
||||
|
|
||||
|
buildA11yStrings(tree.body, a11yStrings, _atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "mathchoice": |
||||
|
{ |
||||
|
// TODO: track which which style we're using, e.g. dispaly, text, etc.
|
||||
|
// default to text style if even that may not be the correct style
|
||||
|
buildA11yStrings(tree.text, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "htmlmathml": |
||||
|
{ |
||||
|
buildA11yStrings(tree.mathml, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "middle": |
||||
|
{ |
||||
|
buildString(tree.delim, atomType, a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "internal": |
||||
|
{ |
||||
|
// internal nodes are never included in the parse tree
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "html": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
tree.type; |
||||
|
throw new Error("KaTeX a11y un-recognized type: " + tree.type); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var buildA11yStrings = function buildA11yStrings(tree, a11yStrings, atomType) { |
||||
|
if (a11yStrings === void 0) { |
||||
|
a11yStrings = []; |
||||
|
} |
||||
|
|
||||
|
if (tree instanceof Array) { |
||||
|
for (var i = 0; i < tree.length; i++) { |
||||
|
buildA11yStrings(tree[i], a11yStrings, atomType); |
||||
|
} |
||||
|
} else { |
||||
|
handleObject(tree, a11yStrings, atomType); |
||||
|
} |
||||
|
|
||||
|
return a11yStrings; |
||||
|
}; |
||||
|
|
||||
|
var flatten = function flatten(array) { |
||||
|
var result = []; |
||||
|
array.forEach(function (item) { |
||||
|
if (item instanceof Array) { |
||||
|
result = result.concat(flatten(item)); |
||||
|
} else { |
||||
|
result.push(item); |
||||
|
} |
||||
|
}); |
||||
|
return result; |
||||
|
}; |
||||
|
|
||||
|
var renderA11yString = function renderA11yString(text, settings) { |
||||
|
var tree = katex__WEBPACK_IMPORTED_MODULE_0___default().__parse(text, settings); |
||||
|
|
||||
|
var a11yStrings = buildA11yStrings(tree, [], "normal"); |
||||
|
return flatten(a11yStrings).join(", "); |
||||
|
}; |
||||
|
|
||||
|
/* harmony default export */ __webpack_exports__["default"] = (renderA11yString); |
||||
|
}(); |
||||
|
__webpack_exports__ = __webpack_exports__["default"]; |
||||
|
/******/ return __webpack_exports__; |
||||
|
/******/ })() |
||||
|
; |
||||
|
}); |
@ -0,0 +1,794 @@ |
|||||
|
import katex from '../katex.mjs'; |
||||
|
|
||||
|
/** |
||||
|
* renderA11yString returns a readable string. |
||||
|
* |
||||
|
* In some cases the string will have the proper semantic math |
||||
|
* meaning,: |
||||
|
* renderA11yString("\\frac{1}{2}"") |
||||
|
* -> "start fraction, 1, divided by, 2, end fraction" |
||||
|
* |
||||
|
* However, other cases do not: |
||||
|
* renderA11yString("f(x) = x^2") |
||||
|
* -> "f, left parenthesis, x, right parenthesis, equals, x, squared" |
||||
|
* |
||||
|
* The commas in the string aim to increase ease of understanding |
||||
|
* when read by a screenreader. |
||||
|
*/ |
||||
|
var stringMap = { |
||||
|
"(": "left parenthesis", |
||||
|
")": "right parenthesis", |
||||
|
"[": "open bracket", |
||||
|
"]": "close bracket", |
||||
|
"\\{": "left brace", |
||||
|
"\\}": "right brace", |
||||
|
"\\lvert": "open vertical bar", |
||||
|
"\\rvert": "close vertical bar", |
||||
|
"|": "vertical bar", |
||||
|
"\\uparrow": "up arrow", |
||||
|
"\\Uparrow": "up arrow", |
||||
|
"\\downarrow": "down arrow", |
||||
|
"\\Downarrow": "down arrow", |
||||
|
"\\updownarrow": "up down arrow", |
||||
|
"\\leftarrow": "left arrow", |
||||
|
"\\Leftarrow": "left arrow", |
||||
|
"\\rightarrow": "right arrow", |
||||
|
"\\Rightarrow": "right arrow", |
||||
|
"\\langle": "open angle", |
||||
|
"\\rangle": "close angle", |
||||
|
"\\lfloor": "open floor", |
||||
|
"\\rfloor": "close floor", |
||||
|
"\\int": "integral", |
||||
|
"\\intop": "integral", |
||||
|
"\\lim": "limit", |
||||
|
"\\ln": "natural log", |
||||
|
"\\log": "log", |
||||
|
"\\sin": "sine", |
||||
|
"\\cos": "cosine", |
||||
|
"\\tan": "tangent", |
||||
|
"\\cot": "cotangent", |
||||
|
"\\sum": "sum", |
||||
|
"/": "slash", |
||||
|
",": "comma", |
||||
|
".": "point", |
||||
|
"-": "negative", |
||||
|
"+": "plus", |
||||
|
"~": "tilde", |
||||
|
":": "colon", |
||||
|
"?": "question mark", |
||||
|
"'": "apostrophe", |
||||
|
"\\%": "percent", |
||||
|
" ": "space", |
||||
|
"\\ ": "space", |
||||
|
"\\$": "dollar sign", |
||||
|
"\\angle": "angle", |
||||
|
"\\degree": "degree", |
||||
|
"\\circ": "circle", |
||||
|
"\\vec": "vector", |
||||
|
"\\triangle": "triangle", |
||||
|
"\\pi": "pi", |
||||
|
"\\prime": "prime", |
||||
|
"\\infty": "infinity", |
||||
|
"\\alpha": "alpha", |
||||
|
"\\beta": "beta", |
||||
|
"\\gamma": "gamma", |
||||
|
"\\omega": "omega", |
||||
|
"\\theta": "theta", |
||||
|
"\\sigma": "sigma", |
||||
|
"\\lambda": "lambda", |
||||
|
"\\tau": "tau", |
||||
|
"\\Delta": "delta", |
||||
|
"\\delta": "delta", |
||||
|
"\\mu": "mu", |
||||
|
"\\rho": "rho", |
||||
|
"\\nabla": "del", |
||||
|
"\\ell": "ell", |
||||
|
"\\ldots": "dots", |
||||
|
// TODO: add entries for all accents |
||||
|
"\\hat": "hat", |
||||
|
"\\acute": "acute" |
||||
|
}; |
||||
|
var powerMap = { |
||||
|
"prime": "prime", |
||||
|
"degree": "degrees", |
||||
|
"circle": "degrees", |
||||
|
"2": "squared", |
||||
|
"3": "cubed" |
||||
|
}; |
||||
|
var openMap = { |
||||
|
"|": "open vertical bar", |
||||
|
".": "" |
||||
|
}; |
||||
|
var closeMap = { |
||||
|
"|": "close vertical bar", |
||||
|
".": "" |
||||
|
}; |
||||
|
var binMap = { |
||||
|
"+": "plus", |
||||
|
"-": "minus", |
||||
|
"\\pm": "plus minus", |
||||
|
"\\cdot": "dot", |
||||
|
"*": "times", |
||||
|
"/": "divided by", |
||||
|
"\\times": "times", |
||||
|
"\\div": "divided by", |
||||
|
"\\circ": "circle", |
||||
|
"\\bullet": "bullet" |
||||
|
}; |
||||
|
var relMap = { |
||||
|
"=": "equals", |
||||
|
"\\approx": "approximately equals", |
||||
|
"≠": "does not equal", |
||||
|
"\\geq": "is greater than or equal to", |
||||
|
"\\ge": "is greater than or equal to", |
||||
|
"\\leq": "is less than or equal to", |
||||
|
"\\le": "is less than or equal to", |
||||
|
">": "is greater than", |
||||
|
"<": "is less than", |
||||
|
"\\leftarrow": "left arrow", |
||||
|
"\\Leftarrow": "left arrow", |
||||
|
"\\rightarrow": "right arrow", |
||||
|
"\\Rightarrow": "right arrow", |
||||
|
":": "colon" |
||||
|
}; |
||||
|
var accentUnderMap = { |
||||
|
"\\underleftarrow": "left arrow", |
||||
|
"\\underrightarrow": "right arrow", |
||||
|
"\\underleftrightarrow": "left-right arrow", |
||||
|
"\\undergroup": "group", |
||||
|
"\\underlinesegment": "line segment", |
||||
|
"\\utilde": "tilde" |
||||
|
}; |
||||
|
|
||||
|
var buildString = (str, type, a11yStrings) => { |
||||
|
if (!str) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var ret; |
||||
|
|
||||
|
if (type === "open") { |
||||
|
ret = str in openMap ? openMap[str] : stringMap[str] || str; |
||||
|
} else if (type === "close") { |
||||
|
ret = str in closeMap ? closeMap[str] : stringMap[str] || str; |
||||
|
} else if (type === "bin") { |
||||
|
ret = binMap[str] || str; |
||||
|
} else if (type === "rel") { |
||||
|
ret = relMap[str] || str; |
||||
|
} else { |
||||
|
ret = stringMap[str] || str; |
||||
|
} // If the text to add is a number and there is already a string |
||||
|
// in the list and the last string is a number then we should |
||||
|
// combine them into a single number |
||||
|
|
||||
|
|
||||
|
if (/^\d+$/.test(ret) && a11yStrings.length > 0 && // TODO(kevinb): check that the last item in a11yStrings is a string |
||||
|
// I think we might be able to drop the nested arrays, which would make |
||||
|
// this easier to type |
||||
|
// $FlowFixMe |
||||
|
/^\d+$/.test(a11yStrings[a11yStrings.length - 1])) { |
||||
|
a11yStrings[a11yStrings.length - 1] += ret; |
||||
|
} else if (ret) { |
||||
|
a11yStrings.push(ret); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var buildRegion = (a11yStrings, callback) => { |
||||
|
var regionStrings = []; |
||||
|
a11yStrings.push(regionStrings); |
||||
|
callback(regionStrings); |
||||
|
}; |
||||
|
|
||||
|
var handleObject = (tree, a11yStrings, atomType) => { |
||||
|
// Everything else is assumed to be an object... |
||||
|
switch (tree.type) { |
||||
|
case "accent": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, a11yStrings => { |
||||
|
buildA11yStrings(tree.base, a11yStrings, atomType); |
||||
|
a11yStrings.push("with"); |
||||
|
buildString(tree.label, "normal", a11yStrings); |
||||
|
a11yStrings.push("on top"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "accentUnder": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, a11yStrings => { |
||||
|
buildA11yStrings(tree.base, a11yStrings, atomType); |
||||
|
a11yStrings.push("with"); |
||||
|
buildString(accentUnderMap[tree.label], "normal", a11yStrings); |
||||
|
a11yStrings.push("underneath"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "accent-token": |
||||
|
{ |
||||
|
// Used internally by accent symbols. |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "atom": |
||||
|
{ |
||||
|
var { |
||||
|
text |
||||
|
} = tree; |
||||
|
|
||||
|
switch (tree.family) { |
||||
|
case "bin": |
||||
|
{ |
||||
|
buildString(text, "bin", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "close": |
||||
|
{ |
||||
|
buildString(text, "close", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
// TODO(kevinb): figure out what should be done for inner |
||||
|
|
||||
|
case "inner": |
||||
|
{ |
||||
|
buildString(tree.text, "inner", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "open": |
||||
|
{ |
||||
|
buildString(text, "open", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "punct": |
||||
|
{ |
||||
|
buildString(text, "punct", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "rel": |
||||
|
{ |
||||
|
buildString(text, "rel", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
{ |
||||
|
tree.family; |
||||
|
throw new Error("\"" + tree.family + "\" is not a valid atom type"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "color": |
||||
|
{ |
||||
|
var color = tree.color.replace(/katex-/, ""); |
||||
|
buildRegion(a11yStrings, regionStrings => { |
||||
|
regionStrings.push("start color " + color); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end color " + color); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "color-token": |
||||
|
{ |
||||
|
// Used by \color, \colorbox, and \fcolorbox but not directly rendered. |
||||
|
// It's a leaf node and has no children so just break. |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "delimsizing": |
||||
|
{ |
||||
|
if (tree.delim && tree.delim !== ".") { |
||||
|
buildString(tree.delim, "normal", a11yStrings); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "genfrac": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, regionStrings => { |
||||
|
// genfrac can have unbalanced delimiters |
||||
|
var { |
||||
|
leftDelim, |
||||
|
rightDelim |
||||
|
} = tree; // NOTE: Not sure if this is a safe assumption |
||||
|
// hasBarLine true -> fraction, false -> binomial |
||||
|
|
||||
|
if (tree.hasBarLine) { |
||||
|
regionStrings.push("start fraction"); |
||||
|
leftDelim && buildString(leftDelim, "open", regionStrings); |
||||
|
buildA11yStrings(tree.numer, regionStrings, atomType); |
||||
|
regionStrings.push("divided by"); |
||||
|
buildA11yStrings(tree.denom, regionStrings, atomType); |
||||
|
rightDelim && buildString(rightDelim, "close", regionStrings); |
||||
|
regionStrings.push("end fraction"); |
||||
|
} else { |
||||
|
regionStrings.push("start binomial"); |
||||
|
leftDelim && buildString(leftDelim, "open", regionStrings); |
||||
|
buildA11yStrings(tree.numer, regionStrings, atomType); |
||||
|
regionStrings.push("over"); |
||||
|
buildA11yStrings(tree.denom, regionStrings, atomType); |
||||
|
rightDelim && buildString(rightDelim, "close", regionStrings); |
||||
|
regionStrings.push("end binomial"); |
||||
|
} |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "hbox": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "kern": |
||||
|
{ |
||||
|
// No op: we don't attempt to present kerning information |
||||
|
// to the screen reader. |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "leftright": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, regionStrings => { |
||||
|
buildString(tree.left, "open", regionStrings); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
buildString(tree.right, "close", regionStrings); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "leftright-right": |
||||
|
{ |
||||
|
// TODO: double check that this is a no-op |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "lap": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "mathord": |
||||
|
{ |
||||
|
buildString(tree.text, "normal", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "op": |
||||
|
{ |
||||
|
var { |
||||
|
body, |
||||
|
name |
||||
|
} = tree; |
||||
|
|
||||
|
if (body) { |
||||
|
buildA11yStrings(body, a11yStrings, atomType); |
||||
|
} else if (name) { |
||||
|
buildString(name, "normal", a11yStrings); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "op-token": |
||||
|
{ |
||||
|
// Used internally by operator symbols. |
||||
|
buildString(tree.text, atomType, a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "ordgroup": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "overline": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (a11yStrings) { |
||||
|
a11yStrings.push("start overline"); |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
a11yStrings.push("end overline"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "phantom": |
||||
|
{ |
||||
|
a11yStrings.push("empty space"); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "raisebox": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "rule": |
||||
|
{ |
||||
|
a11yStrings.push("rectangle"); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "sizing": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "spacing": |
||||
|
{ |
||||
|
a11yStrings.push("space"); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "styling": |
||||
|
{ |
||||
|
// We ignore the styling and just pass through the contents |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "sqrt": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, regionStrings => { |
||||
|
var { |
||||
|
body, |
||||
|
index |
||||
|
} = tree; |
||||
|
|
||||
|
if (index) { |
||||
|
var indexString = flatten(buildA11yStrings(index, [], atomType)).join(","); |
||||
|
|
||||
|
if (indexString === "3") { |
||||
|
regionStrings.push("cube root of"); |
||||
|
buildA11yStrings(body, regionStrings, atomType); |
||||
|
regionStrings.push("end cube root"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
regionStrings.push("root"); |
||||
|
regionStrings.push("start index"); |
||||
|
buildA11yStrings(index, regionStrings, atomType); |
||||
|
regionStrings.push("end index"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
regionStrings.push("square root of"); |
||||
|
buildA11yStrings(body, regionStrings, atomType); |
||||
|
regionStrings.push("end square root"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "supsub": |
||||
|
{ |
||||
|
var { |
||||
|
base, |
||||
|
sub, |
||||
|
sup |
||||
|
} = tree; |
||||
|
var isLog = false; |
||||
|
|
||||
|
if (base) { |
||||
|
buildA11yStrings(base, a11yStrings, atomType); |
||||
|
isLog = base.type === "op" && base.name === "\\log"; |
||||
|
} |
||||
|
|
||||
|
if (sub) { |
||||
|
var regionName = isLog ? "base" : "subscript"; |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start " + regionName); |
||||
|
buildA11yStrings(sub, regionStrings, atomType); |
||||
|
regionStrings.push("end " + regionName); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
if (sup) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
var supString = flatten(buildA11yStrings(sup, [], atomType)).join(","); |
||||
|
|
||||
|
if (supString in powerMap) { |
||||
|
regionStrings.push(powerMap[supString]); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
regionStrings.push("start superscript"); |
||||
|
buildA11yStrings(sup, regionStrings, atomType); |
||||
|
regionStrings.push("end superscript"); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "text": |
||||
|
{ |
||||
|
// TODO: handle other fonts |
||||
|
if (tree.font === "\\textbf") { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start bold text"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end bold text"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start text"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end text"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "textord": |
||||
|
{ |
||||
|
buildString(tree.text, atomType, a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "smash": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "enclose": |
||||
|
{ |
||||
|
// TODO: create a map for these. |
||||
|
// TODO: differentiate between a body with a single atom, e.g. |
||||
|
// "cancel a" instead of "start cancel, a, end cancel" |
||||
|
if (/cancel/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start cancel"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end cancel"); |
||||
|
}); |
||||
|
break; |
||||
|
} else if (/box/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start box"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end box"); |
||||
|
}); |
||||
|
break; |
||||
|
} else if (/sout/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start strikeout"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end strikeout"); |
||||
|
}); |
||||
|
break; |
||||
|
} else if (/phase/.test(tree.label)) { |
||||
|
buildRegion(a11yStrings, function (regionStrings) { |
||||
|
regionStrings.push("start phase angle"); |
||||
|
buildA11yStrings(tree.body, regionStrings, atomType); |
||||
|
regionStrings.push("end phase angle"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
throw new Error("KaTeX-a11y: enclose node with " + tree.label + " not supported yet"); |
||||
|
} |
||||
|
|
||||
|
case "vcenter": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "vphantom": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: vphantom not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "hphantom": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: hphantom not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "operatorname": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "array": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: array not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "raw": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: raw not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "size": |
||||
|
{ |
||||
|
// Although there are nodes of type "size" in the parse tree, they have |
||||
|
// no semantic meaning and should be ignored. |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "url": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: url not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "tag": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: tag not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "verb": |
||||
|
{ |
||||
|
buildString("start verbatim", "normal", a11yStrings); |
||||
|
buildString(tree.body, "normal", a11yStrings); |
||||
|
buildString("end verbatim", "normal", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "environment": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: environment not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "horizBrace": |
||||
|
{ |
||||
|
buildString("start " + tree.label.slice(1), "normal", a11yStrings); |
||||
|
buildA11yStrings(tree.base, a11yStrings, atomType); |
||||
|
buildString("end " + tree.label.slice(1), "normal", a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "infix": |
||||
|
{ |
||||
|
// All infix nodes are replace with other nodes. |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "includegraphics": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: includegraphics not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "font": |
||||
|
{ |
||||
|
// TODO: callout the start/end of specific fonts |
||||
|
// TODO: map \BBb{N} to "the naturals" or something like that |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "href": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: href not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "cr": |
||||
|
{ |
||||
|
// This is used by environments. |
||||
|
throw new Error("KaTeX-a11y: cr not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "underline": |
||||
|
{ |
||||
|
buildRegion(a11yStrings, function (a11yStrings) { |
||||
|
a11yStrings.push("start underline"); |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
a11yStrings.push("end underline"); |
||||
|
}); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "xArrow": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: xArrow not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "cdlabel": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: cdlabel not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "cdlabelparent": |
||||
|
{ |
||||
|
throw new Error("KaTeX-a11y: cdlabelparent not implemented yet"); |
||||
|
} |
||||
|
|
||||
|
case "mclass": |
||||
|
{ |
||||
|
// \neq and \ne are macros so we let "htmlmathml" render the mathmal |
||||
|
// side of things and extract the text from that. |
||||
|
var _atomType = tree.mclass.slice(1); // $FlowFixMe: drop the leading "m" from the values in mclass |
||||
|
|
||||
|
|
||||
|
buildA11yStrings(tree.body, a11yStrings, _atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "mathchoice": |
||||
|
{ |
||||
|
// TODO: track which which style we're using, e.g. dispaly, text, etc. |
||||
|
// default to text style if even that may not be the correct style |
||||
|
buildA11yStrings(tree.text, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "htmlmathml": |
||||
|
{ |
||||
|
buildA11yStrings(tree.mathml, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "middle": |
||||
|
{ |
||||
|
buildString(tree.delim, atomType, a11yStrings); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "internal": |
||||
|
{ |
||||
|
// internal nodes are never included in the parse tree |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
case "html": |
||||
|
{ |
||||
|
buildA11yStrings(tree.body, a11yStrings, atomType); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
tree.type; |
||||
|
throw new Error("KaTeX a11y un-recognized type: " + tree.type); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var buildA11yStrings = function buildA11yStrings(tree, a11yStrings, atomType) { |
||||
|
if (a11yStrings === void 0) { |
||||
|
a11yStrings = []; |
||||
|
} |
||||
|
|
||||
|
if (tree instanceof Array) { |
||||
|
for (var i = 0; i < tree.length; i++) { |
||||
|
buildA11yStrings(tree[i], a11yStrings, atomType); |
||||
|
} |
||||
|
} else { |
||||
|
handleObject(tree, a11yStrings, atomType); |
||||
|
} |
||||
|
|
||||
|
return a11yStrings; |
||||
|
}; |
||||
|
|
||||
|
var flatten = function flatten(array) { |
||||
|
var result = []; |
||||
|
array.forEach(function (item) { |
||||
|
if (item instanceof Array) { |
||||
|
result = result.concat(flatten(item)); |
||||
|
} else { |
||||
|
result.push(item); |
||||
|
} |
||||
|
}); |
||||
|
return result; |
||||
|
}; |
||||
|
|
||||
|
var renderA11yString = function renderA11yString(text, settings) { |
||||
|
var tree = katex.__parse(text, settings); |
||||
|
|
||||
|
var a11yStrings = buildA11yStrings(tree, [], "normal"); |
||||
|
return flatten(a11yStrings).join(", "); |
||||
|
}; |
||||
|
|
||||
|
export { renderA11yString as default }; |