| 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 |