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 general braille functionality. | 6 * @fileoverview A utility class for general braille functionality. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 goog.provide('cvox.BrailleUtil'); | 10 goog.provide('cvox.BrailleUtil'); |
11 goog.provide('cvox.BrailleUtil.ValueSelectionSpan'); | |
12 goog.provide('cvox.BrailleUtil.ValueSpan'); | |
13 | 11 |
14 goog.require('cvox.ChromeVox'); | 12 goog.require('cvox.ChromeVox'); |
15 goog.require('cvox.DomUtil'); | 13 goog.require('cvox.DomUtil'); |
| 14 goog.require('cvox.EditableTextAreaShadow'); |
16 goog.require('cvox.Focuser'); | 15 goog.require('cvox.Focuser'); |
17 goog.require('cvox.NavBraille'); | 16 goog.require('cvox.NavBraille'); |
18 goog.require('cvox.NodeStateUtil'); | 17 goog.require('cvox.NodeStateUtil'); |
19 goog.require('cvox.Spannable'); | 18 goog.require('cvox.Spannable'); |
| 19 goog.require('cvox.ValueSelectionSpan'); |
| 20 goog.require('cvox.ValueSpan'); |
20 | 21 |
21 | 22 |
22 /** | 23 /** |
23 * Trimmable whitespace character that appears between consecutive items in | 24 * Trimmable whitespace character that appears between consecutive items in |
24 * braille. | 25 * braille. |
25 * @const {string} | 26 * @const {string} |
26 */ | 27 */ |
27 cvox.BrailleUtil.ITEM_SEPARATOR = ' '; | 28 cvox.BrailleUtil.ITEM_SEPARATOR = ' '; |
28 | 29 |
29 | 30 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 'input_type_submit': 'n r s', | 75 'input_type_submit': 'n r s', |
75 'input_type_text': 'n: v r s', | 76 'input_type_text': 'n: v r s', |
76 'input_type_tel': 'n: v r s', | 77 'input_type_tel': 'n: v r s', |
77 'input_type_url': 'n: v r s', | 78 'input_type_url': 'n: v r s', |
78 'tag_button': 'n r s', | 79 'tag_button': 'n r s', |
79 'tag_textarea': 'n: v r s' | 80 'tag_textarea': 'n: v r s' |
80 }; | 81 }; |
81 | 82 |
82 | 83 |
83 /** | 84 /** |
84 * Attached to the value region of a braille spannable. | |
85 * @param {number} offset The offset of the span into the value. | |
86 * @constructor | |
87 */ | |
88 cvox.BrailleUtil.ValueSpan = function(offset) { | |
89 /** | |
90 * The offset of the span into the value. | |
91 * @type {number} | |
92 */ | |
93 this.offset = offset; | |
94 }; | |
95 | |
96 | |
97 /** | |
98 * Creates a value span from a json serializable object. | |
99 * @param {!Object} obj The json serializable object to convert. | |
100 * @return {!cvox.BrailleUtil.ValueSpan} The value span. | |
101 */ | |
102 cvox.BrailleUtil.ValueSpan.fromJson = function(obj) { | |
103 return new cvox.BrailleUtil.ValueSpan(obj.offset); | |
104 }; | |
105 | |
106 | |
107 /** | |
108 * Converts this object to a json serializable object. | |
109 * @return {!Object} The JSON representation. | |
110 */ | |
111 cvox.BrailleUtil.ValueSpan.prototype.toJson = function() { | |
112 return this; | |
113 }; | |
114 | |
115 | |
116 cvox.Spannable.registerSerializableSpan( | |
117 cvox.BrailleUtil.ValueSpan, | |
118 'cvox.BrailleUtil.ValueSpan', | |
119 cvox.BrailleUtil.ValueSpan.fromJson, | |
120 cvox.BrailleUtil.ValueSpan.prototype.toJson); | |
121 | |
122 | |
123 /** | |
124 * Attached to the selected text within a value. | |
125 * @constructor | |
126 */ | |
127 cvox.BrailleUtil.ValueSelectionSpan = function() { | |
128 }; | |
129 | |
130 | |
131 cvox.Spannable.registerStatelessSerializableSpan( | |
132 cvox.BrailleUtil.ValueSelectionSpan, | |
133 'cvox.BrailleUtil.ValueSelectionSpan'); | |
134 | |
135 | |
136 /** | |
137 * Gets the braille name for a node. | 85 * Gets the braille name for a node. |
138 * See DomUtil for a more precise definition of 'name'. | 86 * See DomUtil for a more precise definition of 'name'. |
139 * Additionally, whitespace is trimmed. | 87 * Additionally, whitespace is trimmed. |
140 * @param {Node} node The node. | 88 * @param {Node} node The node. |
141 * @return {string} The string representation. | 89 * @return {string} The string representation. |
142 */ | 90 */ |
143 cvox.BrailleUtil.getName = function(node) { | 91 cvox.BrailleUtil.getName = function(node) { |
144 if (!node) { | 92 if (!node) { |
145 return ''; | 93 return ''; |
146 } | 94 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 var msg = cvox.BrailleUtil.getRoleMsg(container); | 161 var msg = cvox.BrailleUtil.getRoleMsg(container); |
214 if (msg && cvox.BrailleUtil.CONTAINER.indexOf(msg) != -1) { | 162 if (msg && cvox.BrailleUtil.CONTAINER.indexOf(msg) != -1) { |
215 return cvox.ChromeVox.msgs.getMsg(msg); | 163 return cvox.ChromeVox.msgs.getMsg(msg); |
216 } | 164 } |
217 } | 165 } |
218 return ''; | 166 return ''; |
219 }; | 167 }; |
220 | 168 |
221 | 169 |
222 /** | 170 /** |
223 * Gets the braille value of a node. A cvox.BrailleUtil.ValueSpan will be | 171 * Gets the braille value of a node. A {@code cvox.ValueSpan} will be |
224 * attached, along with (possibly) a cvox.BrailleUtil.ValueSelectionSpan. | 172 * attached, along with (possibly) a {@code cvox.ValueSelectionSpan}. |
225 * @param {Node} node The node. | 173 * @param {Node} node The node. |
226 * @return {!cvox.Spannable} The value spannable. | 174 * @return {!cvox.Spannable} The value spannable. |
227 */ | 175 */ |
228 cvox.BrailleUtil.getValue = function(node) { | 176 cvox.BrailleUtil.getValue = function(node) { |
229 if (!node) { | 177 if (!node) { |
230 return new cvox.Spannable(); | 178 return new cvox.Spannable(); |
231 } | 179 } |
232 var valueSpan = new cvox.BrailleUtil.ValueSpan(0 /* offset */); | 180 var valueSpan = new cvox.ValueSpan(0 /* offset */); |
233 if (cvox.DomUtil.isInputTypeText(node)) { | 181 if (cvox.DomUtil.isInputTypeText(node)) { |
234 var value = node.value; | 182 var value = node.value; |
235 if (node.type === 'password') { | 183 if (node.type === 'password') { |
236 value = value.replace(/./g, '*'); | 184 value = value.replace(/./g, '*'); |
237 } | 185 } |
238 var spannable = new cvox.Spannable(value, valueSpan); | 186 var spannable = new cvox.Spannable(value, valueSpan); |
239 if (node === document.activeElement && | 187 if (node === document.activeElement && |
240 cvox.DomUtil.doesInputSupportSelection(node)) { | 188 cvox.DomUtil.doesInputSupportSelection(node)) { |
241 var selectionStart = cvox.BrailleUtil.clamp_( | 189 var selectionStart = cvox.BrailleUtil.clamp_( |
242 node.selectionStart, 0, spannable.getLength()); | 190 node.selectionStart, 0, spannable.getLength()); |
243 var selectionEnd = cvox.BrailleUtil.clamp_( | 191 var selectionEnd = cvox.BrailleUtil.clamp_( |
244 node.selectionEnd, 0, spannable.getLength()); | 192 node.selectionEnd, 0, spannable.getLength()); |
245 spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), | 193 spannable.setSpan(new cvox.ValueSelectionSpan(), |
246 Math.min(selectionStart, selectionEnd), | 194 Math.min(selectionStart, selectionEnd), |
247 Math.max(selectionStart, selectionEnd)); | 195 Math.max(selectionStart, selectionEnd)); |
248 } | 196 } |
249 return spannable; | 197 return spannable; |
250 } else if (node instanceof HTMLTextAreaElement) { | 198 } else if (node instanceof HTMLTextAreaElement) { |
251 var shadow = new cvox.EditableTextAreaShadow(); | 199 var shadow = new cvox.EditableTextAreaShadow(); |
252 shadow.update(node); | 200 shadow.update(node); |
253 var lineIndex = shadow.getLineIndex(node.selectionEnd); | 201 var lineIndex = shadow.getLineIndex(node.selectionEnd); |
254 var lineStart = shadow.getLineStart(lineIndex); | 202 var lineStart = shadow.getLineStart(lineIndex); |
255 var lineEnd = shadow.getLineEnd(lineIndex); | 203 var lineEnd = shadow.getLineEnd(lineIndex); |
256 var lineText = node.value.substring(lineStart, lineEnd); | 204 var lineText = node.value.substring(lineStart, lineEnd); |
257 valueSpan.offset = lineStart; | 205 valueSpan.offset = lineStart; |
258 var spannable = new cvox.Spannable(lineText, valueSpan); | 206 var spannable = new cvox.Spannable(lineText, valueSpan); |
259 if (node === document.activeElement) { | 207 if (node === document.activeElement) { |
260 var selectionStart = cvox.BrailleUtil.clamp_( | 208 var selectionStart = cvox.BrailleUtil.clamp_( |
261 node.selectionStart - lineStart, 0, spannable.getLength()); | 209 node.selectionStart - lineStart, 0, spannable.getLength()); |
262 var selectionEnd = cvox.BrailleUtil.clamp_( | 210 var selectionEnd = cvox.BrailleUtil.clamp_( |
263 node.selectionEnd - lineStart, 0, spannable.getLength()); | 211 node.selectionEnd - lineStart, 0, spannable.getLength()); |
264 spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), | 212 spannable.setSpan(new cvox.ValueSelectionSpan(), |
265 Math.min(selectionStart, selectionEnd), | 213 Math.min(selectionStart, selectionEnd), |
266 Math.max(selectionStart, selectionEnd)); | 214 Math.max(selectionStart, selectionEnd)); |
267 } | 215 } |
268 return spannable; | 216 return spannable; |
269 } else { | 217 } else { |
270 return new cvox.Spannable(cvox.DomUtil.getValue(node), valueSpan); | 218 return new cvox.Spannable(cvox.DomUtil.getValue(node), valueSpan); |
271 } | 219 } |
272 }; | 220 }; |
273 | 221 |
274 | 222 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 }; | 274 }; |
327 for (var i = 0; i < template.length; i++) { | 275 for (var i = 0; i < template.length; i++) { |
328 var component = mapChar(template[i]); | 276 var component = mapChar(template[i]); |
329 templated.append(component); | 277 templated.append(component); |
330 // Ignore the next whitespace separator if the current component is empty, | 278 // Ignore the next whitespace separator if the current component is empty, |
331 // unless the empty value has a selection, in which case the cursor | 279 // unless the empty value has a selection, in which case the cursor |
332 // should be placed on the empty space after the empty value. | 280 // should be placed on the empty space after the empty value. |
333 if (!component.toString() && template[i + 1] == ' ' && | 281 if (!component.toString() && template[i + 1] == ' ' && |
334 (!(component instanceof cvox.Spannable) || | 282 (!(component instanceof cvox.Spannable) || |
335 !/**@type {cvox.Spannable}*/(component).getSpanInstanceOf( | 283 !/**@type {cvox.Spannable}*/(component).getSpanInstanceOf( |
336 cvox.BrailleUtil.ValueSelectionSpan))) { | 284 cvox.ValueSelectionSpan))) { |
337 i++; | 285 i++; |
338 } | 286 } |
339 } | 287 } |
340 return templated.trimRight(); | 288 return templated.trimRight(); |
341 }; | 289 }; |
342 | 290 |
343 | 291 |
344 /** | 292 /** |
345 * Creates a braille value from a string and, optionally, a selection range. | 293 * Creates a braille value from a string and, optionally, a selection range. |
346 * A cvox.BrailleUtil.ValueSpan will be | 294 * A {@code cvox.ValueSpan} will be attached, along with a |
347 * attached, along with a cvox.BrailleUtil.ValueSelectionSpan if applicable. | 295 * {@code cvox.ValueSelectionSpan} if applicable. |
348 * @param {string} text The text to display as the value. | 296 * @param {string} text The text to display as the value. |
349 * @param {number=} opt_selStart Selection start. | 297 * @param {number=} opt_selStart Selection start. |
350 * @param {number=} opt_selEnd Selection end if different from selection start. | 298 * @param {number=} opt_selEnd Selection end if different from selection start. |
351 * @param {number=} opt_textOffset Start offset of text. | 299 * @param {number=} opt_textOffset Start offset of text. |
352 * @return {!cvox.Spannable} The value spannable. | 300 * @return {!cvox.Spannable} The value spannable. |
353 */ | 301 */ |
354 cvox.BrailleUtil.createValue = function(text, opt_selStart, opt_selEnd, | 302 cvox.BrailleUtil.createValue = function(text, opt_selStart, opt_selEnd, |
355 opt_textOffset) { | 303 opt_textOffset) { |
356 var spannable = new cvox.Spannable( | 304 var spannable = new cvox.Spannable( |
357 text, new cvox.BrailleUtil.ValueSpan(opt_textOffset || 0)); | 305 text, new cvox.ValueSpan(opt_textOffset || 0)); |
358 if (goog.isDef(opt_selStart)) { | 306 if (goog.isDef(opt_selStart)) { |
359 opt_selEnd = goog.isDef(opt_selEnd) ? opt_selEnd : opt_selStart; | 307 opt_selEnd = goog.isDef(opt_selEnd) ? opt_selEnd : opt_selStart; |
360 // TODO(plundblad): This looses the distinction between the selection | 308 // TODO(plundblad): This looses the distinction between the selection |
361 // anchor (start) and focus (end). We should use that information to | 309 // anchor (start) and focus (end). We should use that information to |
362 // decide where to pan the braille display. | 310 // decide where to pan the braille display. |
363 if (opt_selStart > opt_selEnd) { | 311 if (opt_selStart > opt_selEnd) { |
364 var temp = opt_selStart; | 312 var temp = opt_selStart; |
365 opt_selStart = opt_selEnd; | 313 opt_selStart = opt_selEnd; |
366 opt_selEnd = temp; | 314 opt_selEnd = temp; |
367 } | 315 } |
368 | 316 |
369 spannable.setSpan(new cvox.BrailleUtil.ValueSelectionSpan(), | 317 spannable.setSpan(new cvox.ValueSelectionSpan(), opt_selStart, opt_selEnd); |
370 opt_selStart, opt_selEnd); | |
371 } | 318 } |
372 return spannable; | 319 return spannable; |
373 }; | 320 }; |
374 | 321 |
375 | 322 |
376 /** | 323 /** |
377 * Activates a position in a nav braille. Moves the caret in text fields | 324 * Activates a position in a nav braille. Moves the caret in text fields |
378 * and simulates a mouse click on the node at the position. | 325 * and simulates a mouse click on the node at the position. |
379 * | 326 * |
380 * @param {!cvox.NavBraille} braille the nav braille representing the display | 327 * @param {!cvox.NavBraille} braille the nav braille representing the display |
381 * content that was active when the user issued the key command. | 328 * content that was active when the user issued the key command. |
382 * The annotations in the spannable are used to decide what | 329 * The annotations in the spannable are used to decide what |
383 * node to activate and what part of the node value (if any) to | 330 * node to activate and what part of the node value (if any) to |
384 * move the caret to. | 331 * move the caret to. |
385 * @param {number=} opt_displayPosition position of the display that the user | 332 * @param {number=} opt_displayPosition position of the display that the user |
386 * activated, relative to the start of braille. | 333 * activated, relative to the start of braille. |
387 */ | 334 */ |
388 cvox.BrailleUtil.click = function(braille, opt_displayPosition) { | 335 cvox.BrailleUtil.click = function(braille, opt_displayPosition) { |
389 var handled = false; | 336 var handled = false; |
390 var spans = braille.text.getSpans(opt_displayPosition || 0); | 337 var spans = braille.text.getSpans(opt_displayPosition || 0); |
391 var node = spans.filter(function(n) { return n instanceof Node; })[0]; | 338 var node = spans.filter(function(n) { return n instanceof Node; })[0]; |
392 if (node) { | 339 if (node) { |
393 if (goog.isDef(opt_displayPosition) && | 340 if (goog.isDef(opt_displayPosition) && |
394 (cvox.DomUtil.isInputTypeText(node) || | 341 (cvox.DomUtil.isInputTypeText(node) || |
395 node instanceof HTMLTextAreaElement)) { | 342 node instanceof HTMLTextAreaElement)) { |
396 var valueSpan = spans.filter( | 343 var valueSpan = spans.filter( |
397 function(s) { | 344 function(s) { |
398 return s instanceof cvox.BrailleUtil.ValueSpan; | 345 return s instanceof cvox.ValueSpan; |
399 })[0]; | 346 })[0]; |
400 if (valueSpan) { | 347 if (valueSpan) { |
401 if (document.activeElement !== node) { | 348 if (document.activeElement !== node) { |
402 cvox.Focuser.setFocus(node); | 349 cvox.Focuser.setFocus(node); |
403 } | 350 } |
404 var cursorPosition = opt_displayPosition - | 351 var cursorPosition = opt_displayPosition - |
405 braille.text.getSpanStart(valueSpan) + | 352 braille.text.getSpanStart(valueSpan) + |
406 valueSpan.offset; | 353 valueSpan.offset; |
407 cvox.ChromeVoxEventWatcher.setUpTextHandler(); | 354 cvox.ChromeVoxEventWatcher.setUpTextHandler(); |
408 node.selectionStart = node.selectionEnd = cursorPosition; | 355 node.selectionStart = node.selectionEnd = cursorPosition; |
(...skipping 15 matching lines...) Expand all Loading... |
424 * @param {number} number The number to clamp. | 371 * @param {number} number The number to clamp. |
425 * @param {number} min The minimum value to return. | 372 * @param {number} min The minimum value to return. |
426 * @param {number} max The maximum value to return. | 373 * @param {number} max The maximum value to return. |
427 * @return {number} {@code number} if it is within the bounds, or the nearest | 374 * @return {number} {@code number} if it is within the bounds, or the nearest |
428 * number within the bounds otherwise. | 375 * number within the bounds otherwise. |
429 * @private | 376 * @private |
430 */ | 377 */ |
431 cvox.BrailleUtil.clamp_ = function(number, min, max) { | 378 cvox.BrailleUtil.clamp_ = function(number, min, max) { |
432 return Math.min(Math.max(number, min), max); | 379 return Math.min(Math.max(number, min), max); |
433 }; | 380 }; |
OLD | NEW |