Chromium Code Reviews| 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 Provides output services for ChromeVox. | 6 * @fileoverview Provides output services for ChromeVox. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 goog.provide('Output'); | 9 goog.provide('Output'); |
| 10 goog.provide('Output.EventType'); | 10 goog.provide('Output.EventType'); |
| (...skipping 632 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 643 /** @override */ | 643 /** @override */ |
| 644 run: function() { | 644 run: function() { |
| 645 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon[this.earconId]); | 645 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon[this.earconId]); |
| 646 } | 646 } |
| 647 }; | 647 }; |
| 648 | 648 |
| 649 /** | 649 /** |
| 650 * Annotation for text with a selection inside it. | 650 * Annotation for text with a selection inside it. |
| 651 * @param {number} startIndex | 651 * @param {number} startIndex |
| 652 * @param {number} endIndex | 652 * @param {number} endIndex |
| 653 * @param {number=} opt_offset | |
| 654 * @constructor | 653 * @constructor |
| 655 */ | 654 */ |
| 656 Output.SelectionSpan = function(startIndex, endIndex, opt_offset) { | 655 Output.SelectionSpan = function(startIndex, endIndex) { |
| 657 // TODO(dtseng): Direction lost below; should preserve for braille panning. | 656 // TODO(dtseng): Direction lost below; should preserve for braille panning. |
| 658 this.startIndex = startIndex < endIndex ? startIndex : endIndex; | 657 this.startIndex = startIndex < endIndex ? startIndex : endIndex; |
| 659 this.endIndex = endIndex > startIndex ? endIndex : startIndex; | 658 this.endIndex = endIndex > startIndex ? endIndex : startIndex; |
| 660 this.offset = opt_offset || 0; | |
| 661 }; | 659 }; |
| 662 | 660 |
| 663 /** | 661 /** |
| 664 * Wrapper for automation nodes as annotations. Since the | 662 * Wrapper for automation nodes as annotations. Since the |
| 665 * {@code AutomationNode} constructor isn't exposed in the API, this class is | 663 * {@code AutomationNode} constructor isn't exposed in the API, this class is |
| 666 * used to allow instanceof checks on these annotations. | 664 * used to allow instanceof checks on these annotations. |
| 667 * @param {!AutomationNode} node | 665 * @param {!AutomationNode} node |
| 668 * @constructor | 666 * @constructor |
| 669 */ | 667 */ |
| 670 Output.NodeSpan = function(node) { | 668 Output.NodeSpan = function(node) { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 865 * @param {string} formatStr | 863 * @param {string} formatStr |
| 866 * @param {!AutomationNode=} opt_node An optional node to apply the | 864 * @param {!AutomationNode=} opt_node An optional node to apply the |
| 867 * formatting to. | 865 * formatting to. |
| 868 * @return {!Output} |this| for chaining | 866 * @return {!Output} |this| for chaining |
| 869 */ | 867 */ |
| 870 formatForBraille: function(formatStr, opt_node) { | 868 formatForBraille: function(formatStr, opt_node) { |
| 871 var node = opt_node || null; | 869 var node = opt_node || null; |
| 872 | 870 |
| 873 this.formatOptions_ = {speech: false, braille: true, auralStyle: false}; | 871 this.formatOptions_ = {speech: false, braille: true, auralStyle: false}; |
| 874 this.format_(node, formatStr, this.brailleBuffer_); | 872 this.format_(node, formatStr, this.brailleBuffer_); |
| 875 | |
| 876 return this; | 873 return this; |
| 877 }, | 874 }, |
| 878 | 875 |
| 879 /** | 876 /** |
| 880 * Triggers callback for a speech event. | 877 * Triggers callback for a speech event. |
| 881 * @param {function()} callback | 878 * @param {function()} callback |
| 882 * @return {Output} | 879 * @return {Output} |
| 883 */ | 880 */ |
| 884 onSpeechEnd: function(callback) { | 881 onSpeechEnd: function(callback) { |
| 885 this.speechEndCallback_ = function(opt_cleanupOnly) { | 882 this.speechEndCallback_ = function(opt_cleanupOnly) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 925 if (i == this.speechBuffer_.length - 1) | 922 if (i == this.speechBuffer_.length - 1) |
| 926 speechProps['endCallback'] = this.speechEndCallback_; | 923 speechProps['endCallback'] = this.speechEndCallback_; |
| 927 | 924 |
| 928 cvox.ChromeVox.tts.speak( | 925 cvox.ChromeVox.tts.speak( |
| 929 buff.toString(), queueMode, speechProps); | 926 buff.toString(), queueMode, speechProps); |
| 930 queueMode = cvox.QueueMode.QUEUE; | 927 queueMode = cvox.QueueMode.QUEUE; |
| 931 } | 928 } |
| 932 | 929 |
| 933 // Braille. | 930 // Braille. |
| 934 if (this.brailleBuffer_.length) { | 931 if (this.brailleBuffer_.length) { |
| 935 var buff = this.createBrailleOutput_(); | 932 var buff = this.mergeBraille_(this.brailleBuffer_); |
| 936 var selSpan = | 933 var selSpan = |
| 937 buff.getSpanInstanceOf(Output.SelectionSpan); | 934 buff.getSpanInstanceOf(Output.SelectionSpan); |
| 938 var startIndex = -1, endIndex = -1; | 935 var startIndex = -1, endIndex = -1; |
| 939 if (selSpan) { | 936 if (selSpan) { |
| 940 var valueStart = buff.getSpanStart(selSpan); | 937 var valueStart = buff.getSpanStart(selSpan); |
| 941 var valueEnd = buff.getSpanEnd(selSpan); | 938 var valueEnd = buff.getSpanEnd(selSpan); |
| 942 startIndex = valueStart + selSpan.startIndex; | 939 startIndex = valueStart + selSpan.startIndex; |
| 943 endIndex = valueStart + selSpan.endIndex; | 940 endIndex = valueStart + selSpan.endIndex; |
| 944 buff.setSpan(new cvox.ValueSpan(selSpan.offset), valueStart, valueEnd); | 941 buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd); |
| 945 buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex); | 942 buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex); |
| 946 } | 943 } |
| 947 | 944 |
| 948 var output = new cvox.NavBraille({ | 945 var output = new cvox.NavBraille({ |
| 949 text: buff, | 946 text: buff, |
| 950 startIndex: startIndex, | 947 startIndex: startIndex, |
| 951 endIndex: endIndex | 948 endIndex: endIndex |
| 952 }); | 949 }); |
| 953 | 950 |
| 954 cvox.ChromeVox.braille.write(output); | 951 cvox.ChromeVox.braille.write(output); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1031 // Obtain the operator token. | 1028 // Obtain the operator token. |
| 1032 token = tree.value; | 1029 token = tree.value; |
| 1033 | 1030 |
| 1034 // Set suffix options. | 1031 // Set suffix options. |
| 1035 var options = {}; | 1032 var options = {}; |
| 1036 options.annotation = []; | 1033 options.annotation = []; |
| 1037 options.isUnique = token[token.length - 1] == '='; | 1034 options.isUnique = token[token.length - 1] == '='; |
| 1038 if (options.isUnique) | 1035 if (options.isUnique) |
| 1039 token = token.substring(0, token.length - 1); | 1036 token = token.substring(0, token.length - 1); |
| 1040 | 1037 |
| 1041 // Annotate braille output with the corresponding automation nodes | |
| 1042 // to support acting on nodes based on location in the output. | |
| 1043 if (node && this.formatOptions_.braille) | |
| 1044 options.annotation.push(new Output.NodeSpan(node)); | |
| 1045 | |
| 1046 // Process token based on prefix. | 1038 // Process token based on prefix. |
| 1047 var prefix = token[0]; | 1039 var prefix = token[0]; |
| 1048 token = token.slice(1); | 1040 token = token.slice(1); |
| 1049 | 1041 |
| 1050 // All possible tokens based on prefix. | 1042 // All possible tokens based on prefix. |
| 1051 if (prefix == '$') { | 1043 if (prefix == '$') { |
| 1052 if (token == 'value') { | 1044 if (token == 'value') { |
| 1053 var text = node.value; | 1045 var text = node.value; |
| 1054 if (!node.state.editable && node.name == text) | 1046 if (!node.state.editable && node.name == text) |
| 1055 return; | 1047 return; |
| 1056 | 1048 |
| 1057 var selectedText = ''; | 1049 var selectedText = ''; |
| 1058 if (text !== undefined) { | 1050 if (text !== undefined) { |
| 1059 if (node.textSelStart !== undefined) { | 1051 if (node.textSelStart !== undefined) { |
| 1060 options.annotation.push(new Output.SelectionSpan( | 1052 options.annotation.push(new Output.SelectionSpan( |
| 1061 node.textSelStart, | 1053 node.textSelStart, |
| 1062 node.textSelEnd)); | 1054 node.textSelEnd)); |
| 1063 | 1055 |
| 1064 selectedText = | 1056 selectedText = |
| 1065 node.value.substring(node.textSelStart, node.textSelEnd); | 1057 node.value.substring(node.textSelStart, node.textSelEnd); |
| 1066 } | 1058 } |
| 1067 } | 1059 } |
| 1068 options.annotation.push(token); | 1060 options.annotation.push(token); |
| 1069 if (selectedText) { | 1061 if (selectedText) { |
| 1070 this.append_(buff, selectedText, options); | 1062 this.append_(buff, selectedText, options); |
| 1071 this.append_(buff, Msgs.getMsg('selected'), options); | 1063 this.append_(buff, Msgs.getMsg('selected')); |
| 1072 } else { | 1064 } else { |
| 1073 this.append_(buff, text, options); | 1065 this.append_(buff, text, options); |
| 1074 } | 1066 } |
| 1075 } else if (token == 'name') { | 1067 } else if (token == 'name') { |
| 1076 options.annotation.push(token); | 1068 options.annotation.push(token); |
| 1077 var earcon = node ? this.findEarcon_(node, opt_prevNode) : null; | 1069 var earcon = node ? this.findEarcon_(node, opt_prevNode) : null; |
| 1078 if (earcon) | 1070 if (earcon) |
| 1079 options.annotation.push(earcon); | 1071 options.annotation.push(earcon); |
| 1080 this.append_(buff, node.name, options); | 1072 this.append_(buff, node.name, options); |
| 1081 } else if (token == 'urlFilename') { | 1073 } else if (token == 'urlFilename') { |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1491 if (enteredRoleSet[formatPrevNode.role] || | 1483 if (enteredRoleSet[formatPrevNode.role] || |
| 1492 node.role == formatPrevNode.role || | 1484 node.role == formatPrevNode.role || |
| 1493 localStorage['useVerboseMode'] == 'false') | 1485 localStorage['useVerboseMode'] == 'false') |
| 1494 continue; | 1486 continue; |
| 1495 | 1487 |
| 1496 var roleBlock = getMergedRoleBlock(formatPrevNode.role); | 1488 var roleBlock = getMergedRoleBlock(formatPrevNode.role); |
| 1497 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true') | 1489 if (roleBlock.leave && localStorage['useVerboseMode'] == 'true') |
| 1498 this.format_(formatPrevNode, roleBlock.leave, buff, prevNode); | 1490 this.format_(formatPrevNode, roleBlock.leave, buff, prevNode); |
| 1499 } | 1491 } |
| 1500 | 1492 |
| 1501 var enterOutputs = []; | 1493 // Customize for braille node annotations. |
| 1494 var originalBuff = buff; | |
| 1502 var enterRole = {}; | 1495 var enterRole = {}; |
| 1503 for (var j = uniqueAncestors.length - 1, formatNode; | 1496 for (var j = uniqueAncestors.length - 1, formatNode; |
| 1504 (formatNode = uniqueAncestors[j]); | 1497 (formatNode = uniqueAncestors[j]); |
| 1505 j--) { | 1498 j--) { |
| 1506 var roleBlock = getMergedRoleBlock(formatNode.role); | 1499 var roleBlock = getMergedRoleBlock(formatNode.role); |
| 1507 if (roleBlock.enter) { | 1500 if (roleBlock.enter) { |
| 1508 if (enterRole[formatNode.role]) | 1501 if (enterRole[formatNode.role]) |
| 1509 continue; | 1502 continue; |
| 1503 | |
| 1504 if (this.formatOptions_.braille) | |
| 1505 buff = []; | |
| 1506 | |
| 1510 enterRole[formatNode.role] = true; | 1507 enterRole[formatNode.role] = true; |
| 1511 this.format_(formatNode, roleBlock.enter, buff, prevNode); | 1508 this.format_(formatNode, roleBlock.enter, buff, prevNode); |
| 1509 | |
| 1510 if (this.formatOptions_.braille && buff.length) { | |
| 1511 var nodeSpan = this.mergeBraille_(buff); | |
| 1512 nodeSpan.setSpan(new Output.NodeSpan(formatNode), 0, nodeSpan.length); | |
| 1513 originalBuff.push(nodeSpan); | |
| 1514 } | |
| 1512 } | 1515 } |
| 1513 } | 1516 } |
| 1514 }, | 1517 }, |
| 1515 | 1518 |
| 1516 /** | 1519 /** |
| 1517 * @param {!AutomationNode} node | 1520 * @param {!AutomationNode} node |
| 1518 * @param {!AutomationNode} prevNode | 1521 * @param {!AutomationNode} prevNode |
| 1519 * @param {EventType|Output.EventType} type | 1522 * @param {EventType|Output.EventType} type |
| 1520 * @param {!Array<Spannable>} buff | 1523 * @param {!Array<Spannable>} buff |
| 1521 * @private | 1524 * @private |
| 1522 */ | 1525 */ |
| 1523 node_: function(node, prevNode, type, buff) { | 1526 node_: function(node, prevNode, type, buff) { |
| 1527 var originalBuff = buff; | |
| 1528 | |
| 1529 if (this.formatOptions_.braille) | |
| 1530 buff = []; | |
| 1531 | |
| 1524 // Navigate is the default event. | 1532 // Navigate is the default event. |
| 1525 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; | 1533 var eventBlock = Output.RULES[type] || Output.RULES['navigate']; |
| 1526 var roleBlock = eventBlock[node.role] || {}; | 1534 var roleBlock = eventBlock[node.role] || {}; |
| 1527 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits; | 1535 var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits; |
| 1528 var parentRoleBlock = eventBlock[parentRole || ''] || {}; | 1536 var parentRoleBlock = eventBlock[parentRole || ''] || {}; |
| 1529 var speakFormat = roleBlock.speak || | 1537 var speakFormat = roleBlock.speak || |
| 1530 parentRoleBlock.speak || | 1538 parentRoleBlock.speak || |
| 1531 eventBlock['default'].speak; | 1539 eventBlock['default'].speak; |
| 1532 | 1540 |
| 1533 this.format_(node, speakFormat, buff, prevNode); | 1541 this.format_(node, speakFormat, buff, prevNode); |
| 1542 | |
| 1543 // Restore braille and add an annotation for this node. | |
| 1544 if (this.formatOptions_.braille) { | |
| 1545 var nodeSpan = this.mergeBraille_(buff); | |
| 1546 nodeSpan.setSpan(new Output.NodeSpan(node), 0, nodeSpan.length); | |
| 1547 originalBuff.push(nodeSpan); | |
| 1548 } | |
| 1534 }, | 1549 }, |
| 1535 | 1550 |
| 1536 /** | 1551 /** |
| 1537 * @param {!cursors.Range} range | 1552 * @param {!cursors.Range} range |
| 1538 * @param {cursors.Range} prevRange | 1553 * @param {cursors.Range} prevRange |
| 1539 * @param {EventType|Output.EventType} type | 1554 * @param {EventType|Output.EventType} type |
| 1540 * @param {!Array<Spannable>} buff | 1555 * @param {!Array<Spannable>} buff |
| 1541 * @private | 1556 * @private |
| 1542 */ | 1557 */ |
| 1543 subNode_: function(range, prevRange, type, buff) { | 1558 subNode_: function(range, prevRange, type, buff) { |
| 1544 if (!prevRange) | 1559 if (!prevRange) |
| 1545 prevRange = range; | 1560 prevRange = range; |
| 1546 var dir = cursors.Range.getDirection(prevRange, range); | 1561 var dir = cursors.Range.getDirection(prevRange, range); |
| 1547 var node = range.start.node; | 1562 var node = range.start.node; |
| 1548 var prevNode = prevRange.getBound(dir).node; | 1563 var prevNode = prevRange.getBound(dir).node; |
| 1549 if (!node || !prevNode) | 1564 if (!node || !prevNode) |
| 1550 return; | 1565 return; |
| 1551 | 1566 |
| 1552 var options = {annotation: ['name'], isUnique: true}; | 1567 var options = {annotation: ['name'], isUnique: true}; |
| 1553 var startIndex = range.start.index; | 1568 var startIndex = range.start.index; |
| 1554 var endIndex = range.end.index; | 1569 var endIndex = range.end.index; |
| 1555 if (this.formatOptions_.braille) { | 1570 if (this.formatOptions_.braille) { |
| 1556 options.annotation.push(new Output.NodeSpan(node)); | 1571 options.annotation.push(new Output.NodeSpan(node)); |
| 1557 var selStart = node.textSelStart; | 1572 var selStart = node.textSelStart; |
| 1558 var selEnd = node.textSelEnd; | 1573 var selEnd = node.textSelEnd; |
| 1574 | |
| 1559 if (selStart !== undefined && | 1575 if (selStart !== undefined && |
| 1560 (selEnd >= startIndex && selStart <= endIndex)) { | 1576 selEnd >= startIndex && selStart <= endIndex) { |
| 1577 // Editable text selection. | |
| 1578 // Note that there are two sets of indicies here. | |
|
dmazzoni
2016/11/10 17:17:22
nit: indicies -> indices (throughout)
David Tseng
2016/11/10 23:17:04
Done.
| |
| 1579 | |
| 1580 // |startIndex| and |endIndex| are indicies set by the caller | |
| 1581 // and are assumed to be inside of the range. In braille, we | |
| 1582 // only ever expect to get ranges surrounding a line as | |
| 1583 // anything smaller doesn't make sense. | |
| 1584 | |
| 1585 // The second set of indicies is set by the browser and | |
|
dmazzoni
2016/11/10 17:17:22
Nit: clarify that the second set of indices you're
David Tseng
2016/11/10 23:17:04
Done.
| |
| 1586 // reflects the editable selection. Since both sets of | |
| 1587 // indicies are absolute indicies into the text content, we | |
| 1588 // can safely take the difference between the selection | |
| 1589 // indicies and the start index of the range to arrive at the | |
| 1590 // relative index for the line output. See editing_test.js for | |
| 1591 // examples. | |
| 1561 options.annotation.push(new Output.SelectionSpan( | 1592 options.annotation.push(new Output.SelectionSpan( |
| 1562 selStart - startIndex, | 1593 selStart - startIndex, selEnd - startIndex)); |
| 1563 selEnd - startIndex, | 1594 } else { |
| 1564 startIndex)); | 1595 // Non-editable text selection. |
| 1596 options.annotation.push(new Output.SelectionSpan(startIndex, endIndex)); | |
| 1565 } | 1597 } |
| 1566 } | 1598 } |
| 1567 | 1599 |
| 1568 if (this.outputContextFirst_) | 1600 if (this.outputContextFirst_) |
| 1569 this.ancestry_(node, prevNode, type, buff); | 1601 this.ancestry_(node, prevNode, type, buff); |
| 1570 var earcon = this.findEarcon_(node, prevNode); | 1602 var earcon = this.findEarcon_(node, prevNode); |
| 1571 if (earcon) | 1603 if (earcon) |
| 1572 options.annotation.push(earcon); | 1604 options.annotation.push(earcon); |
| 1573 this.append_(buff, range.start.getText().substring(startIndex, endIndex), | 1605 var text = ''; |
| 1574 options); | 1606 text = range.start.getText().substring(startIndex, endIndex); |
| 1607 | |
| 1608 // In braille, we almost always want to show the entire contents and simply | |
| 1609 // place the cursor under the selection. | |
| 1610 if (this.formatOptions_.braille && !node.state.editable) | |
| 1611 text = range.start.getText(); | |
|
dmazzoni
2016/11/10 17:17:22
How about making this an if/else with a comment ex
David Tseng
2016/11/10 23:17:04
Done (if/else). The else case is both speech and n
| |
| 1612 | |
| 1613 this.append_(buff, text, options); | |
| 1614 | |
| 1575 if (!this.outputContextFirst_) | 1615 if (!this.outputContextFirst_) |
| 1576 this.ancestry_(node, prevNode, type, buff); | 1616 this.ancestry_(node, prevNode, type, buff); |
| 1577 | 1617 |
| 1578 var loc = | 1618 var loc = |
| 1579 range.start.node.boundsForRange(startIndex, endIndex); | 1619 range.start.node.boundsForRange(startIndex, endIndex); |
| 1580 if (loc) | 1620 if (loc) |
| 1581 this.locations_.push(loc); | 1621 this.locations_.push(loc); |
| 1582 }, | 1622 }, |
| 1583 | 1623 |
| 1584 /** | 1624 /** |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1666 index++; | 1706 index++; |
| 1667 } | 1707 } |
| 1668 | 1708 |
| 1669 if (currentNode != root) | 1709 if (currentNode != root) |
| 1670 throw 'Unbalanced parenthesis: ' + inputStr; | 1710 throw 'Unbalanced parenthesis: ' + inputStr; |
| 1671 | 1711 |
| 1672 return root; | 1712 return root; |
| 1673 }, | 1713 }, |
| 1674 | 1714 |
| 1675 /** | 1715 /** |
| 1676 * Converts the currently rendered braille buffers to a single spannable. | 1716 * Converts the braille |spans| buffer to a single spannable. |
| 1717 * @param {!Array<Spannable>} spans | |
| 1677 * @return {!Spannable} | 1718 * @return {!Spannable} |
| 1678 * @private | 1719 * @private |
| 1679 */ | 1720 */ |
| 1680 createBrailleOutput_: function() { | 1721 mergeBraille_: function(spans) { |
| 1681 var result = new Spannable(); | |
| 1682 var separator = ''; // Changes to space as appropriate. | 1722 var separator = ''; // Changes to space as appropriate. |
| 1683 this.brailleBuffer_.forEach(function(cur) { | 1723 var prevInline = {}; |
| 1684 // If this chunk is empty, don't add it since it won't result | 1724 var lookupInline = function(node) { |
| 1685 // in any output on the braille display, but node spans would | 1725 return prevInline[node]; |
| 1686 // start before the separator in that case, which is not desired. | 1726 }; |
| 1687 // The exception is if this chunk contains a selectionm, in which | 1727 var hashInlineSiblings = function(dict, node) { |
|
dmazzoni
2016/11/10 17:17:22
It seems you just want a set, right?
How about: a
David Tseng
2016/11/10 23:17:04
Good point; using WeakSet now.
| |
| 1688 // case it will result in a cursor which has to be preserved. | 1728 var inlineSibling = node; |
| 1689 // In this case, having separators, potentially both before and after | 1729 while (inlineSibling) { |
| 1690 // the empty string is correct. | 1730 dict[inlineSibling] = inlineSibling; |
| 1691 if (cur.length == 0 && !cur.getSpanInstanceOf(Output.SelectionSpan)) | 1731 if (inlineSibling.role == RoleType.inlineTextBox) |
| 1692 return; | 1732 dict[inlineSibling.parent] = inlineSibling.parent; |
|
dmazzoni
2016/11/10 17:17:22
Note that the parent of an inline text box might b
David Tseng
2016/11/10 23:17:04
Alright, I simplified this more and it appears dis
| |
| 1693 var spansToExtend = []; | 1733 inlineSibling = inlineSibling.nextOnLine; |
| 1694 var spansToRemove = []; | 1734 } |
| 1695 // Nodes that have node spans both on the character to the left | 1735 inlineSibling = node.previousOnLine; |
| 1696 // of the separator and to the right should also cover the separator. | 1736 while (inlineSibling) { |
| 1697 // We extend the left span to cover both the separator and what the | 1737 dict[inlineSibling] = inlineSibling; |
| 1698 // right span used to cover, removing the right span, mostly for | 1738 if (inlineSibling.role == RoleType.inlineTextBox) |
| 1699 // ease of writing tests and debug. | 1739 dict[inlineSibling.parent] = inlineSibling.parent; |
| 1700 // Note that getSpan(position) never returns zero length spans | 1740 inlineSibling = inlineSibling.previousOnLine; |
| 1701 // (because they don't cover any position). Still, we want to include | 1741 } |
| 1702 // these because they can be included (the selection span in an empty | 1742 }; |
| 1703 // text field is an example), which is why we write the below code | 1743 |
| 1704 // using getSpansInstanceOf and check the endpoints (isntead of doing | 1744 return spans.reduce(function(result, cur) { |
| 1705 // the opposite). | 1745 // Ignore empty spans except when they contain a selection. |
| 1706 result.getSpansInstanceOf(Output.NodeSpan).forEach(function(leftSpan) { | 1746 var hasSelection = cur.getSpanInstanceOf(Output.SelectionSpan); |
| 1707 if (result.getSpanEnd(leftSpan) < result.length) | 1747 if (cur.length == 0 && !hasSelection) |
| 1708 return; | 1748 return result; |
| 1709 var newEnd = result.length; | 1749 |
| 1710 cur.getSpansInstanceOf(Output.NodeSpan).forEach(function(rightSpan) { | 1750 // For empty selections, we just add the space separator to account for |
| 1711 if (cur.getSpanStart(rightSpan) == 0 && | 1751 // showing the braille cursor. |
| 1712 leftSpan.node === rightSpan.node) { | 1752 if (cur.length == 0 && hasSelection) { |
| 1713 newEnd = Math.max( | 1753 result.append(cur); |
| 1714 newEnd, | 1754 result.append(Output.SPACE); |
| 1715 result.length + separator.length + | 1755 separator = ''; |
| 1716 cur.getSpanEnd(rightSpan)); | 1756 return result; |
| 1717 spansToRemove.push(rightSpan); | 1757 } |
| 1718 } | 1758 |
| 1719 }); | 1759 // Grab all of the nodes associated with |cur|. |
| 1720 if (newEnd > result.length) | 1760 var curNodes = cur.getSpansInstanceOf(Output.NodeSpan).map(function(s) { |
| 1721 spansToExtend.push({span: leftSpan, end: newEnd}); | 1761 return s.node; |
| 1722 }); | 1762 }); |
| 1763 | |
| 1764 // Now, decide whether we should include separators between the previous | |
| 1765 // span and |cur|. | |
| 1766 // Never separate chunks without something already there at this point. | |
| 1767 if (result.length == 0 || | |
| 1768 curNodes.some(lookupInline)) | |
|
dmazzoni
2016/11/10 17:17:22
nit: fits on previous line
David Tseng
2016/11/10 23:17:04
Acknowledged.
| |
| 1769 separator = ''; | |
| 1770 else | |
| 1771 separator = Output.SPACE; | |
|
dmazzoni
2016/11/10 17:17:22
nit: indent
David Tseng
2016/11/10 23:17:04
Done.
| |
| 1772 | |
| 1723 result.append(separator); | 1773 result.append(separator); |
| 1724 result.append(cur); | 1774 result.append(cur); |
| 1725 spansToExtend.forEach(function(elem) { | 1775 |
| 1726 result.setSpan( | 1776 // Refresh |prevInline| for the next span. Any two spans who have |
| 1727 elem.span, | 1777 // associated nodes that fall on the same line and are themselves text |
| 1728 result.getSpanStart(elem.span), | 1778 // nodes should not cause a separator. |
| 1729 elem.end); | 1779 prevInline = curNodes.reduce(function(dict, node) { |
| 1730 }); | 1780 if (node.role == RoleType.inlineTextBox) |
| 1731 spansToRemove.forEach(result.removeSpan.bind(result)); | 1781 hashInlineSiblings(dict, node); |
|
dmazzoni
2016/11/10 17:17:22
Maybe hashInlineSiblings or whatever you end up ca
David Tseng
2016/11/10 23:17:04
Acknowledged.
| |
| 1732 separator = Output.SPACE; | 1782 |
| 1733 }); | 1783 if (node.role == RoleType.staticText) |
| 1734 return result; | 1784 hashInlineSiblings(dict, node.firstChild); |
| 1785 | |
| 1786 return dict; | |
| 1787 }, {}); | |
| 1788 | |
| 1789 return result; | |
| 1790 }, new Spannable()); | |
| 1735 }, | 1791 }, |
| 1736 | 1792 |
| 1737 /** | 1793 /** |
| 1738 * Find the earcon for a given node (including ancestry). | 1794 * Find the earcon for a given node (including ancestry). |
| 1739 * @param {!AutomationNode} node | 1795 * @param {!AutomationNode} node |
| 1740 * @param {!AutomationNode=} opt_prevNode | 1796 * @param {!AutomationNode=} opt_prevNode |
| 1741 * @return {Output.Action} | 1797 * @return {Output.Action} |
| 1742 */ | 1798 */ |
| 1743 findEarcon_: function(node, opt_prevNode) { | 1799 findEarcon_: function(node, opt_prevNode) { |
| 1744 if (node === opt_prevNode) | 1800 if (node === opt_prevNode) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1789 prev.append(cur); | 1845 prev.append(cur); |
| 1790 return prev; | 1846 return prev; |
| 1791 }, null); | 1847 }, null); |
| 1792 }, | 1848 }, |
| 1793 | 1849 |
| 1794 /** | 1850 /** |
| 1795 * Gets the output buffer for braille. | 1851 * Gets the output buffer for braille. |
| 1796 * @return {!Spannable} | 1852 * @return {!Spannable} |
| 1797 */ | 1853 */ |
| 1798 get brailleOutputForTest() { | 1854 get brailleOutputForTest() { |
| 1799 return this.createBrailleOutput_(); | 1855 return this.mergeBraille_(this.brailleBuffer_); |
| 1800 } | 1856 } |
| 1801 }; | 1857 }; |
| 1802 | 1858 |
| 1803 }); // goog.scope | 1859 }); // goog.scope |
| OLD | NEW |