| 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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 this.node_.textSelEnd, | 132 this.node_.textSelEnd, |
| 133 true /* triggered by user */); | 133 true /* triggered by user */); |
| 134 this.changed(textChangeEvent); | 134 this.changed(textChangeEvent); |
| 135 this.outputBraille_(); | 135 this.outputBraille_(); |
| 136 }, | 136 }, |
| 137 | 137 |
| 138 /** @override */ | 138 /** @override */ |
| 139 getLineIndex: function(charIndex) { | 139 getLineIndex: function(charIndex) { |
| 140 if (!this.multiline) | 140 if (!this.multiline) |
| 141 return 0; | 141 return 0; |
| 142 var breaks = this.getLineBreaks_(); | 142 var breaks = this.node_.lineBreaks || []; |
| 143 | 143 var index = 0; |
| 144 var computedIndex = 0; | 144 while (index < breaks.length && breaks[index] <= charIndex) |
| 145 for (var index = 0; index < breaks.length; index++) { | 145 ++index; |
| 146 if (charIndex >= breaks[index] && | 146 return index; |
| 147 (index == (breaks.length - 1) || | |
| 148 charIndex < breaks[index + 1])) { | |
| 149 computedIndex = index + 1; | |
| 150 break; | |
| 151 } | |
| 152 } | |
| 153 return computedIndex; | |
| 154 }, | 147 }, |
| 155 | 148 |
| 156 /** @override */ | 149 /** @override */ |
| 157 getLineStart: function(lineIndex) { | 150 getLineStart: function(lineIndex) { |
| 158 if (!this.multiline || lineIndex == 0) | 151 if (!this.multiline || lineIndex == 0) |
| 159 return 0; | 152 return 0; |
| 160 var breaks = this.getLineBreaks_(); | 153 var breaks = this.getLineBreaks_(); |
| 161 return breaks[lineIndex - 1] || this.node_.value.length; | 154 return breaks[lineIndex - 1] || this.node_.value.length; |
| 162 }, | 155 }, |
| 163 | 156 |
| 164 /** @override */ | 157 /** @override */ |
| 165 getLineEnd: function(lineIndex) { | 158 getLineEnd: function(lineIndex) { |
| 166 var breaks = this.getLineBreaks_(); | 159 var breaks = this.getLineBreaks_(); |
| 167 var value = this.node_.value; | 160 var value = this.node_.value; |
| 168 if (lineIndex >= breaks.length) | 161 if (lineIndex >= breaks.length) |
| 169 return value.length; | 162 return value.length; |
| 170 return breaks[lineIndex] - 1; | 163 return breaks[lineIndex] - 1; |
| 171 }, | 164 }, |
| 172 | 165 |
| 173 /** | 166 /** |
| 174 * @return {Array<number>} | 167 * @return {Array<number>} |
| 175 * @private | 168 * @private |
| 176 */ | 169 */ |
| 177 getLineBreaks_: function() { | 170 getLineBreaks_: function() { |
| 178 if (this.lineBreaks_.length) | 171 // node.lineBreaks is undefined when the multiline field has no line |
| 179 return this.lineBreaks_; | 172 // breaks. |
| 180 | 173 return this.node_.lineBreaks || []; |
| 181 // |lineStartOffsets| is sometimes pretty wrong especially when | |
| 182 // there's multiple consecutive line breaks. | |
| 183 | |
| 184 // Use Blink's innerText which we plumb through as value. For | |
| 185 // soft line breaks, use line start offsets, but ensure it is | |
| 186 // likely to be a soft line wrap. | |
| 187 | |
| 188 var lineStartOffsets = {}; | |
| 189 this.node_.lineStartOffsets.forEach(function(offset) { | |
| 190 lineStartOffsets[offset] = true; | |
| 191 }); | |
| 192 var lineBreaks = []; | |
| 193 for (var i = 0; i < this.node_.value.length; i++) { | |
| 194 var prev = this.node_.value[i - 1]; | |
| 195 var next = this.node_.value[i + 1]; | |
| 196 var cur = this.node_.value[i]; | |
| 197 if (prev == '\n') { | |
| 198 // Hard line break. | |
| 199 lineBreaks.push(i); | |
| 200 } else if (lineStartOffsets[i]) { | |
| 201 // Soft line break. | |
| 202 if (prev != '\n' && next != '\n' && cur != '\n') | |
| 203 lineBreaks.push(i); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 this.lineBreaks_ = lineBreaks; | |
| 208 | |
| 209 return lineBreaks; | |
| 210 }, | 174 }, |
| 211 | 175 |
| 212 /** @private */ | 176 /** @private */ |
| 213 outputBraille_: function() { | 177 outputBraille_: function() { |
| 214 var isFirstLine = false; // First line in a multiline field. | 178 var isFirstLine = false; // First line in a multiline field. |
| 215 var output = new Output(); | 179 var output = new Output(); |
| 216 var range; | 180 var range; |
| 217 if (this.multiline) { | 181 if (this.multiline) { |
| 218 var lineIndex = this.getLineIndex(this.start); | 182 var lineIndex = this.getLineIndex(this.start); |
| 219 if (lineIndex == 0) { | 183 if (lineIndex == 0) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 248 testNode = testNode.parent; | 212 testNode = testNode.parent; |
| 249 } while (testNode); | 213 } while (testNode); |
| 250 | 214 |
| 251 if (rootFocusedEditable) | 215 if (rootFocusedEditable) |
| 252 return new TextFieldTextEditHandler(rootFocusedEditable); | 216 return new TextFieldTextEditHandler(rootFocusedEditable); |
| 253 | 217 |
| 254 return null; | 218 return null; |
| 255 }; | 219 }; |
| 256 | 220 |
| 257 }); | 221 }); |
| OLD | NEW |