semantic_util.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.MMLTAGS = void 0;
  4. exports.hasMathTag = hasMathTag;
  5. exports.hasIgnoreTag = hasIgnoreTag;
  6. exports.hasEmptyTag = hasEmptyTag;
  7. exports.hasDisplayTag = hasDisplayTag;
  8. exports.isOrphanedGlyph = isOrphanedGlyph;
  9. exports.purgeNodes = purgeNodes;
  10. exports.isZeroLength = isZeroLength;
  11. exports.addAttributes = addAttributes;
  12. exports.getEmbellishedInner = getEmbellishedInner;
  13. exports.sliceNodes = sliceNodes;
  14. exports.partitionNodes = partitionNodes;
  15. const DomUtil = require("../common/dom_util.js");
  16. var MMLTAGS;
  17. (function (MMLTAGS) {
  18. MMLTAGS["ANNOTATION"] = "ANNOTATION";
  19. MMLTAGS["ANNOTATIONXML"] = "ANNOTATION-XML";
  20. MMLTAGS["MACTION"] = "MACTION";
  21. MMLTAGS["MALIGNGROUP"] = "MALIGNGROUP";
  22. MMLTAGS["MALIGNMARK"] = "MALIGNMARK";
  23. MMLTAGS["MATH"] = "MATH";
  24. MMLTAGS["MENCLOSE"] = "MENCLOSE";
  25. MMLTAGS["MERROR"] = "MERROR";
  26. MMLTAGS["MFENCED"] = "MFENCED";
  27. MMLTAGS["MFRAC"] = "MFRAC";
  28. MMLTAGS["MGLYPH"] = "MGLYPH";
  29. MMLTAGS["MI"] = "MI";
  30. MMLTAGS["MLABELEDTR"] = "MLABELEDTR";
  31. MMLTAGS["MMULTISCRIPTS"] = "MMULTISCRIPTS";
  32. MMLTAGS["MN"] = "MN";
  33. MMLTAGS["MO"] = "MO";
  34. MMLTAGS["MOVER"] = "MOVER";
  35. MMLTAGS["MPADDED"] = "MPADDED";
  36. MMLTAGS["MPHANTOM"] = "MPHANTOM";
  37. MMLTAGS["MPRESCRIPTS"] = "MPRESCRIPTS";
  38. MMLTAGS["MROOT"] = "MROOT";
  39. MMLTAGS["MROW"] = "MROW";
  40. MMLTAGS["MS"] = "MS";
  41. MMLTAGS["MSPACE"] = "MSPACE";
  42. MMLTAGS["MSQRT"] = "MSQRT";
  43. MMLTAGS["MSTYLE"] = "MSTYLE";
  44. MMLTAGS["MSUB"] = "MSUB";
  45. MMLTAGS["MSUBSUP"] = "MSUBSUP";
  46. MMLTAGS["MSUP"] = "MSUP";
  47. MMLTAGS["MTABLE"] = "MTABLE";
  48. MMLTAGS["MTD"] = "MTD";
  49. MMLTAGS["MTEXT"] = "MTEXT";
  50. MMLTAGS["MTR"] = "MTR";
  51. MMLTAGS["MUNDER"] = "MUNDER";
  52. MMLTAGS["MUNDEROVER"] = "MUNDEROVER";
  53. MMLTAGS["NONE"] = "NONE";
  54. MMLTAGS["SEMANTICS"] = "SEMANTICS";
  55. })(MMLTAGS || (exports.MMLTAGS = MMLTAGS = {}));
  56. const ALLTAGS = Object.values(MMLTAGS);
  57. const LEAFTAGS = [
  58. MMLTAGS.MO,
  59. MMLTAGS.MI,
  60. MMLTAGS.MN,
  61. MMLTAGS.MTEXT,
  62. MMLTAGS.MS,
  63. MMLTAGS.MSPACE
  64. ];
  65. const IGNORETAGS = [
  66. MMLTAGS.MERROR,
  67. MMLTAGS.MPHANTOM,
  68. MMLTAGS.MALIGNGROUP,
  69. MMLTAGS.MALIGNMARK,
  70. MMLTAGS.MPRESCRIPTS,
  71. MMLTAGS.ANNOTATION,
  72. MMLTAGS.ANNOTATIONXML
  73. ];
  74. const EMPTYTAGS = [
  75. MMLTAGS.MATH,
  76. MMLTAGS.MROW,
  77. MMLTAGS.MPADDED,
  78. MMLTAGS.MACTION,
  79. MMLTAGS.NONE,
  80. MMLTAGS.MSTYLE,
  81. MMLTAGS.SEMANTICS
  82. ];
  83. const DISPLAYTAGS = [MMLTAGS.MROOT, MMLTAGS.MSQRT];
  84. const directSpeechKeys = ['aria-label', 'exact-speech', 'alt'];
  85. function hasMathTag(node) {
  86. return !!node && DomUtil.tagName(node) === MMLTAGS.MATH;
  87. }
  88. function hasLeafTag(node) {
  89. return !!node && LEAFTAGS.includes(DomUtil.tagName(node));
  90. }
  91. function hasIgnoreTag(node) {
  92. return (!!node &&
  93. (IGNORETAGS.includes(DomUtil.tagName(node)) ||
  94. !ALLTAGS.includes(DomUtil.tagName(node))));
  95. }
  96. function hasEmptyTag(node) {
  97. return !!node && EMPTYTAGS.includes(DomUtil.tagName(node));
  98. }
  99. function hasDisplayTag(node) {
  100. return !!node && DISPLAYTAGS.includes(DomUtil.tagName(node));
  101. }
  102. function isOrphanedGlyph(node) {
  103. return (!!node &&
  104. DomUtil.tagName(node) === MMLTAGS.MGLYPH &&
  105. !hasLeafTag(node.parentNode));
  106. }
  107. function purgeNodes(nodes) {
  108. const nodeArray = [];
  109. for (let i = 0, node; (node = nodes[i]); i++) {
  110. if (node.nodeType !== DomUtil.NodeType.ELEMENT_NODE) {
  111. continue;
  112. }
  113. const tagName = DomUtil.tagName(node);
  114. if (IGNORETAGS.includes(tagName)) {
  115. continue;
  116. }
  117. if (EMPTYTAGS.includes(tagName) && node.childNodes.length === 0) {
  118. continue;
  119. }
  120. nodeArray.push(node);
  121. }
  122. return nodeArray;
  123. }
  124. function isZeroLength(length) {
  125. if (!length) {
  126. return false;
  127. }
  128. const negativeNamedSpaces = [
  129. 'negativeveryverythinmathspace',
  130. 'negativeverythinmathspace',
  131. 'negativethinmathspace',
  132. 'negativemediummathspace',
  133. 'negativethickmathspace',
  134. 'negativeverythickmathspace',
  135. 'negativeveryverythickmathspace'
  136. ];
  137. if (negativeNamedSpaces.includes(length)) {
  138. return true;
  139. }
  140. const value = length.match(/[0-9.]+/);
  141. if (!value) {
  142. return false;
  143. }
  144. return parseFloat(value[0]) === 0;
  145. }
  146. function addAttributes(to, from) {
  147. if (from.hasAttributes()) {
  148. const attrs = from.attributes;
  149. for (let i = attrs.length - 1; i >= 0; i--) {
  150. const key = attrs[i].name;
  151. if (key.match(/^ext/)) {
  152. to.attributes[key] = attrs[i].value;
  153. to.nobreaking = true;
  154. }
  155. if (directSpeechKeys.includes(key)) {
  156. to.attributes['ext-speech'] = attrs[i].value;
  157. to.nobreaking = true;
  158. }
  159. if (key.match(/texclass$/)) {
  160. to.attributes['texclass'] = attrs[i].value;
  161. }
  162. if (key.toLowerCase() === 'data-latex') {
  163. to.attributes['latex'] = attrs[i].value;
  164. }
  165. if (key === 'href') {
  166. to.attributes['href'] = attrs[i].value;
  167. to.nobreaking = true;
  168. }
  169. }
  170. }
  171. }
  172. function getEmbellishedInner(node) {
  173. if (node && node.embellished && node.childNodes.length > 0) {
  174. return getEmbellishedInner(node.childNodes[0]);
  175. }
  176. return node;
  177. }
  178. function sliceNodes(nodes, pred, opt_reverse) {
  179. if (opt_reverse) {
  180. nodes.reverse();
  181. }
  182. const head = [];
  183. for (let i = 0, node; (node = nodes[i]); i++) {
  184. if (pred(node)) {
  185. if (opt_reverse) {
  186. return {
  187. head: nodes.slice(i + 1).reverse(),
  188. div: node,
  189. tail: head.reverse()
  190. };
  191. }
  192. return { head: head, div: node, tail: nodes.slice(i + 1) };
  193. }
  194. head.push(node);
  195. }
  196. if (opt_reverse) {
  197. return { head: [], div: null, tail: head.reverse() };
  198. }
  199. return { head: head, div: null, tail: [] };
  200. }
  201. function partitionNodes(nodes, pred) {
  202. let restNodes = nodes;
  203. const rel = [];
  204. const comp = [];
  205. let result = null;
  206. do {
  207. result = sliceNodes(restNodes, pred);
  208. comp.push(result.head);
  209. rel.push(result.div);
  210. restNodes = result.tail;
  211. } while (result.div);
  212. rel.pop();
  213. return { rel: rel, comp: comp };
  214. }