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 Classes related to cursors that point to and select parts of | 6 * @fileoverview Classes related to cursors that point to and select parts of |
7 * the automation tree. | 7 * the automation tree. |
8 */ | 8 */ |
9 | 9 |
10 goog.provide('cursors.Cursor'); | 10 goog.provide('cursors.Cursor'); |
(...skipping 19 matching lines...) Expand all Loading... |
30 cursors.Unit = { | 30 cursors.Unit = { |
31 /** A single character within accessible name or value. */ | 31 /** A single character within accessible name or value. */ |
32 CHARACTER: 'character', | 32 CHARACTER: 'character', |
33 | 33 |
34 /** A range of characters (given by attributes on automation nodes). */ | 34 /** A range of characters (given by attributes on automation nodes). */ |
35 WORD: 'word', | 35 WORD: 'word', |
36 | 36 |
37 /** A leaf node. */ | 37 /** A leaf node. */ |
38 NODE: 'node', | 38 NODE: 'node', |
39 | 39 |
40 /** A leaf DOM-node. */ | 40 /** |
41 DOM_NODE: 'dom_node', | 41 * A node or in line textbox that immediately precedes or follows a visual |
42 | 42 * line break. |
43 /** Formed by a set of leaf nodes that are inline. */ | 43 */ |
44 LINE: 'line' | 44 LINE: 'line' |
45 }; | 45 }; |
46 | 46 |
47 /** | 47 /** |
48 * Represents the ways in which cursors can move given a cursor unit. | 48 * Represents the ways in which cursors can move given a cursor unit. |
49 * @enum {string} | 49 * @enum {string} |
50 */ | 50 */ |
51 cursors.Movement = { | 51 cursors.Movement = { |
52 /** Move to the beginning or end of the current unit. */ | 52 /** Move to the beginning or end of the current unit. */ |
53 BOUND: 'bound', | 53 BOUND: 'bound', |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 * @return {!cursors.Cursor} The moved cursor. | 211 * @return {!cursors.Cursor} The moved cursor. |
212 */ | 212 */ |
213 move: function(unit, movement, dir) { | 213 move: function(unit, movement, dir) { |
214 var originalNode = this.node; | 214 var originalNode = this.node; |
215 if (!originalNode) | 215 if (!originalNode) |
216 return this; | 216 return this; |
217 | 217 |
218 var newNode = originalNode; | 218 var newNode = originalNode; |
219 var newIndex = this.index_; | 219 var newIndex = this.index_; |
220 | 220 |
221 if ((unit != Unit.NODE || unit != Unit.DOM_NODE) && | 221 if (unit != Unit.NODE && newIndex === cursors.NODE_INDEX) |
222 newIndex === cursors.NODE_INDEX) | |
223 newIndex = 0; | 222 newIndex = 0; |
224 | 223 |
225 switch (unit) { | 224 switch (unit) { |
226 case Unit.CHARACTER: | 225 case Unit.CHARACTER: |
227 // BOUND and DIRECTIONAL are the same for characters. | 226 // BOUND and DIRECTIONAL are the same for characters. |
228 var text = this.getText(); | 227 var text = this.getText(); |
229 newIndex = dir == Dir.FORWARD ? | 228 newIndex = dir == Dir.FORWARD ? |
230 StringUtil.nextCodePointOffset(text, newIndex) : | 229 StringUtil.nextCodePointOffset(text, newIndex) : |
231 StringUtil.previousCodePointOffset(text, newIndex); | 230 StringUtil.previousCodePointOffset(text, newIndex); |
232 if (newIndex < 0 || newIndex >= text.length) { | 231 if (newIndex < 0 || newIndex >= text.length) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 } | 299 } |
301 } | 300 } |
302 } | 301 } |
303 } | 302 } |
304 } else { | 303 } else { |
305 // TODO(dtseng): Figure out what to do in this case. | 304 // TODO(dtseng): Figure out what to do in this case. |
306 } | 305 } |
307 } | 306 } |
308 break; | 307 break; |
309 case Unit.NODE: | 308 case Unit.NODE: |
310 case Unit.DOM_NODE: | |
311 switch (movement) { | 309 switch (movement) { |
312 case Movement.BOUND: | 310 case Movement.BOUND: |
313 newIndex = dir == Dir.FORWARD ? this.getText().length - 1 : 0; | 311 newIndex = dir == Dir.FORWARD ? this.getText().length - 1 : 0; |
314 break; | 312 break; |
315 case Movement.DIRECTIONAL: | 313 case Movement.DIRECTIONAL: |
316 var pred = unit == Unit.NODE ? | |
317 AutomationPredicate.leaf : AutomationPredicate.object; | |
318 newNode = AutomationUtil.findNextNode( | 314 newNode = AutomationUtil.findNextNode( |
319 newNode, dir, pred) || originalNode; | 315 newNode, dir, AutomationPredicate.object) || originalNode; |
320 newIndex = cursors.NODE_INDEX; | 316 newIndex = cursors.NODE_INDEX; |
321 break; | 317 break; |
322 } | 318 } |
323 break; | 319 break; |
324 case Unit.LINE: | 320 case Unit.LINE: |
325 newIndex = 0; | 321 newIndex = 0; |
326 switch (movement) { | 322 switch (movement) { |
327 case Movement.BOUND: | 323 case Movement.BOUND: |
328 newNode = AutomationUtil.findNodeUntil(newNode, dir, | 324 newNode = AutomationUtil.findNodeUntil(newNode, dir, |
329 AutomationPredicate.linebreak, true); | 325 AutomationPredicate.linebreak, true); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 cursors.WrappingCursor.prototype = { | 376 cursors.WrappingCursor.prototype = { |
381 __proto__: cursors.Cursor.prototype, | 377 __proto__: cursors.Cursor.prototype, |
382 | 378 |
383 /** @override */ | 379 /** @override */ |
384 move: function(unit, movement, dir) { | 380 move: function(unit, movement, dir) { |
385 var result = this; | 381 var result = this; |
386 if (!result.node) | 382 if (!result.node) |
387 return this; | 383 return this; |
388 | 384 |
389 // Regular movement. | 385 // Regular movement. |
390 if (!AutomationPredicate.root(this.node) || dir == Dir.FORWARD) | 386 if (!AutomationPredicate.root(this.node) || |
| 387 dir == Dir.FORWARD || |
| 388 movement == Movement.BOUND) |
391 result = cursors.Cursor.prototype.move.call(this, unit, movement, dir); | 389 result = cursors.Cursor.prototype.move.call(this, unit, movement, dir); |
392 | 390 |
| 391 // Moving to the bounds of a unit never wraps. |
| 392 if (movement == Movement.BOUND) |
| 393 return new cursors.WrappingCursor(result.node, result.index); |
| 394 |
393 // There are two cases for wrapping: | 395 // There are two cases for wrapping: |
394 // 1. moving forwards from the last element. | 396 // 1. moving forwards from the last element. |
395 // 2. moving backwards from the first element. | 397 // 2. moving backwards from the first element. |
396 // Both result in |move| returning the same cursor. | 398 // Both result in |move| returning the same cursor. |
397 // For 1, simply place the new cursor on the document node. | 399 // For 1, simply place the new cursor on the document node. |
398 // For 2, place range on the root (if not already there). If at root, | 400 // For 2, place range on the root (if not already there). If at root, |
399 // try to descend to the first leaf-like object. | 401 // try to descend to the first leaf-like object. |
400 if (movement == Movement.DIRECTIONAL && result.equals(this)) { | 402 if (movement == Movement.DIRECTIONAL && result.equals(this)) { |
401 var pred = unit == Unit.DOM_NODE ? | 403 var pred = unit == Unit.NODE ? |
402 AutomationPredicate.object : AutomationPredicate.leaf; | 404 AutomationPredicate.object : AutomationPredicate.leaf; |
403 var endpoint = this.node; | 405 var endpoint = this.node; |
404 if (!endpoint) | 406 if (!endpoint) |
405 return this; | 407 return this; |
406 | 408 |
407 // Case 1: forwards (find the root-like node). | 409 // Case 1: forwards (find the root-like node). |
408 while (!AutomationPredicate.root(endpoint) && endpoint.parent) | 410 while (!AutomationPredicate.root(endpoint) && endpoint.parent) |
409 endpoint = endpoint.parent; | 411 endpoint = endpoint.parent; |
410 | 412 |
411 // Always play a wrap earcon when moving forward. | 413 // Always play a wrap earcon when moving forward. |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 if (newStart.node !== newEnd.node) | 563 if (newStart.node !== newEnd.node) |
562 newEnd = new cursors.Cursor(newStart.node, newStart.index + 1); | 564 newEnd = new cursors.Cursor(newStart.node, newStart.index + 1); |
563 break; | 565 break; |
564 case Unit.WORD: | 566 case Unit.WORD: |
565 case Unit.LINE: | 567 case Unit.LINE: |
566 newStart = newStart.move(unit, Movement.DIRECTIONAL, dir); | 568 newStart = newStart.move(unit, Movement.DIRECTIONAL, dir); |
567 newStart = newStart.move(unit, Movement.BOUND, Dir.BACKWARD); | 569 newStart = newStart.move(unit, Movement.BOUND, Dir.BACKWARD); |
568 newEnd = newStart.move(unit, Movement.BOUND, Dir.FORWARD); | 570 newEnd = newStart.move(unit, Movement.BOUND, Dir.FORWARD); |
569 break; | 571 break; |
570 case Unit.NODE: | 572 case Unit.NODE: |
571 case Unit.DOM_NODE: | |
572 newStart = newStart.move(unit, Movement.DIRECTIONAL, dir); | 573 newStart = newStart.move(unit, Movement.DIRECTIONAL, dir); |
573 newEnd = newStart; | 574 newEnd = newStart; |
574 break; | 575 break; |
575 default: | 576 default: |
576 throw Error('Invalid unit: ' + unit); | 577 throw Error('Invalid unit: ' + unit); |
577 } | 578 } |
578 return new cursors.Range(newStart, newEnd); | 579 return new cursors.Range(newStart, newEnd); |
579 }, | 580 }, |
580 | 581 |
581 /** | 582 /** |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 /** | 631 /** |
631 * Returns whether this range has valid start and end cursors. | 632 * Returns whether this range has valid start and end cursors. |
632 * @return {boolean} | 633 * @return {boolean} |
633 */ | 634 */ |
634 isValid: function() { | 635 isValid: function() { |
635 return this.start.isValid() && this.end.isValid(); | 636 return this.start.isValid() && this.end.isValid(); |
636 } | 637 } |
637 }; | 638 }; |
638 | 639 |
639 }); // goog.scope | 640 }); // goog.scope |
OLD | NEW |