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 /** | 5 /** |
6 * @fileoverview A utility class for building NavDescriptions from the dom. | 6 * @fileoverview A utility class for building NavDescriptions from the dom. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 goog.provide('cvox.DescriptionUtil'); | 10 goog.provide('cvox.DescriptionUtil'); |
(...skipping 26 matching lines...) Expand all Loading... |
37 /** | 37 /** |
38 * Get a control's complete description in the same format as if you | 38 * Get a control's complete description in the same format as if you |
39 * navigated to the node. | 39 * navigated to the node. |
40 * @param {Element} control A control. | 40 * @param {Element} control A control. |
41 * @param {Array<Node>=} opt_changedAncestors The changed ancestors that will | 41 * @param {Array<Node>=} opt_changedAncestors The changed ancestors that will |
42 * be used to determine what needs to be spoken. If this is not provided, the | 42 * be used to determine what needs to be spoken. If this is not provided, the |
43 * ancestors used to determine what needs to be spoken will just be the control | 43 * ancestors used to determine what needs to be spoken will just be the control |
44 * itself and its surrounding control if it has one. | 44 * itself and its surrounding control if it has one. |
45 * @return {cvox.NavDescription} The description of the control. | 45 * @return {cvox.NavDescription} The description of the control. |
46 */ | 46 */ |
47 cvox.DescriptionUtil.getControlDescription = | 47 cvox.DescriptionUtil.getControlDescription = function( |
48 function(control, opt_changedAncestors) { | 48 control, opt_changedAncestors) { |
49 var ancestors = [control]; | 49 var ancestors = [control]; |
50 if (opt_changedAncestors && (opt_changedAncestors.length > 0)) { | 50 if (opt_changedAncestors && (opt_changedAncestors.length > 0)) { |
51 ancestors = opt_changedAncestors; | 51 ancestors = opt_changedAncestors; |
52 } else { | 52 } else { |
53 var surroundingControl = cvox.DomUtil.getSurroundingControl(control); | 53 var surroundingControl = cvox.DomUtil.getSurroundingControl(control); |
54 if (surroundingControl) { | 54 if (surroundingControl) { |
55 ancestors = [surroundingControl, control]; | 55 ancestors = [surroundingControl, control]; |
56 } | 56 } |
57 } | 57 } |
58 | 58 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 var name = cvox.DomUtil.getName(node, false); | 138 var name = cvox.DomUtil.getName(node, false); |
139 if (name) { | 139 if (name) { |
140 roleText = name + ' ' + roleText; | 140 roleText = name + ' ' + roleText; |
141 } | 141 } |
142 } | 142 } |
143 if (roleText.length > 0) { | 143 if (roleText.length > 0) { |
144 // Since we prioritize reading of context in reading order, only populate | 144 // Since we prioritize reading of context in reading order, only populate |
145 // it for larger ancestry changes. | 145 // it for larger ancestry changes. |
146 if (context.length > 0 || | 146 if (context.length > 0 || |
147 (annotation.length > 0 && node.childElementCount > 1)) { | 147 (annotation.length > 0 && node.childElementCount > 1)) { |
148 context = roleText + ' ' + cvox.DomUtil.getState(node, false) + | 148 context = |
149 ' ' + context; | 149 roleText + ' ' + cvox.DomUtil.getState(node, false) + ' ' + context; |
150 } else { | 150 } else { |
151 if (annotation.length > 0) { | 151 if (annotation.length > 0) { |
152 annotation += | 152 annotation += |
153 ' ' + roleText + ' ' + cvox.DomUtil.getState(node, true); | 153 ' ' + roleText + ' ' + cvox.DomUtil.getState(node, true); |
154 } else { | 154 } else { |
155 annotation = roleText + ' ' + cvox.DomUtil.getState(node, true); | 155 annotation = roleText + ' ' + cvox.DomUtil.getState(node, true); |
156 } | 156 } |
157 } | 157 } |
158 } | 158 } |
159 var earcon = cvox.EarconUtil.getEarcon(node); | 159 var earcon = cvox.EarconUtil.getEarcon(node); |
(...skipping 18 matching lines...) Expand all Loading... |
178 * tree to the lowest, i.e. ending with the current leaf node. | 178 * tree to the lowest, i.e. ending with the current leaf node. |
179 * | 179 * |
180 * @param {Node} prevNode The previous node in navigation. | 180 * @param {Node} prevNode The previous node in navigation. |
181 * @param {Node} node The current node in navigation. | 181 * @param {Node} node The current node in navigation. |
182 * @param {boolean} recursive Whether or not the element's subtree should | 182 * @param {boolean} recursive Whether or not the element's subtree should |
183 * be used; true by default. | 183 * be used; true by default. |
184 * @param {number} verbosity The verbosity setting. | 184 * @param {number} verbosity The verbosity setting. |
185 * @return {!Array<cvox.NavDescription>} The description of the navigation | 185 * @return {!Array<cvox.NavDescription>} The description of the navigation |
186 * action. | 186 * action. |
187 */ | 187 */ |
188 cvox.DescriptionUtil.getDescriptionFromNavigation = | 188 cvox.DescriptionUtil.getDescriptionFromNavigation = function( |
189 function(prevNode, node, recursive, verbosity) { | 189 prevNode, node, recursive, verbosity) { |
190 if (!prevNode || !node) { | 190 if (!prevNode || !node) { |
191 return []; | 191 return []; |
192 } | 192 } |
193 | 193 |
194 // Specialized math descriptions. | 194 // Specialized math descriptions. |
195 if (cvox.DomUtil.isMath(node) && | 195 if (cvox.DomUtil.isMath(node) && !cvox.AriaUtil.isMath(node)) { |
196 !cvox.AriaUtil.isMath(node)) { | |
197 return cvox.DescriptionUtil.getMathDescription(node); | 196 return cvox.DescriptionUtil.getMathDescription(node); |
198 } | 197 } |
199 | 198 |
200 // Next, check to see if the current node is a collection type. | 199 // Next, check to see if the current node is a collection type. |
201 if (cvox.DescriptionUtil.COLLECTION_NODE_TYPE[node.tagName]) { | 200 if (cvox.DescriptionUtil.COLLECTION_NODE_TYPE[node.tagName]) { |
202 return cvox.DescriptionUtil.getCollectionDescription( | 201 return cvox.DescriptionUtil.getCollectionDescription( |
203 /** @type {!cvox.CursorSelection} */( | 202 /** @type {!cvox.CursorSelection} */ ( |
204 cvox.CursorSelection.fromNode(prevNode)), | 203 cvox.CursorSelection.fromNode(prevNode)), |
205 /** @type {!cvox.CursorSelection} */( | 204 /** @type {!cvox.CursorSelection} */ |
206 cvox.CursorSelection.fromNode(node))); | 205 (cvox.CursorSelection.fromNode(node))); |
207 } | 206 } |
208 | 207 |
209 // Now, generate a description for all other elements. | 208 // Now, generate a description for all other elements. |
210 var ancestors = cvox.DomUtil.getUniqueAncestors(prevNode, node, true); | 209 var ancestors = cvox.DomUtil.getUniqueAncestors(prevNode, node, true); |
211 var desc = cvox.DescriptionUtil.getDescriptionFromAncestors( | 210 var desc = cvox.DescriptionUtil.getDescriptionFromAncestors( |
212 ancestors, recursive, verbosity); | 211 ancestors, recursive, verbosity); |
213 var prevAncestors = cvox.DomUtil.getUniqueAncestors(node, prevNode); | 212 var prevAncestors = cvox.DomUtil.getUniqueAncestors(node, prevNode); |
214 if (cvox.DescriptionUtil.shouldDescribeExit_(prevAncestors)) { | 213 if (cvox.DescriptionUtil.shouldDescribeExit_(prevAncestors)) { |
215 var prevDesc = cvox.DescriptionUtil.getDescriptionFromAncestors( | 214 var prevDesc = cvox.DescriptionUtil.getDescriptionFromAncestors( |
216 prevAncestors, recursive, verbosity); | 215 prevAncestors, recursive, verbosity); |
217 if (prevDesc.context && !desc.context) { | 216 if (prevDesc.context && !desc.context) { |
218 desc.context = | 217 desc.context = Msgs.getMsg('exited_container', [prevDesc.context]); |
219 Msgs.getMsg('exited_container', [prevDesc.context]); | |
220 } | 218 } |
221 } | 219 } |
222 return [desc]; | 220 return [desc]; |
223 }; | 221 }; |
224 | 222 |
225 | 223 |
226 /** | 224 /** |
227 * Returns an array of NavDescriptions that includes everything that would be | 225 * Returns an array of NavDescriptions that includes everything that would be |
228 * spoken by an object walker while traversing from prevSel to sel. | 226 * spoken by an object walker while traversing from prevSel to sel. |
229 * It also includes any necessary annotations and context about the set of | 227 * It also includes any necessary annotations and context about the set of |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 var prevNode = prevSel.end.node; | 267 var prevNode = prevSel.end.node; |
270 var curSel = cvox.CursorSelection.fromNode(node); | 268 var curSel = cvox.CursorSelection.fromNode(node); |
271 | 269 |
272 if (!curSel) { | 270 if (!curSel) { |
273 return []; | 271 return []; |
274 } | 272 } |
275 | 273 |
276 while (cvox.DomUtil.isDescendantOfNode(node, sel.start.node)) { | 274 while (cvox.DomUtil.isDescendantOfNode(node, sel.start.node)) { |
277 var ancestors = cvox.DomUtil.getUniqueAncestors(prevNode, node); | 275 var ancestors = cvox.DomUtil.getUniqueAncestors(prevNode, node); |
278 // Specialized math descriptions. | 276 // Specialized math descriptions. |
279 if (cvox.DomUtil.isMath(node) && | 277 if (cvox.DomUtil.isMath(node) && !cvox.AriaUtil.isMath(node)) { |
280 !cvox.AriaUtil.isMath(node)) { | |
281 descriptions = | 278 descriptions = |
282 descriptions.concat(cvox.DescriptionUtil.getMathDescription(node)); | 279 descriptions.concat(cvox.DescriptionUtil.getMathDescription(node)); |
283 } else { | 280 } else { |
284 var description = cvox.DescriptionUtil.getDescriptionFromAncestors( | 281 var description = cvox.DescriptionUtil.getDescriptionFromAncestors( |
285 ancestors, true, cvox.ChromeVox.verbosity); | 282 ancestors, true, cvox.ChromeVox.verbosity); |
286 descriptions.push(description); | 283 descriptions.push(description); |
287 } | 284 } |
288 curSel = cvox.DescriptionUtil.subWalker_.next(curSel); | 285 curSel = cvox.DescriptionUtil.subWalker_.next(curSel); |
289 if (!curSel) { | 286 if (!curSel) { |
290 break; | 287 break; |
291 } | 288 } |
292 | 289 |
293 curSel = /** @type {!cvox.CursorSelection} */ (curSel); | 290 curSel = /** @type {!cvox.CursorSelection} */ (curSel); |
294 prevNode = node; | 291 prevNode = node; |
295 node = curSel.start.node; | 292 node = curSel.start.node; |
296 } | 293 } |
297 | 294 |
298 return descriptions; | 295 return descriptions; |
299 }; | 296 }; |
300 | 297 |
301 /** | 298 /** |
302 * Returns the full descriptions of the child nodes that would be gotten by an | 299 * Returns the full descriptions of the child nodes that would be gotten by an |
303 * object walker. | 300 * object walker. |
304 * @param {?Node} prevnode The previous element if there is one. | 301 * @param {?Node} prevnode The previous element if there is one. |
305 * @param {!Node} node The target element. | 302 * @param {!Node} node The target element. |
306 * @return {!Array<!cvox.NavDescription>} The descriptions. | 303 * @return {!Array<!cvox.NavDescription>} The descriptions. |
307 */ | 304 */ |
308 cvox.DescriptionUtil.getFullDescriptionsFromChildren = | 305 cvox.DescriptionUtil.getFullDescriptionsFromChildren = function( |
309 function(prevnode, node) { | 306 prevnode, node) { |
310 var descriptions = []; | 307 var descriptions = []; |
311 if (!node) { | 308 if (!node) { |
312 return descriptions; | 309 return descriptions; |
313 } | 310 } |
314 var desc; | 311 var desc; |
315 if (cvox.DomUtil.isLeafNode(node)) { | 312 if (cvox.DomUtil.isLeafNode(node)) { |
316 var ancestors; | 313 var ancestors; |
317 if (prevnode) { | 314 if (prevnode) { |
318 ancestors = cvox.DomUtil.getUniqueAncestors(prevnode, node); | 315 ancestors = cvox.DomUtil.getUniqueAncestors(prevnode, node); |
319 } else { | 316 } else { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 * Modify the descriptions to say that it is a collection. | 352 * Modify the descriptions to say that it is a collection. |
356 * @param {Array<cvox.NavDescription>} descriptions The descriptions. | 353 * @param {Array<cvox.NavDescription>} descriptions The descriptions. |
357 * @private | 354 * @private |
358 */ | 355 */ |
359 cvox.DescriptionUtil.insertCollectionDescription_ = function(descriptions) { | 356 cvox.DescriptionUtil.insertCollectionDescription_ = function(descriptions) { |
360 var annotations = cvox.DescriptionUtil.getAnnotations_(descriptions); | 357 var annotations = cvox.DescriptionUtil.getAnnotations_(descriptions); |
361 // If all of the items have the same annotation, describe it as a | 358 // If all of the items have the same annotation, describe it as a |
362 // <annotation> collection with <n> items. Currently only enabled | 359 // <annotation> collection with <n> items. Currently only enabled |
363 // for links, but support should be added for any other type that | 360 // for links, but support should be added for any other type that |
364 // makes sense. | 361 // makes sense. |
365 if (descriptions.length >= 3 && | 362 if (descriptions.length >= 3 && descriptions[0].context.length == 0 && |
366 descriptions[0].context.length == 0 && | 363 annotations.length == 1 && annotations[0].length > 0 && |
367 annotations.length == 1 && | |
368 annotations[0].length > 0 && | |
369 cvox.DescriptionUtil.isAnnotationCollection_(annotations[0])) { | 364 cvox.DescriptionUtil.isAnnotationCollection_(annotations[0])) { |
370 var commonAnnotation = annotations[0]; | 365 var commonAnnotation = annotations[0]; |
371 var firstContext = descriptions[0].context; | 366 var firstContext = descriptions[0].context; |
372 descriptions[0].context = ''; | 367 descriptions[0].context = ''; |
373 for (var i = 0; i < descriptions.length; i++) { | 368 for (var i = 0; i < descriptions.length; i++) { |
374 descriptions[i].annotation = ''; | 369 descriptions[i].annotation = ''; |
375 } | 370 } |
376 | 371 |
377 descriptions.splice(0, 0, new cvox.NavDescription({ | 372 descriptions.splice(0, 0, new cvox.NavDescription({ |
378 context: firstContext, | 373 context: firstContext, |
379 text: '', | 374 text: '', |
380 annotation: Msgs.getMsg( | 375 annotation: Msgs.getMsg( |
381 'collection', | 376 'collection', |
382 [commonAnnotation, | 377 [commonAnnotation, Msgs.getNumber(descriptions.length)]) |
383 Msgs.getNumber(descriptions.length)]) | |
384 })); | 378 })); |
385 } | 379 } |
386 }; | 380 }; |
387 | 381 |
388 | 382 |
389 /** | 383 /** |
390 * Pulls the annotations from a description array. | 384 * Pulls the annotations from a description array. |
391 * @param {Array<cvox.NavDescription>} descriptions The descriptions. | 385 * @param {Array<cvox.NavDescription>} descriptions The descriptions. |
392 * @return {Array<string>} The annotations. | 386 * @return {Array<string>} The annotations. |
393 * @private | 387 * @private |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 var ret = speechEngine.evaluateNode(traverse.activeNode); | 463 var ret = speechEngine.evaluateNode(traverse.activeNode); |
470 if (ret == []) { | 464 if (ret == []) { |
471 return [new cvox.NavDescription({'text': 'empty math'})]; | 465 return [new cvox.NavDescription({'text': 'empty math'})]; |
472 } | 466 } |
473 if (cvox.ChromeVox.verbosity == cvox.VERBOSITY_VERBOSE) { | 467 if (cvox.ChromeVox.verbosity == cvox.VERBOSITY_VERBOSE) { |
474 ret[ret.length - 1].annotation = 'math'; | 468 ret[ret.length - 1].annotation = 'math'; |
475 } | 469 } |
476 ret[0].pushEarcon(cvox.Earcon.MATH); | 470 ret[0].pushEarcon(cvox.Earcon.MATH); |
477 return ret; | 471 return ret; |
478 }; | 472 }; |
OLD | NEW |