| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 goog.provide('cvox.TraverseMath'); | 5 goog.provide('cvox.TraverseMath'); |
| 6 | 6 |
| 7 goog.require('cvox.ChromeVox'); | 7 goog.require('cvox.ChromeVox'); |
| 8 goog.require('cvox.DomUtil'); | 8 goog.require('cvox.DomUtil'); |
| 9 goog.require('cvox.SemanticTree'); | 9 goog.require('cvox.SemanticTree'); |
| 10 | 10 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 // If a node has a cvoxid attribute we know that it contains a LaTeX | 124 // If a node has a cvoxid attribute we know that it contains a LaTeX |
| 125 // expression that we have rewritten into its corresponding MathML | 125 // expression that we have rewritten into its corresponding MathML |
| 126 // representation, which we can speak and walk. | 126 // representation, which we can speak and walk. |
| 127 if (!node.hasAttribute('cvoxid')) { | 127 if (!node.hasAttribute('cvoxid')) { |
| 128 return; | 128 return; |
| 129 } | 129 } |
| 130 var cvoxid = node.getAttribute('cvoxid'); | 130 var cvoxid = node.getAttribute('cvoxid'); |
| 131 node = this.allTexs_[cvoxid]; | 131 node = this.allTexs_[cvoxid]; |
| 132 } | 132 } |
| 133 if (cvox.DomUtil.isMathJax(node)) { | 133 if (cvox.DomUtil.isMathJax(node)) { |
| 134 this.activeMathmlHost = this.allMathjaxs_[node.getAttribute('id')]; | 134 this.activeMathmlHost = this.allMathjaxs_[node.getAttribute('id')]; |
| 135 } | 135 } |
| 136 this.activeMath = this.activeMathmlHost || node; | 136 this.activeMath = this.activeMathmlHost || node; |
| 137 this.activeNode = this.activeMathmlHost || node; | 137 this.activeNode = this.activeMathmlHost || node; |
| 138 if (this.activeNode && cvox.TraverseMath.setSemantic_ && | 138 if (this.activeNode && cvox.TraverseMath.setSemantic_ && |
| 139 this.activeNode.nodeType == Node.ELEMENT_NODE) { | 139 this.activeNode.nodeType == Node.ELEMENT_NODE) { |
| 140 this.activeNode = | 140 this.activeNode = |
| 141 (new cvox.SemanticTree(/** @type {!Element} */ (this.activeNode))).xml()
; | 141 (new cvox.SemanticTree(/** @type {!Element} */ (this.activeNode))) |
| 142 .xml(); |
| 142 } | 143 } |
| 143 }; | 144 }; |
| 144 | 145 |
| 145 | 146 |
| 146 /** | 147 /** |
| 147 * Adds a mapping of a MathJax node to its MathML representation to the | 148 * Adds a mapping of a MathJax node to its MathML representation to the |
| 148 * dictionary of MathJax elements. | 149 * dictionary of MathJax elements. |
| 149 * @param {!Node} mml The MathML node. | 150 * @param {!Node} mml The MathML node. |
| 150 * @param {string} id The MathJax node id. | 151 * @param {string} id The MathJax node id. |
| 151 */ | 152 */ |
| 152 cvox.TraverseMath.prototype.addMathjax = function(mml, id) { | 153 cvox.TraverseMath.prototype.addMathjax = function(mml, id) { |
| 153 var spanId = cvox.DomUtil.getMathSpanId(id); | 154 var spanId = cvox.DomUtil.getMathSpanId(id); |
| 154 if (spanId) { | 155 if (spanId) { |
| 155 this.allMathjaxs_[spanId] = mml; | 156 this.allMathjaxs_[spanId] = mml; |
| 156 } else { | 157 } else { |
| 157 this.redoMathjaxs(mml, id); | 158 this.redoMathjaxs(mml, id); |
| 158 } | 159 } |
| 159 }; | 160 }; |
| 160 | 161 |
| 161 | 162 |
| 162 /** | 163 /** |
| 163 * Retries to compute MathML representations of MathJax elements, if | 164 * Retries to compute MathML representations of MathJax elements, if |
| 164 * they have not been filled in during rendering. | 165 * they have not been filled in during rendering. |
| 165 * @param {!Node} mml The MathML node. | 166 * @param {!Node} mml The MathML node. |
| 166 * @param {string} id The MathJax node id. | 167 * @param {string} id The MathJax node id. |
| 167 */ | 168 */ |
| 168 cvox.TraverseMath.prototype.redoMathjaxs = function(mml, id) { | 169 cvox.TraverseMath.prototype.redoMathjaxs = function(mml, id) { |
| 169 var fetch = goog.bind(function() {this.addMathjax(mml, id);}, this); | 170 var fetch = goog.bind(function() { |
| 171 this.addMathjax(mml, id); |
| 172 }, this); |
| 170 setTimeout(fetch, 500); | 173 setTimeout(fetch, 500); |
| 171 }; | 174 }; |
| 172 | 175 |
| 173 | 176 |
| 174 /** | 177 /** |
| 175 * Initializes the MathJax to MathML mapping. | 178 * Initializes the MathJax to MathML mapping. |
| 176 * We first try to get all MathJax elements that are already being rendered. | 179 * We first try to get all MathJax elements that are already being rendered. |
| 177 * Secondly, we register a signal to get updated on all elements that are | 180 * Secondly, we register a signal to get updated on all elements that are |
| 178 * rendered or re-rendered later. | 181 * rendered or re-rendered later. |
| 179 */ | 182 */ |
| 180 cvox.TraverseMath.prototype.initializeMathjaxs = function() { | 183 cvox.TraverseMath.prototype.initializeMathjaxs = function() { |
| 181 var callback = | 184 var callback = goog.bind(function(mml, id) { |
| 182 goog.bind(function(mml, id) { | 185 this.addMathjax(mml, id); |
| 183 this.addMathjax(mml, id); | 186 }, this); |
| 184 }, this); | 187 cvox.ChromeVox.mathJax.isMathjaxActive(function(bool) { |
| 185 cvox.ChromeVox.mathJax.isMathjaxActive( | 188 if (bool) { |
| 186 function(bool) { | 189 cvox.ChromeVox.mathJax.getAllJax(callback); |
| 187 if (bool) { | 190 cvox.ChromeVox.mathJax.registerSignal(callback, 'New Math'); |
| 188 cvox.ChromeVox.mathJax.getAllJax(callback); | 191 } |
| 189 cvox.ChromeVox.mathJax.registerSignal(callback, 'New Math'); | 192 }); |
| 190 } | |
| 191 }); | |
| 192 }; | 193 }; |
| 193 | 194 |
| 194 | 195 |
| 195 /** | 196 /** |
| 196 * Initializes the elements in the page that we identify as potentially | 197 * Initializes the elements in the page that we identify as potentially |
| 197 * containing tex or asciimath alt text. | 198 * containing tex or asciimath alt text. |
| 198 */ | 199 */ |
| 199 cvox.TraverseMath.prototype.initializeAltMaths = function() { | 200 cvox.TraverseMath.prototype.initializeAltMaths = function() { |
| 200 if (!document.querySelector( | 201 if (!document.querySelector( |
| 201 cvox.DomUtil.altMathQuerySelector('tex') + ', ' + | 202 cvox.DomUtil.altMathQuerySelector('tex') + ', ' + |
| 202 cvox.DomUtil.altMathQuerySelector('asciimath'))) { | 203 cvox.DomUtil.altMathQuerySelector('asciimath'))) { |
| 203 return; | 204 return; |
| 204 } | 205 } |
| 205 var callback = goog.bind( | 206 var callback = goog.bind(function(mml, id) { |
| 206 function(mml, id) { | 207 this.allTexs_[id] = mml; |
| 207 this.allTexs_[id] = mml; | 208 }, this); |
| 208 }, this); | |
| 209 // Inject a minimalistic version of MathJax into the page. | 209 // Inject a minimalistic version of MathJax into the page. |
| 210 cvox.ChromeVox.mathJax.injectScripts(); | 210 cvox.ChromeVox.mathJax.injectScripts(); |
| 211 // Once MathJax is injected we harvest all Latex and AsciiMath in alt | 211 // Once MathJax is injected we harvest all Latex and AsciiMath in alt |
| 212 // attributes and translate them to MathML expression. | 212 // attributes and translate them to MathML expression. |
| 213 cvox.ChromeVox.mathJax.isMathjaxActive( | 213 cvox.ChromeVox.mathJax.isMathjaxActive(function(active) { |
| 214 function(active) { | 214 if (active) { |
| 215 if (active) { | 215 cvox.ChromeVox.mathJax.configMediaWiki(); |
| 216 cvox.ChromeVox.mathJax.configMediaWiki(); | 216 cvox.ChromeVox.mathJax.getAllTexs(callback); |
| 217 cvox.ChromeVox.mathJax.getAllTexs(callback); | 217 cvox.ChromeVox.mathJax.getAllAsciiMaths(callback); |
| 218 cvox.ChromeVox.mathJax.getAllAsciiMaths(callback); | 218 } |
| 219 } | 219 }); |
| 220 }); | |
| 221 }; | 220 }; |
| 222 | 221 |
| 223 | 222 |
| 224 /** | 223 /** |
| 225 * Moves to the next leaf node in the current Math expression if it exists. | 224 * Moves to the next leaf node in the current Math expression if it exists. |
| 226 * @param {boolean} reverse True if reversed. False by default. | 225 * @param {boolean} reverse True if reversed. False by default. |
| 227 * @param {function(!Node):boolean} pred Predicate deciding what a leaf is. | 226 * @param {function(!Node):boolean} pred Predicate deciding what a leaf is. |
| 228 * @return {Node} The next node. | 227 * @return {Node} The next node. |
| 229 */ | 228 */ |
| 230 cvox.TraverseMath.prototype.nextLeaf = function(reverse, pred) { | 229 cvox.TraverseMath.prototype.nextLeaf = function(reverse, pred) { |
| 231 if (this.activeNode && this.activeMath) { | 230 if (this.activeNode && this.activeMath) { |
| 232 var next = pred(this.activeNode) ? | 231 var next = pred(this.activeNode) ? |
| 233 cvox.DomUtil.directedFindNextNode( | 232 cvox.DomUtil.directedFindNextNode( |
| 234 this.activeNode, this.activeMath, reverse, pred) : | 233 this.activeNode, this.activeMath, reverse, pred) : |
| 235 cvox.DomUtil.directedFindFirstNode(this.activeNode, reverse, pred); | 234 cvox.DomUtil.directedFindFirstNode(this.activeNode, reverse, pred); |
| 236 if (next) { | 235 if (next) { |
| 237 this.activeNode = next; | 236 this.activeNode = next; |
| 238 } | 237 } |
| 239 } | 238 } |
| 240 return this.activeNode; | 239 return this.activeNode; |
| 241 }; | 240 }; |
| 242 | 241 |
| 243 | 242 |
| 244 // TODO (sorge) Refactor this logic into single walkers. | 243 // TODO (sorge) Refactor this logic into single walkers. |
| 245 /** | 244 /** |
| 246 * Returns a string with the content of the active node. | 245 * Returns a string with the content of the active node. |
| 247 * @return {string} The active content. | 246 * @return {string} The active content. |
| 248 */ | 247 */ |
| 249 cvox.TraverseMath.prototype.activeContent = function() { | 248 cvox.TraverseMath.prototype.activeContent = function() { |
| 250 return this.activeNode.textContent; | 249 return this.activeNode.textContent; |
| 251 }; | 250 }; |
| 252 | 251 |
| 253 | 252 |
| 254 /** | 253 /** |
| 255 * Moves to the next subtree from a given node in a depth first fashion. | 254 * Moves to the next subtree from a given node in a depth first fashion. |
| 256 * @param {boolean} reverse True if reversed. False by default. | 255 * @param {boolean} reverse True if reversed. False by default. |
| 257 * @param {function(!Node):boolean} pred Predicate deciding what a subtree is. | 256 * @param {function(!Node):boolean} pred Predicate deciding what a subtree is. |
| 258 * @return {Node} The next subtree. | 257 * @return {Node} The next subtree. |
| 259 */ | 258 */ |
| 260 cvox.TraverseMath.prototype.nextSubtree = function(reverse, pred) { | 259 cvox.TraverseMath.prototype.nextSubtree = function(reverse, pred) { |
| 261 if (!this.activeNode || !this.activeMath) { | 260 if (!this.activeNode || !this.activeMath) { |
| 262 return null; | 261 return null; |
| 263 } | 262 } |
| 264 if (!reverse) { | 263 if (!reverse) { |
| 265 var child = cvox.DomUtil.directedFindFirstNode( | 264 var child = |
| 266 this.activeNode, reverse, pred); | 265 cvox.DomUtil.directedFindFirstNode(this.activeNode, reverse, pred); |
| 267 if (child) { | 266 if (child) { |
| 268 this.activeNode = child; | 267 this.activeNode = child; |
| 269 } else { | 268 } else { |
| 270 var next = cvox.DomUtil.directedFindNextNode( | 269 var next = cvox.DomUtil.directedFindNextNode( |
| 271 this.activeNode, this.activeMath, reverse, pred); | 270 this.activeNode, this.activeMath, reverse, pred); |
| 272 if (next) { | 271 if (next) { |
| 273 this.activeNode = next; | 272 this.activeNode = next; |
| 274 } | 273 } |
| 275 } | 274 } |
| 276 } else { | 275 } else { |
| 277 if (this.activeNode == this.activeMath) { | 276 if (this.activeNode == this.activeMath) { |
| 278 var child = cvox.DomUtil.directedFindDeepestNode( | 277 var child = |
| 279 this.activeNode, reverse, pred); | 278 cvox.DomUtil.directedFindDeepestNode(this.activeNode, reverse, pred); |
| 280 if (child != this.activeNode) { | 279 if (child != this.activeNode) { |
| 281 this.activeNode = child; | 280 this.activeNode = child; |
| 282 return this.activeNode; | 281 return this.activeNode; |
| 283 } | 282 } |
| 284 } | 283 } |
| 285 var prev = cvox.DomUtil.directedFindNextNode( | 284 var prev = cvox.DomUtil.directedFindNextNode( |
| 286 this.activeNode, this.activeMath, reverse, pred, true, true); | 285 this.activeNode, this.activeMath, reverse, pred, true, true); |
| 287 if (prev) { | 286 if (prev) { |
| 288 this.activeNode = prev; | 287 this.activeNode = prev; |
| 289 } | 288 } |
| 290 } | 289 } |
| 291 return this.activeNode; | 290 return this.activeNode; |
| 292 }; | 291 }; |
| 293 | 292 |
| 294 | 293 |
| 295 /** | 294 /** |
| 296 * left or right in the math expression. | 295 * left or right in the math expression. |
| 297 * Navigation is bounded by the presence of a sibling. | 296 * Navigation is bounded by the presence of a sibling. |
| 298 * @param {boolean} r True to move left; false to move right. | 297 * @param {boolean} r True to move left; false to move right. |
| 299 * @return {Node} The result. | 298 * @return {Node} The result. |
| 300 */ | 299 */ |
| 301 cvox.TraverseMath.prototype.nextSibling = function(r) { | 300 cvox.TraverseMath.prototype.nextSibling = function(r) { |
| 302 if (!this.activeNode || !this.activeMath) { | 301 if (!this.activeNode || !this.activeMath) { |
| 303 return null; | 302 return null; |
| 304 } | 303 } |
| 305 var node = this.activeNode; | 304 var node = this.activeNode; |
| 306 node = r ? node.previousSibling : node.nextSibling; | 305 node = r ? node.previousSibling : node.nextSibling; |
| 307 if (!node) { | 306 if (!node) { |
| 308 return null; | 307 return null; |
| 309 } | 308 } |
| 310 this.activeNode = node; | 309 this.activeNode = node; |
| 311 return this.activeNode; | 310 return this.activeNode; |
| 312 }; | 311 }; |
| 313 | 312 |
| 314 | 313 |
| 315 /** | 314 /** |
| 316 * Moves up or down the math expression. | 315 * Moves up or down the math expression. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 335 }; | 334 }; |
| 336 | 335 |
| 337 | 336 |
| 338 /** | 337 /** |
| 339 * Adds a list of domains and styles to the existing one. | 338 * Adds a list of domains and styles to the existing one. |
| 340 * @param {Array<string>} domains List of domain names. | 339 * @param {Array<string>} domains List of domain names. |
| 341 * @param {Array<string>} styles List of style names. | 340 * @param {Array<string>} styles List of style names. |
| 342 */ | 341 */ |
| 343 cvox.TraverseMath.prototype.addDomainsAndStyles = function(domains, styles) { | 342 cvox.TraverseMath.prototype.addDomainsAndStyles = function(domains, styles) { |
| 344 this.allDomains.push.apply( | 343 this.allDomains.push.apply( |
| 345 this.allDomains, | 344 this.allDomains, domains.filter(goog.bind(function(x) { |
| 346 domains.filter( | 345 return this.allDomains.indexOf(x) < 0; |
| 347 goog.bind(function(x) {return this.allDomains.indexOf(x) < 0;}, | 346 }, this))); |
| 348 this))); | |
| 349 this.allStyles.push.apply( | 347 this.allStyles.push.apply( |
| 350 this.allStyles, | 348 this.allStyles, styles.filter(goog.bind(function(x) { |
| 351 styles.filter( | 349 return this.allStyles.indexOf(x) < 0; |
| 352 goog.bind(function(x) {return this.allStyles.indexOf(x) < 0;}, | 350 }, this))); |
| 353 this))); | |
| 354 }; | 351 }; |
| 355 | 352 |
| 356 | 353 |
| 357 /** | 354 /** |
| 358 * Gets a list of domains and styles from the symbol and function mappings. | 355 * Gets a list of domains and styles from the symbol and function mappings. |
| 359 * Depending on the platform they either live in the background page or | 356 * Depending on the platform they either live in the background page or |
| 360 * in the android math map. | 357 * in the android math map. |
| 361 */ | 358 */ |
| 362 cvox.TraverseMath.prototype.initDomainsAndStyles = function() { | 359 cvox.TraverseMath.prototype.initDomainsAndStyles = function() { |
| 363 if (cvox.ChromeVox.host['mathMap']) { | 360 if (cvox.ChromeVox.host['mathMap']) { |
| 364 this.addDomainsAndStyles( | 361 this.addDomainsAndStyles( |
| 365 cvox.ChromeVox.host['mathMap'].allDomains, | 362 cvox.ChromeVox.host['mathMap'].allDomains, |
| 366 cvox.ChromeVox.host['mathMap'].allStyles); | 363 cvox.ChromeVox.host['mathMap'].allStyles); |
| 367 } else { | 364 } else { |
| 368 cvox.ChromeVox.host.sendToBackgroundPage( | 365 cvox.ChromeVox.host.sendToBackgroundPage( |
| 369 {'target': 'Math', | 366 {'target': 'Math', 'action': 'getDomains'}); |
| 370 'action': 'getDomains'}); | 367 } |
| 371 } | |
| 372 }; | 368 }; |
| 373 | 369 |
| 374 | 370 |
| 375 /** | 371 /** |
| 376 * Sets the domain for the TraverseMath object to the next one in the list | 372 * Sets the domain for the TraverseMath object to the next one in the list |
| 377 * restarting from the first, if necessary. | 373 * restarting from the first, if necessary. |
| 378 * @return {string} The name of the newly set domain. | 374 * @return {string} The name of the newly set domain. |
| 379 */ | 375 */ |
| 380 cvox.TraverseMath.prototype.cycleDomain = function() { | 376 cvox.TraverseMath.prototype.cycleDomain = function() { |
| 381 this.initDomainsAndStyles(); | 377 this.initDomainsAndStyles(); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 * @return {Node} The active node, if it exists. | 433 * @return {Node} The active node, if it exists. |
| 438 */ | 434 */ |
| 439 cvox.TraverseMath.prototype.getAttachedActiveNode = function() { | 435 cvox.TraverseMath.prototype.getAttachedActiveNode = function() { |
| 440 var node = this.activeNode; | 436 var node = this.activeNode; |
| 441 if (!node || node.nodeType != Node.ELEMENT_NODE) { | 437 if (!node || node.nodeType != Node.ELEMENT_NODE) { |
| 442 return null; | 438 return null; |
| 443 } | 439 } |
| 444 var id = node.getAttribute('spanID'); | 440 var id = node.getAttribute('spanID'); |
| 445 return document.getElementById(id); | 441 return document.getElementById(id); |
| 446 }; | 442 }; |
| OLD | NEW |