| 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'); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 | 30 |
| 31 /** | 31 /** |
| 32 * Messages considered as containers in braille. | 32 * Messages considered as containers in braille. |
| 33 * Containers are distinguished from roles by their appearance higher up in the | 33 * Containers are distinguished from roles by their appearance higher up in the |
| 34 * DOM tree of a selected node. | 34 * DOM tree of a selected node. |
| 35 * This list should be very short. | 35 * This list should be very short. |
| 36 * @type {!Array<string>} | 36 * @type {!Array<string>} |
| 37 */ | 37 */ |
| 38 cvox.BrailleUtil.CONTAINER = [ | 38 cvox.BrailleUtil.CONTAINER = [ |
| 39 'tag_h1_brl', | 39 'tag_h1_brl', 'tag_h2_brl', 'tag_h3_brl', 'tag_h4_brl', 'tag_h5_brl', |
| 40 'tag_h2_brl', | |
| 41 'tag_h3_brl', | |
| 42 'tag_h4_brl', | |
| 43 'tag_h5_brl', | |
| 44 'tag_h6_brl' | 40 'tag_h6_brl' |
| 45 ]; | 41 ]; |
| 46 | 42 |
| 47 | 43 |
| 48 /** | 44 /** |
| 49 * Maps a ChromeVox message id to a braille template. | 45 * Maps a ChromeVox message id to a braille template. |
| 50 * The template takes one-character specifiers: | 46 * The template takes one-character specifiers: |
| 51 * n: replaced with braille name. | 47 * n: replaced with braille name. |
| 52 * r: replaced with braille role. | 48 * r: replaced with braille role. |
| 53 * s: replaced with braille state. | 49 * s: replaced with braille state. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 } | 169 } |
| 174 var valueSpan = new cvox.ValueSpan(0 /* offset */); | 170 var valueSpan = new cvox.ValueSpan(0 /* offset */); |
| 175 if (cvox.DomUtil.isInputTypeText(node)) { | 171 if (cvox.DomUtil.isInputTypeText(node)) { |
| 176 var value = node.value; | 172 var value = node.value; |
| 177 if (node.type === 'password') { | 173 if (node.type === 'password') { |
| 178 value = value.replace(/./g, '*'); | 174 value = value.replace(/./g, '*'); |
| 179 } | 175 } |
| 180 var spannable = new Spannable(value, valueSpan); | 176 var spannable = new Spannable(value, valueSpan); |
| 181 if (node === document.activeElement && | 177 if (node === document.activeElement && |
| 182 cvox.DomUtil.doesInputSupportSelection(node)) { | 178 cvox.DomUtil.doesInputSupportSelection(node)) { |
| 183 var selectionStart = cvox.BrailleUtil.clamp_( | 179 var selectionStart = |
| 184 node.selectionStart, 0, spannable.length); | 180 cvox.BrailleUtil.clamp_(node.selectionStart, 0, spannable.length); |
| 185 var selectionEnd = cvox.BrailleUtil.clamp_( | 181 var selectionEnd = |
| 186 node.selectionEnd, 0, spannable.length); | 182 cvox.BrailleUtil.clamp_(node.selectionEnd, 0, spannable.length); |
| 187 spannable.setSpan(new cvox.ValueSelectionSpan(), | 183 spannable.setSpan( |
| 188 Math.min(selectionStart, selectionEnd), | 184 new cvox.ValueSelectionSpan(), Math.min(selectionStart, selectionEnd), |
| 189 Math.max(selectionStart, selectionEnd)); | 185 Math.max(selectionStart, selectionEnd)); |
| 190 } | 186 } |
| 191 return spannable; | 187 return spannable; |
| 192 } else if (node instanceof HTMLTextAreaElement) { | 188 } else if (node instanceof HTMLTextAreaElement) { |
| 193 var shadow = new cvox.EditableTextAreaShadow(); | 189 var shadow = new cvox.EditableTextAreaShadow(); |
| 194 shadow.update(node); | 190 shadow.update(node); |
| 195 var lineIndex = shadow.getLineIndex(node.selectionEnd); | 191 var lineIndex = shadow.getLineIndex(node.selectionEnd); |
| 196 var lineStart = shadow.getLineStart(lineIndex); | 192 var lineStart = shadow.getLineStart(lineIndex); |
| 197 var lineEnd = shadow.getLineEnd(lineIndex); | 193 var lineEnd = shadow.getLineEnd(lineIndex); |
| 198 var lineText = node.value.substring(lineStart, lineEnd); | 194 var lineText = node.value.substring(lineStart, lineEnd); |
| 199 valueSpan.offset = lineStart; | 195 valueSpan.offset = lineStart; |
| 200 var spannable = new Spannable(lineText, valueSpan); | 196 var spannable = new Spannable(lineText, valueSpan); |
| 201 if (node === document.activeElement) { | 197 if (node === document.activeElement) { |
| 202 var selectionStart = cvox.BrailleUtil.clamp_( | 198 var selectionStart = cvox.BrailleUtil.clamp_( |
| 203 node.selectionStart - lineStart, 0, spannable.length); | 199 node.selectionStart - lineStart, 0, spannable.length); |
| 204 var selectionEnd = cvox.BrailleUtil.clamp_( | 200 var selectionEnd = cvox.BrailleUtil.clamp_( |
| 205 node.selectionEnd - lineStart, 0, spannable.length); | 201 node.selectionEnd - lineStart, 0, spannable.length); |
| 206 spannable.setSpan(new cvox.ValueSelectionSpan(), | 202 spannable.setSpan( |
| 207 Math.min(selectionStart, selectionEnd), | 203 new cvox.ValueSelectionSpan(), Math.min(selectionStart, selectionEnd), |
| 208 Math.max(selectionStart, selectionEnd)); | 204 Math.max(selectionStart, selectionEnd)); |
| 209 } | 205 } |
| 210 return spannable; | 206 return spannable; |
| 211 } else { | 207 } else { |
| 212 return new Spannable(cvox.DomUtil.getValue(node), valueSpan); | 208 return new Spannable(cvox.DomUtil.getValue(node), valueSpan); |
| 213 } | 209 } |
| 214 }; | 210 }; |
| 215 | 211 |
| 216 | 212 |
| 217 /** | 213 /** |
| 218 * Gets the templated representation of braille. | 214 * Gets the templated representation of braille. |
| 219 * @param {Node} prev The previous node (during navigation). | 215 * @param {Node} prev The previous node (during navigation). |
| 220 * @param {Node} node The node. | 216 * @param {Node} node The node. |
| 221 * @param {{name:(undefined|string), | 217 * @param {{name:(undefined|string), |
| 222 * role:(undefined|string), | 218 * role:(undefined|string), |
| 223 * roleMsg:(undefined|string), | 219 * roleMsg:(undefined|string), |
| 224 * state:(undefined|string), | 220 * state:(undefined|string), |
| 225 * container:(undefined|string), | 221 * container:(undefined|string), |
| 226 * value:(undefined|Spannable)}|Object=} opt_override Override a | 222 * value:(undefined|Spannable)}|Object=} opt_override Override a |
| 227 * specific property for the given node. | 223 * specific property for the given node. |
| 228 * @return {!Spannable} The string representation. | 224 * @return {!Spannable} The string representation. |
| 229 */ | 225 */ |
| 230 cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { | 226 cvox.BrailleUtil.getTemplated = function(prev, node, opt_override) { |
| 231 opt_override = opt_override ? opt_override : {}; | 227 opt_override = opt_override ? opt_override : {}; |
| 232 var roleMsg = opt_override.roleMsg || | 228 var roleMsg = opt_override.roleMsg || |
| 233 (node ? cvox.DomUtil.getRoleMsg(node, cvox.VERBOSITY_VERBOSE) : ''); | 229 (node ? cvox.DomUtil.getRoleMsg(node, cvox.VERBOSITY_VERBOSE) : ''); |
| 234 var template = cvox.BrailleUtil.TEMPLATE[roleMsg] || | 230 var template = |
| 235 cvox.BrailleUtil.TEMPLATE['base']; | 231 cvox.BrailleUtil.TEMPLATE[roleMsg] || cvox.BrailleUtil.TEMPLATE['base']; |
| 236 var state = opt_override.state; | 232 var state = opt_override.state; |
| 237 if (!state) { | 233 if (!state) { |
| 238 if (node) { | 234 if (node) { |
| 239 state = cvox.BrailleUtil.expandStateMsgs_( | 235 state = cvox.BrailleUtil.expandStateMsgs_( |
| 240 cvox.DomUtil.getStateMsgs(node, true)); | 236 cvox.DomUtil.getStateMsgs(node, true)); |
| 241 } else { | 237 } else { |
| 242 state = ''; | 238 state = ''; |
| 243 } | 239 } |
| 244 } | 240 } |
| 245 var role = opt_override.role || ''; | 241 var role = opt_override.role || ''; |
| 246 if (!role && roleMsg) { | 242 if (!role && roleMsg) { |
| 247 role = Msgs.getMsg(roleMsg + '_brl') || | 243 role = Msgs.getMsg(roleMsg + '_brl') || Msgs.getMsg(roleMsg); |
| 248 Msgs.getMsg(roleMsg); | |
| 249 } | 244 } |
| 250 | 245 |
| 251 var templated = new Spannable(); | 246 var templated = new Spannable(); |
| 252 var mapChar = function(c) { | 247 var mapChar = function(c) { |
| 253 switch (c) { | 248 switch (c) { |
| 254 case 'n': | 249 case 'n': |
| 255 return opt_override.name || cvox.BrailleUtil.getName(node); | 250 return opt_override.name || cvox.BrailleUtil.getName(node); |
| 256 case 'r': | 251 case 'r': |
| 257 return role; | 252 return role; |
| 258 case 's': | 253 case 's': |
| 259 return state; | 254 return state; |
| 260 case 'c': | 255 case 'c': |
| 261 return opt_override.container || | 256 return opt_override.container || |
| 262 cvox.BrailleUtil.getContainer(prev, node); | 257 cvox.BrailleUtil.getContainer(prev, node); |
| 263 case 'v': | 258 case 'v': |
| 264 return opt_override.value || cvox.BrailleUtil.getValue(node); | 259 return opt_override.value || cvox.BrailleUtil.getValue(node); |
| 265 default: | 260 default: |
| 266 return c; | 261 return c; |
| 267 } | 262 } |
| 268 }; | 263 }; |
| 269 for (var i = 0; i < template.length; i++) { | 264 for (var i = 0; i < template.length; i++) { |
| 270 var component = mapChar(template[i]); | 265 var component = mapChar(template[i]); |
| 271 templated.append(component); | 266 templated.append(component); |
| 272 // Ignore the next whitespace separator if the current component is empty, | 267 // Ignore the next whitespace separator if the current component is empty, |
| 273 // unless the empty value has a selection, in which case the cursor | 268 // unless the empty value has a selection, in which case the cursor |
| 274 // should be placed on the empty space after the empty value. | 269 // should be placed on the empty space after the empty value. |
| 275 if (!component.toString() && template[i + 1] == ' ' && | 270 if (!component.toString() && template[i + 1] == ' ' && |
| 276 (!(component instanceof Spannable) || | 271 (!(component instanceof Spannable) || |
| 277 !/**@type {Spannable}*/(component).getSpanInstanceOf( | 272 !/**@type {Spannable}*/ (component).getSpanInstanceOf( |
| 278 cvox.ValueSelectionSpan))) { | 273 cvox.ValueSelectionSpan))) { |
| 279 i++; | 274 i++; |
| 280 } | 275 } |
| 281 } | 276 } |
| 282 return templated.trimRight(); | 277 return templated.trimRight(); |
| 283 }; | 278 }; |
| 284 | 279 |
| 285 | 280 |
| 286 /** | 281 /** |
| 287 * Creates a braille value from a string and, optionally, a selection range. | 282 * Creates a braille value from a string and, optionally, a selection range. |
| 288 * A {@code cvox.ValueSpan} will be attached, along with a | 283 * A {@code cvox.ValueSpan} will be attached, along with a |
| 289 * {@code cvox.ValueSelectionSpan} if applicable. | 284 * {@code cvox.ValueSelectionSpan} if applicable. |
| 290 * @param {string} text The text to display as the value. | 285 * @param {string} text The text to display as the value. |
| 291 * @param {number=} opt_selStart Selection start. | 286 * @param {number=} opt_selStart Selection start. |
| 292 * @param {number=} opt_selEnd Selection end if different from selection start. | 287 * @param {number=} opt_selEnd Selection end if different from selection start. |
| 293 * @param {number=} opt_textOffset Start offset of text. | 288 * @param {number=} opt_textOffset Start offset of text. |
| 294 * @return {!Spannable} The value spannable. | 289 * @return {!Spannable} The value spannable. |
| 295 */ | 290 */ |
| 296 cvox.BrailleUtil.createValue = function(text, opt_selStart, opt_selEnd, | 291 cvox.BrailleUtil.createValue = function( |
| 297 opt_textOffset) { | 292 text, opt_selStart, opt_selEnd, opt_textOffset) { |
| 298 var spannable = new Spannable(text, new cvox.ValueSpan(opt_textOffset || 0)); | 293 var spannable = new Spannable(text, new cvox.ValueSpan(opt_textOffset || 0)); |
| 299 if (goog.isDef(opt_selStart)) { | 294 if (goog.isDef(opt_selStart)) { |
| 300 opt_selEnd = goog.isDef(opt_selEnd) ? opt_selEnd : opt_selStart; | 295 opt_selEnd = goog.isDef(opt_selEnd) ? opt_selEnd : opt_selStart; |
| 301 // TODO(plundblad): This looses the distinction between the selection | 296 // TODO(plundblad): This looses the distinction between the selection |
| 302 // anchor (start) and focus (end). We should use that information to | 297 // anchor (start) and focus (end). We should use that information to |
| 303 // decide where to pan the braille display. | 298 // decide where to pan the braille display. |
| 304 if (opt_selStart > opt_selEnd) { | 299 if (opt_selStart > opt_selEnd) { |
| 305 var temp = opt_selStart; | 300 var temp = opt_selStart; |
| 306 opt_selStart = opt_selEnd; | 301 opt_selStart = opt_selEnd; |
| 307 opt_selEnd = temp; | 302 opt_selEnd = temp; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 321 * content that was active when the user issued the key command. | 316 * content that was active when the user issued the key command. |
| 322 * The annotations in the spannable are used to decide what | 317 * The annotations in the spannable are used to decide what |
| 323 * node to activate and what part of the node value (if any) to | 318 * node to activate and what part of the node value (if any) to |
| 324 * move the caret to. | 319 * move the caret to. |
| 325 * @param {number=} opt_displayPosition position of the display that the user | 320 * @param {number=} opt_displayPosition position of the display that the user |
| 326 * activated, relative to the start of braille. | 321 * activated, relative to the start of braille. |
| 327 */ | 322 */ |
| 328 cvox.BrailleUtil.click = function(braille, opt_displayPosition) { | 323 cvox.BrailleUtil.click = function(braille, opt_displayPosition) { |
| 329 var handled = false; | 324 var handled = false; |
| 330 var spans = braille.text.getSpans(opt_displayPosition || 0); | 325 var spans = braille.text.getSpans(opt_displayPosition || 0); |
| 331 var node = spans.filter(function(n) { return n instanceof Node; })[0]; | 326 var node = spans.filter(function(n) { |
| 327 return n instanceof Node; |
| 328 })[0]; |
| 332 if (node) { | 329 if (node) { |
| 333 if (goog.isDef(opt_displayPosition) && | 330 if (goog.isDef(opt_displayPosition) && |
| 334 (cvox.DomUtil.isInputTypeText(node) || | 331 (cvox.DomUtil.isInputTypeText(node) || |
| 335 node instanceof HTMLTextAreaElement)) { | 332 node instanceof HTMLTextAreaElement)) { |
| 336 var valueSpan = spans.filter( | 333 var valueSpan = spans.filter(function(s) { |
| 337 function(s) { | 334 return s instanceof cvox.ValueSpan; |
| 338 return s instanceof cvox.ValueSpan; | 335 })[0]; |
| 339 })[0]; | |
| 340 if (valueSpan) { | 336 if (valueSpan) { |
| 341 if (document.activeElement !== node) { | 337 if (document.activeElement !== node) { |
| 342 cvox.Focuser.setFocus(node); | 338 cvox.Focuser.setFocus(node); |
| 343 } | 339 } |
| 344 var cursorPosition = opt_displayPosition - | 340 var cursorPosition = opt_displayPosition - |
| 345 braille.text.getSpanStart(valueSpan) + | 341 braille.text.getSpanStart(valueSpan) + valueSpan.offset; |
| 346 valueSpan.offset; | |
| 347 cvox.ChromeVoxEventWatcher.setUpTextHandler(); | 342 cvox.ChromeVoxEventWatcher.setUpTextHandler(); |
| 348 node.selectionStart = node.selectionEnd = cursorPosition; | 343 node.selectionStart = node.selectionEnd = cursorPosition; |
| 349 cvox.ChromeVoxEventWatcher.handleTextChanged(true); | 344 cvox.ChromeVoxEventWatcher.handleTextChanged(true); |
| 350 handled = true; | 345 handled = true; |
| 351 } | 346 } |
| 352 } | 347 } |
| 353 } | 348 } |
| 354 if (!handled) { | 349 if (!handled) { |
| 355 cvox.DomUtil.clickElem( | 350 cvox.DomUtil.clickElem( |
| 356 node || cvox.ChromeVox.navigationManager.getCurrentNode(), | 351 node || cvox.ChromeVox.navigationManager.getCurrentNode(), false, false, |
| 357 false, false, false, true); | 352 false, true); |
| 358 } | 353 } |
| 359 }; | 354 }; |
| 360 | 355 |
| 361 | 356 |
| 362 /** | 357 /** |
| 363 * Clamps a number so it is within the given boundaries. | 358 * Clamps a number so it is within the given boundaries. |
| 364 * @param {number} number The number to clamp. | 359 * @param {number} number The number to clamp. |
| 365 * @param {number} min The minimum value to return. | 360 * @param {number} min The minimum value to return. |
| 366 * @param {number} max The maximum value to return. | 361 * @param {number} max The maximum value to return. |
| 367 * @return {number} {@code number} if it is within the bounds, or the nearest | 362 * @return {number} {@code number} if it is within the bounds, or the nearest |
| 368 * number within the bounds otherwise. | 363 * number within the bounds otherwise. |
| 369 * @private | 364 * @private |
| 370 */ | 365 */ |
| 371 cvox.BrailleUtil.clamp_ = function(number, min, max) { | 366 cvox.BrailleUtil.clamp_ = function(number, min, max) { |
| 372 return Math.min(Math.max(number, min), max); | 367 return Math.min(Math.max(number, min), max); |
| 373 }; | 368 }; |
| OLD | NEW |