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 |