semantic_skeleton.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.SemanticSkeleton = void 0;
  4. const BaseUtil = require("../common/base_util.js");
  5. const engine_js_1 = require("../common/engine.js");
  6. const XpathUtil = require("../common/xpath_util.js");
  7. const enrich_attr_js_1 = require("../enrich_mathml/enrich_attr.js");
  8. const semantic_meaning_js_1 = require("./semantic_meaning.js");
  9. const Options = {
  10. tree: false
  11. };
  12. class SemanticSkeleton {
  13. static fromTree(tree) {
  14. return SemanticSkeleton.fromNode(tree.root);
  15. }
  16. static fromNode(node) {
  17. return new SemanticSkeleton(SemanticSkeleton.fromNode_(node));
  18. }
  19. static fromString(skel) {
  20. return new SemanticSkeleton(SemanticSkeleton.fromString_(skel));
  21. }
  22. static simpleCollapseStructure(strct) {
  23. return typeof strct === 'number';
  24. }
  25. static contentCollapseStructure(strct) {
  26. return (!!strct &&
  27. !SemanticSkeleton.simpleCollapseStructure(strct) &&
  28. strct[0] === 'c');
  29. }
  30. static interleaveIds(first, second) {
  31. return BaseUtil.interleaveLists(SemanticSkeleton.collapsedLeafs(first), SemanticSkeleton.collapsedLeafs(second));
  32. }
  33. static collapsedLeafs(...args) {
  34. const collapseStructure = (coll) => {
  35. if (SemanticSkeleton.simpleCollapseStructure(coll)) {
  36. return [coll];
  37. }
  38. coll = coll;
  39. return SemanticSkeleton.contentCollapseStructure(coll[1])
  40. ? coll.slice(2)
  41. : coll.slice(1);
  42. };
  43. return args.reduce((x, y) => x.concat(collapseStructure(y)), []);
  44. }
  45. static fromStructure(mml, tree) {
  46. return new SemanticSkeleton(SemanticSkeleton.tree_(mml, tree.root));
  47. }
  48. static combineContentChildren(type, _role, content, children) {
  49. switch (type) {
  50. case semantic_meaning_js_1.SemanticType.RELSEQ:
  51. case semantic_meaning_js_1.SemanticType.INFIXOP:
  52. case semantic_meaning_js_1.SemanticType.MULTIREL:
  53. return BaseUtil.interleaveLists(children, content);
  54. case semantic_meaning_js_1.SemanticType.PREFIXOP:
  55. return content.concat(children);
  56. case semantic_meaning_js_1.SemanticType.POSTFIXOP:
  57. return children.concat(content);
  58. case semantic_meaning_js_1.SemanticType.MATRIX:
  59. case semantic_meaning_js_1.SemanticType.VECTOR:
  60. case semantic_meaning_js_1.SemanticType.FENCED:
  61. children.unshift(content[0]);
  62. children.push(content[1]);
  63. return children;
  64. case semantic_meaning_js_1.SemanticType.CASES:
  65. children.unshift(content[0]);
  66. return children;
  67. case semantic_meaning_js_1.SemanticType.APPL:
  68. return [children[0], content[0], children[1]];
  69. case semantic_meaning_js_1.SemanticType.ROOT:
  70. return [children[0], children[1]];
  71. case semantic_meaning_js_1.SemanticType.ROW:
  72. case semantic_meaning_js_1.SemanticType.LINE:
  73. if (content.length) {
  74. children.unshift(content[0]);
  75. }
  76. return children;
  77. default:
  78. return children;
  79. }
  80. }
  81. static makeSexp_(struct) {
  82. if (SemanticSkeleton.simpleCollapseStructure(struct)) {
  83. return struct.toString();
  84. }
  85. if (SemanticSkeleton.contentCollapseStructure(struct)) {
  86. return ('(' +
  87. 'c ' +
  88. struct.slice(1).map(SemanticSkeleton.makeSexp_).join(' ') +
  89. ')');
  90. }
  91. return ('(' + struct.map(SemanticSkeleton.makeSexp_).join(' ') + ')');
  92. }
  93. static fromString_(skeleton) {
  94. let str = skeleton.replace(/\(/g, '[');
  95. str = str.replace(/\)/g, ']');
  96. str = str.replace(/ /g, ',');
  97. str = str.replace(/c/g, '"c"');
  98. return JSON.parse(str);
  99. }
  100. static fromNode_(node) {
  101. if (!node) {
  102. return [];
  103. }
  104. const content = node.contentNodes;
  105. let contentStructure;
  106. if (content.length) {
  107. contentStructure = content.map(SemanticSkeleton.fromNode_);
  108. contentStructure.unshift('c');
  109. }
  110. const children = node.childNodes;
  111. if (!children.length) {
  112. return content.length ? [node.id, contentStructure] : node.id;
  113. }
  114. const structure = children.map(SemanticSkeleton.fromNode_);
  115. if (content.length) {
  116. structure.unshift(contentStructure);
  117. }
  118. structure.unshift(node.id);
  119. return structure;
  120. }
  121. static tree_(mml, node, level = 0, posinset = 1, setsize = 1) {
  122. if (!node) {
  123. return [];
  124. }
  125. const id = node.id;
  126. const skeleton = [id];
  127. XpathUtil.updateEvaluator(mml);
  128. const mmlChild = XpathUtil.evalXPath(`.//self::*[@${enrich_attr_js_1.Attribute.ID}=${id}]`, mml)[0];
  129. if (!node.childNodes.length) {
  130. SemanticSkeleton.addAria(mmlChild, level, posinset, setsize);
  131. return node.id;
  132. }
  133. const children = SemanticSkeleton.combineContentChildren(node.type, node.role, node.contentNodes.map(function (x) {
  134. return x;
  135. }), node.childNodes.map(function (x) {
  136. return x;
  137. }));
  138. if (mmlChild) {
  139. SemanticSkeleton.addOwns_(mmlChild, children);
  140. }
  141. for (let i = 0, l = children.length, child; (child = children[i]); i++) {
  142. skeleton.push(SemanticSkeleton.tree_(mml, child, level + 1, i + 1, l));
  143. }
  144. SemanticSkeleton.addAria(mmlChild, level, posinset, setsize, !Options.tree ? 'treeitem' : level ? 'group' : 'tree');
  145. return skeleton;
  146. }
  147. static addAria(node, level, posinset, setsize, role = !Options.tree ? 'treeitem' : level ? 'treeitem' : 'tree') {
  148. if (!engine_js_1.Engine.getInstance().aria || !node) {
  149. return;
  150. }
  151. node.setAttribute('aria-level', level.toString());
  152. node.setAttribute('aria-posinset', posinset.toString());
  153. node.setAttribute('aria-setsize', setsize.toString());
  154. node.setAttribute('role', role);
  155. if (node.hasAttribute(enrich_attr_js_1.Attribute.OWNS)) {
  156. node.setAttribute('aria-owns', node.getAttribute(enrich_attr_js_1.Attribute.OWNS));
  157. }
  158. }
  159. static addOwns_(node, children) {
  160. const collapsed = node.getAttribute(enrich_attr_js_1.Attribute.COLLAPSED);
  161. const leafs = collapsed
  162. ? SemanticSkeleton.realLeafs_(SemanticSkeleton.fromString(collapsed).array)
  163. : children.map((x) => x.id);
  164. node.setAttribute(enrich_attr_js_1.Attribute.OWNS, leafs.join(' '));
  165. }
  166. static realLeafs_(sexp) {
  167. if (SemanticSkeleton.simpleCollapseStructure(sexp)) {
  168. return [sexp];
  169. }
  170. if (SemanticSkeleton.contentCollapseStructure(sexp)) {
  171. return [];
  172. }
  173. sexp = sexp;
  174. let result = [];
  175. for (let i = 1; i < sexp.length; i++) {
  176. result = result.concat(SemanticSkeleton.realLeafs_(sexp[i]));
  177. }
  178. return result;
  179. }
  180. constructor(skeleton) {
  181. this.parents = null;
  182. this.levelsMap = null;
  183. skeleton = skeleton === 0 ? skeleton : skeleton || [];
  184. this.array = skeleton;
  185. }
  186. populate() {
  187. if (this.parents && this.levelsMap) {
  188. return;
  189. }
  190. this.parents = {};
  191. this.levelsMap = {};
  192. this.populate_(this.array, this.array, []);
  193. }
  194. toString() {
  195. return SemanticSkeleton.makeSexp_(this.array);
  196. }
  197. populate_(element, layer, parents) {
  198. if (SemanticSkeleton.simpleCollapseStructure(element)) {
  199. element = element;
  200. this.levelsMap[element] = layer;
  201. this.parents[element] =
  202. element === parents[0] ? parents.slice(1) : parents;
  203. return;
  204. }
  205. const newElement = SemanticSkeleton.contentCollapseStructure(element)
  206. ? element.slice(1)
  207. : element;
  208. const newParents = [newElement[0]].concat(parents);
  209. for (let i = 0, l = newElement.length; i < l; i++) {
  210. const current = newElement[i];
  211. this.populate_(current, element, newParents);
  212. }
  213. }
  214. isRoot(id) {
  215. const level = this.levelsMap[id];
  216. return id === level[0];
  217. }
  218. directChildren(id) {
  219. if (!this.isRoot(id)) {
  220. return [];
  221. }
  222. const level = this.levelsMap[id];
  223. return level.slice(1).map((child) => {
  224. if (SemanticSkeleton.simpleCollapseStructure(child)) {
  225. return child;
  226. }
  227. if (SemanticSkeleton.contentCollapseStructure(child)) {
  228. return child[1];
  229. }
  230. return child[0];
  231. });
  232. }
  233. subtreeNodes(id) {
  234. if (!this.isRoot(id)) {
  235. return [];
  236. }
  237. const subtreeNodes_ = (tree, nodes) => {
  238. if (SemanticSkeleton.simpleCollapseStructure(tree)) {
  239. nodes.push(tree);
  240. return;
  241. }
  242. tree = tree;
  243. if (SemanticSkeleton.contentCollapseStructure(tree)) {
  244. tree = tree.slice(1);
  245. }
  246. tree.forEach((x) => subtreeNodes_(x, nodes));
  247. };
  248. const level = this.levelsMap[id];
  249. const subtree = [];
  250. subtreeNodes_(level.slice(1), subtree);
  251. return subtree;
  252. }
  253. }
  254. exports.SemanticSkeleton = SemanticSkeleton;