OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 Processes events related to editing text and emits the | 6 * @fileoverview Processes events related to editing text and emits the |
7 * appropriate spoken and braille feedback. | 7 * appropriate spoken and braille feedback. |
8 */ | 8 */ |
9 | 9 |
10 goog.provide('editing.TextEditHandler'); | 10 goog.provide('editing.TextEditHandler'); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 * @extends {cvox.ChromeVoxEditableTextBase} | 107 * @extends {cvox.ChromeVoxEditableTextBase} |
108 */ | 108 */ |
109 function AutomationEditableText(node) { | 109 function AutomationEditableText(node) { |
110 if (!node.state.editable) | 110 if (!node.state.editable) |
111 throw Error('Node must have editable state set to true.'); | 111 throw Error('Node must have editable state set to true.'); |
112 var start = node.textSelStart; | 112 var start = node.textSelStart; |
113 var end = node.textSelEnd; | 113 var end = node.textSelEnd; |
114 cvox.ChromeVoxEditableTextBase.call( | 114 cvox.ChromeVoxEditableTextBase.call( |
115 this, node.value || '', Math.min(start, end), Math.max(start, end), | 115 this, node.value || '', Math.min(start, end), Math.max(start, end), |
116 node.state[StateType.PROTECTED] /**password*/, cvox.ChromeVox.tts); | 116 node.state[StateType.PROTECTED] /**password*/, cvox.ChromeVox.tts); |
117 /** @override */ | |
118 this.multiline = node.state[StateType.MULTILINE] || false; | |
119 /** @type {!AutomationNode} @private */ | 117 /** @type {!AutomationNode} @private */ |
120 this.node_ = node; | 118 this.node_ = node; |
121 /** @type {Array<number>} @private */ | |
122 this.lineBreaks_ = []; | |
123 } | 119 } |
124 | 120 |
125 AutomationEditableText.prototype = { | 121 AutomationEditableText.prototype = { |
126 __proto__: cvox.ChromeVoxEditableTextBase.prototype, | 122 __proto__: cvox.ChromeVoxEditableTextBase.prototype, |
127 | 123 |
128 /** | 124 /** |
129 * Called when the text field has been updated. | 125 * Called when the text field has been updated. |
130 */ | 126 */ |
131 onUpdate: function() { | 127 onUpdate: function() { |
132 var newValue = this.node_.value || ''; | 128 var newValue = this.node_.value || ''; |
133 | 129 |
134 if (this.value != newValue) | |
135 this.lineBreaks_ = []; | |
136 | |
137 var textChangeEvent = new cvox.TextChangeEvent( | 130 var textChangeEvent = new cvox.TextChangeEvent( |
138 newValue, this.node_.textSelStart || 0, this.node_.textSelEnd || 0, | 131 newValue, this.node_.textSelStart || 0, this.node_.textSelEnd || 0, |
139 true /* triggered by user */); | 132 true /* triggered by user */); |
140 this.changed(textChangeEvent); | 133 this.changed(textChangeEvent); |
141 this.outputBraille_(); | 134 this.outputBraille_(); |
142 }, | 135 }, |
143 | 136 |
144 /** @override */ | 137 /** @override */ |
145 getLineIndex: function(charIndex) { | 138 getLineIndex: function(charIndex) { |
146 if (!this.multiline) | 139 var breaks = this.node_.lineBreaks || []; |
| 140 if (!breaks.length) |
147 return 0; | 141 return 0; |
148 var breaks = this.node_.lineBreaks || []; | |
149 var index = 0; | 142 var index = 0; |
150 while (index < breaks.length && breaks[index] <= charIndex) | 143 while (index < breaks.length && breaks[index] <= charIndex) |
151 ++index; | 144 ++index; |
152 return index; | 145 return index; |
153 }, | 146 }, |
154 | 147 |
155 /** @override */ | 148 /** @override */ |
156 getLineStart: function(lineIndex) { | 149 getLineStart: function(lineIndex) { |
157 if (!this.multiline || lineIndex == 0) | 150 if (lineIndex == 0) |
158 return 0; | 151 return 0; |
159 var breaks = this.getLineBreaks_(); | 152 var breaks = this.getLineBreaks_(); |
| 153 if (breaks.length < 1) |
| 154 return 0; |
160 return breaks[lineIndex - 1] || this.node_.value.length; | 155 return breaks[lineIndex - 1] || this.node_.value.length; |
161 }, | 156 }, |
162 | 157 |
163 /** @override */ | 158 /** @override */ |
164 getLineEnd: function(lineIndex) { | 159 getLineEnd: function(lineIndex) { |
165 var breaks = this.getLineBreaks_(); | 160 var breaks = this.getLineBreaks_(); |
166 var value = this.node_.value; | 161 var value = this.node_.value; |
167 if (lineIndex >= breaks.length) | 162 if (lineIndex >= breaks.length) |
168 return value.length; | 163 return value.length; |
169 return breaks[lineIndex] - 1; | 164 return breaks[lineIndex] - 1; |
170 }, | 165 }, |
171 | 166 |
172 /** | 167 /** |
173 * @return {Array<number>} | 168 * @return {Array<number>} |
174 * @private | 169 * @private |
175 */ | 170 */ |
176 getLineBreaks_: function() { | 171 getLineBreaks_: function() { |
177 // node.lineBreaks is undefined when the multiline field has no line | 172 // node.lineBreaks is undefined when the multiline field has no line |
178 // breaks. | 173 // breaks. |
179 return this.node_.lineBreaks || []; | 174 return this.node_.lineBreaks || []; |
180 }, | 175 }, |
181 | 176 |
182 /** @private */ | 177 /** @private */ |
183 outputBraille_: function() { | 178 outputBraille_: function() { |
184 var isFirstLine = false; // First line in a multiline field. | 179 var isFirstLine = false; // First line in a multiline field. |
185 var output = new Output(); | 180 var output = new Output(); |
186 var range; | 181 var range; |
187 if (this.multiline) { | 182 if (this.getLineBreaks_().length) { |
188 var lineIndex = this.getLineIndex(this.start); | 183 var lineIndex = this.getLineIndex(this.start); |
189 if (lineIndex == 0) { | 184 if (lineIndex == 0) { |
190 isFirstLine = true; | 185 isFirstLine = true; |
191 output.formatForBraille('$name', this.node_); | 186 output.formatForBraille('$name', this.node_); |
192 } | 187 } |
193 range = new Range( | 188 range = new Range( |
194 new Cursor(this.node_, this.getLineStart(lineIndex)), | 189 new Cursor(this.node_, this.getLineStart(lineIndex)), |
195 new Cursor(this.node_, this.getLineEnd(lineIndex))); | 190 new Cursor(this.node_, this.getLineEnd(lineIndex))); |
196 } else { | 191 } else { |
197 range = Range.fromNode(this.node_); | 192 range = Range.fromNode(this.node_); |
(...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 * @return {boolean} | 761 * @return {boolean} |
767 */ | 762 */ |
768 isSameLineAndSelection: function(otherLine) { | 763 isSameLineAndSelection: function(otherLine) { |
769 return this.isSameLine(otherLine) && | 764 return this.isSameLine(otherLine) && |
770 this.startOffset == otherLine.startOffset && | 765 this.startOffset == otherLine.startOffset && |
771 this.endOffset == otherLine.endOffset; | 766 this.endOffset == otherLine.endOffset; |
772 } | 767 } |
773 }; | 768 }; |
774 | 769 |
775 }); | 770 }); |
OLD | NEW |