Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Side by Side Diff: chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js

Issue 2487043002: Refine braille output (Closed)
Patch Set: Refine braille output Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698