math_util.js revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * @fileoverview DOM utility functions to aid in math expressions navigation.
7 */
8
9goog.provide('cvox.MathUtil');
10
11goog.require('cvox.ChromeVox');
12goog.require('cvox.XpathUtil');
13
14
15/**
16 * Checks if a node is in a given class of MathML nodes.
17 * @private
18 * @param {!Node} node The node to test.
19 * @param {Array.<string>} tags List of tag names.
20 * @return {boolean} True if node has a tag name included in tags.
21 */
22cvox.MathUtil.isMathmlNodeOfClass_ = function(node, tags) {
23  return tags.indexOf(node.tagName.toUpperCase()) != -1;
24};
25
26
27/**
28 * Checks if a node is in a given class of MathJax nodes.
29 * @private
30 * @param {!Node} node The node to test.
31 * @param {Array.<string>} tags List of tag names.
32 * @return {boolean} True if node has a tag name included in tags.
33 */
34cvox.MathUtil.isMathjaxNodeOfClass_ = function(node, tags) {
35  if (node.tagName == 'SPAN') {
36    var classes = node.className.split(' ');
37    return classes.some(function(x)
38                        {return tags.indexOf(x.toUpperCase()) != -1;});
39  }
40  return false;
41};
42
43
44/**
45 * Checks if a node is an element node that belongs to a given class
46 * of MathML or MathJax nodes.
47 * @private
48 * @param {!Node} node The node to test.
49 * @param {Array.<string>} tags List of tag names.
50 * @return {boolean} True if node has a tag name included in tags.
51 */
52cvox.MathUtil.isMathNodeOfClass_ = function(node, tags) {
53  return (node.nodeType == Node.ELEMENT_NODE &&
54          (cvox.MathUtil.isMathmlNodeOfClass_(node, tags) ||
55           cvox.MathUtil.isMathjaxNodeOfClass_(node, tags)));
56};
57
58
59/**
60 * Array of MathML Token Elements.
61 * @type {!Array.<string>}
62 */
63cvox.MathUtil.TOKEN_LIST = ['MI', 'MN', 'MO', 'MTEXT', 'MSPACE', 'MS'];
64
65
66/**
67 *  Checks if an element of a math expression is a Token Element.
68 * Token elements are the following:
69 * <mi> identifier.
70 * <mn> number.
71 * <mo> operator, fence, or separator.
72 * <mtext> text.
73 * <mspace> space.
74 * <ms> string literal.
75 * @param {!Node} element The element of the math expression.
76 * @return {boolean} True if element is a token.
77 */
78cvox.MathUtil.isToken = function(element) {
79  return cvox.MathUtil.isMathNodeOfClass_(element, cvox.MathUtil.TOKEN_LIST);
80};
81
82
83/**
84 * Array of MathML Layout Schemata.
85 * @type {!Array.<string>}
86 */
87cvox.MathUtil.LAYOUT_LIST = ['MROW', 'MFRAC', 'MSQRT', 'MROOT', 'MSTYLE',
88                             'MERROR', 'MPADDED', 'MPHANTOM', 'MFENCED',
89                             'MENCLOSE'];
90
91
92/**
93 *  Checks if an element of a math expression is a Layout Schema.
94 * Layout elements are the following:
95 * <mrow> group any number of sub-expressions horizontally
96 * <mfrac> form a fraction from two sub-expressions
97 * <msqrt> form a square root (radical without an index)
98 * <mroot> form a radical with specified index
99 * <mstyle> style change
100 * <merror> enclose a syntax error message from a preprocessor
101 * <mpadded> adjust space around content
102 * <mphantom> make content invisible but preserve its size
103 * <mfenced> surround content with a pair of fences
104 * <menclose> enclose content with a stretching symbol such as a long
105 * division sign.
106 * @param {!Node} element The element of the math expression.
107 * @return {boolean} True if element is a layout schema.
108 */
109cvox.MathUtil.isLayout = function(element) {
110  return cvox.MathUtil.isMathNodeOfClass_(element, cvox.MathUtil.LAYOUT_LIST);
111};
112
113
114/**
115 * Array of MathML Script Schemata.
116 * @type {!Array.<string>}
117 */
118cvox.MathUtil.SCRIPT_LIST = ['MSUB', 'MSUP', 'MSUBSUP', 'MUNDER', 'MOVER',
119                             'MUNDEROVER', 'MMULTISCRIPTS', 'MPRESCRIPTS'];
120
121
122/**
123 *  Checks if an element of a math expression is a Script Schema.
124 * Script elements are the following:
125 * <msub> attach a subscript to a base.
126 * <msup> attach a superscript to a base.
127 * <msubsup> attach a subscript-superscript pair to a base.
128 * <munder> attach an underscript to a base.
129 * <mover> attach an overscript to a base.
130 * <munderover> attach an underscript-overscript pair to a base.
131 * <mmultiscripts> attach prescripts and tensor indices to a base.
132 * Prescripts are optional.
133 * <mprescripts> two elements prescripts of mmultiscripts. Only makes sense
134 * in that environment (although not illegal outside)!  Two
135 * arguments mandatory (can be <none/>).
136 * @param {!Node} element The element of the math expression.
137 * @return {boolean} True if element is a script schema.
138 */
139cvox.MathUtil.isScript = function(element) {
140  return cvox.MathUtil.isMathNodeOfClass_(element, cvox.MathUtil.SCRIPT_LIST);
141};
142
143
144/**
145 * Array of MathML Table and Matrix tokens.
146 * @type {!Array.<string>}
147 */
148cvox.MathUtil.TABLES_LIST = ['MTABLE', 'MLABELEDTR', 'MTR', 'MTD',
149                             'MALIGNGROUP', 'MALIGNMARK'];
150
151
152/**
153 *  Checks if an element of a math expression is a Tables Schema.
154 * Tables elements are the following:
155 * <mtable> table or matrix.
156 * <mlabeledtr> row in a table or matrix with a label or equation number.
157 * <mtr> row in a table or matrix.
158 * <mtd> one entry in a table or matrix.
159 * <maligngroup> and
160 * <malignmark> alignment markers.
161 * @param {!Node} element The element of the math expression.
162 * @return {boolean} True if element is a tables schema.
163 */
164cvox.MathUtil.isTables = function(element) {
165  return cvox.MathUtil.isMathNodeOfClass_(element, cvox.MathUtil.TABLES_LIST);
166};
167
168
169/**
170 * Array of MathML Elementary Layout Schemata.
171 * @type {!Array.<string>}
172 */
173cvox.MathUtil.ELEMENTARY_LIST = ['MSTACK', 'MLONGDIV', 'MSGROUP', 'MSROW',
174                                 'MSCARRIES', 'MSCARRY', 'MSLINE'];
175
176
177/**
178 *  Checks if an element of a math expression is a Elementary Schema.
179 * Elementary elements are the following:
180 * <mstack> columns of aligned characters.
181 * <mlongdiv> similar to msgroup, with the addition of a divisor and result.
182 * <msgroup> a group of rows in an mstack that are shifted by similar amounts.
183 * <msrow> a row in an mstack.
184 * <mscarries> row in an mstack that whose contents represent carries
185 *             or borrows.
186 * <mscarry> one entry in an mscarries.
187 * <msline> horizontal line inside of mstack.
188 * @param {!Node} element The element of the math expression.
189 * @return {boolean} True if element is a elementary schema.
190 */
191cvox.MathUtil.isElementary = function(element) {
192  return cvox.MathUtil.isMathNodeOfClass_(element,
193                                          cvox.MathUtil.ELEMENTARY_LIST);
194};
195
196
197/**
198 * Array of all valid tags in a MathML expression.
199 * This is a union of all other token lists.
200 * @type {!Array.<string>}
201 */
202cvox.MathUtil.MATHML_TAG_LIST = [cvox.MathUtil.TOKEN_LIST,
203                                 cvox.MathUtil.LAYOUT_LIST,
204                                 cvox.MathUtil.SCRIPT_LIST,
205                                 cvox.MathUtil.TABLES_LIST,
206                                 cvox.MathUtil.ELEMENTARY_LIST].reduce(
207                                     function(x, y) { return x.concat(y); });
208
209
210/**
211 * Checks if a node is valid element of a MathML expression.
212 * @param {!Node} element The element of the math expression.
213 * @return {boolean} True if element has a valid MathML tag.
214 */
215cvox.MathUtil.isMathmlTag = function(element) {
216  return cvox.MathUtil.isMathNodeOfClass_(element,
217                                          cvox.MathUtil.MATHML_TAG_LIST);
218};
219
220
221/**
222 * Array of MathML Whitespace and Alignment tokens.
223 * These are elements that can occur in the other token lists.
224 * @type {!Array.<string>}
225 */
226cvox.MathUtil.WHITESPACE_LIST = ['MSROW', 'MROW', 'MSPACE',
227                                 'MPHANTOM', 'MPADDED'];
228
229
230/**
231 * Checks if an element of a math expression is whitespace or an
232 * alignment marker.
233 * @param {!Node} element The element of the math expression.
234 * @return {boolean} True if element is a whitespace node.
235 */
236cvox.MathUtil.isWhitespace = function(element) {
237  return cvox.MathUtil.isMathNodeOfClass_(element,
238                                          cvox.MathUtil.WHITESPACE_LIST);
239};
240
241
242/**
243 * Checks if an element of a math expression is a legal mathml markup element
244 * but not a whitespace or an alignment marker.
245 * @param {!Node} element The element of the math expression.
246 * @return {boolean} True if element is a non-whitespace node.
247 */
248cvox.MathUtil.isNotWhitespace = function(element) {
249  return (cvox.MathUtil.isMathmlTag(element) &&
250          !cvox.MathUtil.isWhitespace(element));
251};
252
253
254/**
255 * Computes the union of two arrays (not in a strictly set theoretical sense
256 * as all duplicate elements in either array still remain as duplicates!).
257 * @param {Array} a An array.
258 * @param {Array} b Another array.
259 * @return {Array} Union of a and b.
260 */
261cvox.MathUtil.union = function(a, b) {
262  return a.concat(b.filter(function(x) {return a.indexOf(x) < 0;}));
263};
264