case_embellished.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.CaseEmbellished = void 0;
  4. const DomUtil = require("../common/dom_util.js");
  5. const semantic_meaning_js_1 = require("../semantic_tree/semantic_meaning.js");
  6. const semantic_node_js_1 = require("../semantic_tree/semantic_node.js");
  7. const semantic_util_js_1 = require("../semantic_tree/semantic_util.js");
  8. const abstract_enrich_case_js_1 = require("./abstract_enrich_case.js");
  9. const case_double_script_js_1 = require("./case_double_script.js");
  10. const case_multiscripts_js_1 = require("./case_multiscripts.js");
  11. const case_tensor_js_1 = require("./case_tensor.js");
  12. const EnrichMathml = require("./enrich_mathml.js");
  13. const enrich_attr_js_1 = require("./enrich_attr.js");
  14. class CaseEmbellished extends abstract_enrich_case_js_1.AbstractEnrichCase {
  15. static test(semantic) {
  16. return !!(semantic.mathmlTree &&
  17. semantic.fencePointer &&
  18. !semantic.mathmlTree.getAttribute('data-semantic-type'));
  19. }
  20. static makeEmptyNode_(id) {
  21. const mrow = (0, enrich_attr_js_1.addMrow)();
  22. const empty = new semantic_node_js_1.SemanticNode(id);
  23. empty.type = semantic_meaning_js_1.SemanticType.EMPTY;
  24. empty.mathmlTree = mrow;
  25. return empty;
  26. }
  27. static fencedMap_(fence, ids) {
  28. ids[fence.id] = fence.mathmlTree;
  29. if (!fence.embellished) {
  30. return;
  31. }
  32. CaseEmbellished.fencedMap_(fence.childNodes[0], ids);
  33. }
  34. constructor(semantic) {
  35. super(semantic);
  36. this.fenced = null;
  37. this.fencedMml = null;
  38. this.fencedMmlNodes = [];
  39. this.ofence = null;
  40. this.ofenceMml = null;
  41. this.ofenceMap = {};
  42. this.cfence = null;
  43. this.cfenceMml = null;
  44. this.cfenceMap = {};
  45. this.parentCleanup = [];
  46. }
  47. getMathml() {
  48. this.getFenced_();
  49. this.fencedMml = EnrichMathml.walkTree(this.fenced);
  50. this.getFencesMml_();
  51. if (this.fenced.type === semantic_meaning_js_1.SemanticType.EMPTY && !this.fencedMml.parentNode) {
  52. this.fencedMml.setAttribute(enrich_attr_js_1.Attribute.ADDED, 'true');
  53. this.cfenceMml.parentNode.insertBefore(this.fencedMml, this.cfenceMml);
  54. }
  55. this.getFencedMml_();
  56. const rewrite = this.rewrite_();
  57. return rewrite;
  58. }
  59. fencedElement(node) {
  60. return (node.type === semantic_meaning_js_1.SemanticType.FENCED ||
  61. node.type === semantic_meaning_js_1.SemanticType.MATRIX ||
  62. node.type === semantic_meaning_js_1.SemanticType.VECTOR);
  63. }
  64. getFenced_() {
  65. let currentNode = this.semantic;
  66. while (!this.fencedElement(currentNode)) {
  67. currentNode = currentNode.childNodes[0];
  68. }
  69. this.fenced = currentNode.childNodes[0];
  70. this.ofence = currentNode.contentNodes[0];
  71. this.cfence = currentNode.contentNodes[1];
  72. CaseEmbellished.fencedMap_(this.ofence, this.ofenceMap);
  73. CaseEmbellished.fencedMap_(this.cfence, this.cfenceMap);
  74. }
  75. getFencedMml_() {
  76. let sibling = this.ofenceMml.nextSibling;
  77. sibling = sibling === this.fencedMml ? sibling : this.fencedMml;
  78. while (sibling && sibling !== this.cfenceMml) {
  79. this.fencedMmlNodes.push(sibling);
  80. sibling = sibling.nextSibling;
  81. }
  82. }
  83. getFencesMml_() {
  84. let currentNode = this.semantic;
  85. const ofenceIds = Object.keys(this.ofenceMap);
  86. const cfenceIds = Object.keys(this.cfenceMap);
  87. while ((!this.ofenceMml || !this.cfenceMml) &&
  88. currentNode !== this.fenced) {
  89. if (ofenceIds.indexOf(currentNode.fencePointer) !== -1 &&
  90. !this.ofenceMml) {
  91. this.ofenceMml = currentNode.mathmlTree;
  92. }
  93. if (cfenceIds.indexOf(currentNode.fencePointer) !== -1 &&
  94. !this.cfenceMml) {
  95. this.cfenceMml = currentNode.mathmlTree;
  96. }
  97. currentNode = currentNode.childNodes[0];
  98. }
  99. if (!this.ofenceMml) {
  100. this.ofenceMml = this.ofence.mathmlTree;
  101. }
  102. if (!this.cfenceMml) {
  103. this.cfenceMml = this.cfence.mathmlTree;
  104. }
  105. if (this.ofenceMml) {
  106. this.ofenceMml = EnrichMathml.ascendNewNode(this.ofenceMml);
  107. }
  108. if (this.cfenceMml) {
  109. this.cfenceMml = EnrichMathml.ascendNewNode(this.cfenceMml);
  110. }
  111. }
  112. rewrite_() {
  113. let currentNode = this.semantic;
  114. let result = null;
  115. const newNode = this.introduceNewLayer_();
  116. (0, enrich_attr_js_1.setAttributes)(newNode, this.fenced.parent);
  117. while (!this.fencedElement(currentNode)) {
  118. const mml = currentNode.mathmlTree;
  119. const specialCase = this.specialCase_(currentNode, mml);
  120. if (specialCase) {
  121. currentNode = specialCase;
  122. }
  123. else {
  124. (0, enrich_attr_js_1.setAttributes)(mml, currentNode);
  125. const mmlChildren = [];
  126. for (let i = 1, child; (child = currentNode.childNodes[i]); i++) {
  127. mmlChildren.push(EnrichMathml.walkTree(child));
  128. }
  129. currentNode = currentNode.childNodes[0];
  130. }
  131. const dummy = DomUtil.createElement('dummy');
  132. const saveChild = mml.childNodes[0];
  133. DomUtil.replaceNode(mml, dummy);
  134. DomUtil.replaceNode(newNode, mml);
  135. DomUtil.replaceNode(mml.childNodes[0], newNode);
  136. DomUtil.replaceNode(dummy, saveChild);
  137. if (!result) {
  138. result = mml;
  139. }
  140. }
  141. EnrichMathml.walkTree(this.ofence);
  142. EnrichMathml.walkTree(this.cfence);
  143. this.cleanupParents_();
  144. return result || newNode;
  145. }
  146. specialCase_(semantic, mml) {
  147. const mmlTag = DomUtil.tagName(mml);
  148. let parent = null;
  149. let caller;
  150. if (mmlTag === semantic_util_js_1.MMLTAGS.MSUBSUP) {
  151. parent = semantic.childNodes[0];
  152. caller = case_double_script_js_1.CaseDoubleScript;
  153. }
  154. else if (mmlTag === semantic_util_js_1.MMLTAGS.MMULTISCRIPTS) {
  155. if (semantic.type === semantic_meaning_js_1.SemanticType.SUPERSCRIPT ||
  156. semantic.type === semantic_meaning_js_1.SemanticType.SUBSCRIPT) {
  157. caller = case_multiscripts_js_1.CaseMultiscripts;
  158. }
  159. else if (semantic.type === semantic_meaning_js_1.SemanticType.TENSOR) {
  160. caller = case_tensor_js_1.CaseTensor;
  161. }
  162. if (caller &&
  163. semantic.childNodes[0] &&
  164. semantic.childNodes[0].role === semantic_meaning_js_1.SemanticRole.SUBSUP) {
  165. parent = semantic.childNodes[0];
  166. }
  167. else {
  168. parent = semantic;
  169. }
  170. }
  171. if (!parent) {
  172. return null;
  173. }
  174. const base = parent.childNodes[0];
  175. const empty = CaseEmbellished.makeEmptyNode_(base.id);
  176. parent.childNodes[0] = empty;
  177. mml = new caller(semantic).getMathml();
  178. parent.childNodes[0] = base;
  179. this.parentCleanup.push(mml);
  180. return parent.childNodes[0];
  181. }
  182. introduceNewLayer_() {
  183. const fullOfence = this.fullFence(this.ofenceMml);
  184. const fullCfence = this.fullFence(this.cfenceMml);
  185. let newNode = (0, enrich_attr_js_1.addMrow)();
  186. DomUtil.replaceNode(this.fencedMml, newNode);
  187. this.fencedMmlNodes.forEach((node) => newNode.appendChild(node));
  188. newNode.insertBefore(fullOfence, this.fencedMml);
  189. newNode.appendChild(fullCfence);
  190. if (!newNode.parentNode) {
  191. const mrow = (0, enrich_attr_js_1.addMrow)();
  192. while (newNode.childNodes.length > 0) {
  193. mrow.appendChild(newNode.childNodes[0]);
  194. }
  195. newNode.appendChild(mrow);
  196. newNode = mrow;
  197. }
  198. return newNode;
  199. }
  200. fullFence(fence) {
  201. const parent = this.fencedMml.parentNode;
  202. let currentFence = fence;
  203. while (currentFence.parentNode && currentFence.parentNode !== parent) {
  204. currentFence = currentFence.parentNode;
  205. }
  206. return currentFence;
  207. }
  208. cleanupParents_() {
  209. this.parentCleanup.forEach(function (x) {
  210. const parent = x.childNodes[1].getAttribute(enrich_attr_js_1.Attribute.PARENT);
  211. x.childNodes[0].setAttribute(enrich_attr_js_1.Attribute.PARENT, parent);
  212. });
  213. }
  214. }
  215. exports.CaseEmbellished = CaseEmbellished;