NodeUtil.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*************************************************************
  2. *
  3. * Copyright (c) 2009-2022 The MathJax Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * @fileoverview Node utility methods.
  19. *
  20. * @author v.sorge@mathjax.org (Volker Sorge)
  21. */
  22. import {TextNode, MMLNODE, MmlNode, AbstractMmlNode, AbstractMmlEmptyNode} from '../../core/MmlTree/MmlNode.js';
  23. import {MmlMo} from '../../core/MmlTree/MmlNodes/mo.js';
  24. import {Property, PropertyList} from '../../core/Tree/Node.js';
  25. import {Args} from './Types.js';
  26. import {OperatorDef} from '../../core/MmlTree/OperatorDictionary.js';
  27. namespace NodeUtil {
  28. const attrs: Map<String, boolean> = new Map([
  29. ['autoOP', true],
  30. ['fnOP', true],
  31. ['movesupsub', true],
  32. ['subsupOK', true],
  33. ['texprimestyle', true],
  34. ['useHeight', true],
  35. ['variantForm', true],
  36. ['withDelims', true],
  37. ['mathaccent', true],
  38. ['open', true],
  39. ['close', true]
  40. ]);
  41. /**
  42. * Creates a single character from a unicode hex string.
  43. * @param {string} code The code.
  44. * @return {string} The newly created entity.
  45. */
  46. export function createEntity(code: string): string {
  47. return String.fromCodePoint(parseInt(code, 16));
  48. }
  49. /**
  50. * Get the children of the a node.
  51. * @param {MmlNode} node The node.
  52. * @return {MMLNODE[]} Its children.
  53. */
  54. export function getChildren(node: MmlNode): MMLNODE[] {
  55. return (node.childNodes as MMLNODE[]);
  56. }
  57. /**
  58. * Get text content of a node.
  59. * @param {TextNode} node The node.
  60. * @return {string} Its text content.
  61. */
  62. export function getText(node: TextNode): string {
  63. return node.getText();
  64. }
  65. /**
  66. * Append children to a node.
  67. * @param {MmlNode} node The node.
  68. * @param {MMLNODE[]} children A list of new children.
  69. */
  70. export function appendChildren(node: MmlNode, children: MMLNODE[]) {
  71. for (let child of children) {
  72. node.appendChild(child);
  73. }
  74. }
  75. /**
  76. * Sets an attribute of a node.
  77. * @param {MmlNode} node The node.
  78. * @param {string} attribute An attribute.
  79. * @param {Args} value The attribute value.
  80. */
  81. export function setAttribute(node: MmlNode, attribute: string, value: Args) {
  82. node.attributes.set(attribute, value);
  83. }
  84. /**
  85. * Sets a property of a node.
  86. * @param {MmlNode} node The node.
  87. * @param {string} property The property.
  88. * @param {Args} value The property value.
  89. */
  90. export function setProperty(node: MmlNode, property: string, value: Args) {
  91. node.setProperty(property, value);
  92. }
  93. /**
  94. * Sets properties and attributes of a node.
  95. * @param {MmlNode} node The node.
  96. * @param {PropertyList} properties A list of property/attribute value pairs.
  97. */
  98. export function setProperties(node: MmlNode, properties: PropertyList) {
  99. for (const name of Object.keys(properties)) {
  100. let value = properties[name];
  101. if (name === 'texClass') {
  102. node.texClass = (value as number);
  103. node.setProperty(name, value);
  104. } else if (name === 'movablelimits') {
  105. node.setProperty('movablelimits', value);
  106. if (node.isKind('mo') || node.isKind('mstyle')) {
  107. node.attributes.set('movablelimits', value);
  108. }
  109. } else if (name === 'inferred') {
  110. // ignore
  111. } else if (attrs.has(name)) {
  112. node.setProperty(name, value);
  113. } else {
  114. node.attributes.set(name, value);
  115. }
  116. }
  117. }
  118. /**
  119. * Returns the property of a node.
  120. * @param {MmlNode} node The node.
  121. * @param {string} property A property name.
  122. * @return {Property} Value of the property.
  123. */
  124. export function getProperty(node: MmlNode, property: string): Property {
  125. return node.getProperty(property);
  126. }
  127. /**
  128. * Returns the attribute of a node.
  129. * @param {MmlNode} node The node.
  130. * @param {string} attr A attribute name.
  131. * @return {Property} Value of the attribute.
  132. */
  133. export function getAttribute(node: MmlNode, attr: string): Property {
  134. return node.attributes.get(attr);
  135. }
  136. /**
  137. * Removes a set of properties from a node.
  138. * @param {MmlNode} node The node.
  139. * @param {string[]} ...properties A list of properties.
  140. */
  141. export function removeProperties(node: MmlNode, ...properties: string[]) {
  142. node.removeProperty(...properties);
  143. }
  144. /**
  145. * Returns a child node at a given position.
  146. * @param {MmlNode} node The node.
  147. * @param {number} position The position of the child.
  148. * @return {MMLNODE} The child node at position.
  149. */
  150. export function getChildAt(node: MmlNode, position: number): MMLNODE {
  151. return (node.childNodes[position] as MMLNODE);
  152. }
  153. /**
  154. * Set node child at position.
  155. * @param {MmlNode} node The node.
  156. * @param {number} position The position of the new child.
  157. * @param {MmlNode} child The new child.
  158. */
  159. export function setChild(node: MmlNode, position: number, child: MmlNode) {
  160. let children = node.childNodes;
  161. children[position] = child;
  162. if (child) {
  163. child.parent = node;
  164. }
  165. }
  166. /**
  167. * Copies children between nodes.
  168. * @param {MmlNode} oldNode The source node.
  169. * @param {MmlNode} newNode The target node.
  170. */
  171. export function copyChildren(oldNode: MmlNode, newNode: MmlNode) {
  172. let children = oldNode.childNodes as (TextNode | MmlNode)[];
  173. for (let i = 0; i < children.length; i++) {
  174. setChild(newNode, i, children[i]);
  175. }
  176. }
  177. /**
  178. * Copies attributes between nodes.
  179. * @param {MmlNode} oldNode The source node.
  180. * @param {MmlNode} newNode The target node.
  181. */
  182. export function copyAttributes(oldNode: MmlNode, newNode: MmlNode) {
  183. newNode.attributes = oldNode.attributes;
  184. setProperties(newNode, oldNode.getAllProperties());
  185. }
  186. /**
  187. * Checks if node is of a particular type.
  188. * @param {MmlNode} node The node.
  189. * @param {string} kind The type to check.
  190. * @return {boolean} True if node is of the given type.
  191. */
  192. export function isType(node: MmlNode, kind: string): boolean {
  193. return node.isKind(kind);
  194. }
  195. /**
  196. * Checks if the node is embellished.
  197. * @param {MmlNode} node The node.
  198. * @return {boolean} True if node is embellished.
  199. */
  200. export function isEmbellished(node: MmlNode): boolean {
  201. return node.isEmbellished;
  202. }
  203. /**
  204. * Gets the texclass of a node.
  205. * @param {MmlNode} node The node.
  206. * @return {number} Its texclass.
  207. */
  208. export function getTexClass(node: MmlNode): number {
  209. return node.texClass;
  210. }
  211. /**
  212. * Gets the mo element at the core of the node.
  213. * @param {MmlNode} node The node.
  214. * @return {MmlNode} The MO node at the core.
  215. */
  216. export function getCoreMO(node: MmlNode): MmlNode {
  217. return node.coreMO();
  218. }
  219. /**
  220. * Checks if an object is a node.
  221. * @param {any} item The object.
  222. * @return {boolean} True if it is a node.
  223. */
  224. export function isNode(item: any): boolean {
  225. return item instanceof AbstractMmlNode || item instanceof AbstractMmlEmptyNode;
  226. }
  227. /**
  228. * Checks if the node is an inferred mrow.
  229. * @param {MmlNode} node The node.
  230. * @return {boolean} True if the node is an inferred mrow.
  231. */
  232. export function isInferred(node: MmlNode): boolean {
  233. return node.isInferred;
  234. }
  235. /**
  236. * Gets the operator definition of a node.
  237. * @param {MmlNode} node The node.
  238. * @return {OperatorDef} If node is an MO returns the operator definition. O/w
  239. * null.
  240. */
  241. export function getForm(node: MmlNode): OperatorDef {
  242. if (!isType(node, 'mo')) {
  243. return null;
  244. }
  245. let mo = node as MmlMo;
  246. let forms = mo.getForms();
  247. for (let form of forms) {
  248. let symbol = MmlMo.OPTABLE[form][mo.getText()];
  249. if (symbol) {
  250. return symbol;
  251. }
  252. }
  253. return null;
  254. }
  255. }
  256. export default NodeUtil;