@@ -9,8 +9,10 @@ import {first} from '../rxjs/index';
9
9
10
10
11
11
class FakeFocusable {
12
+ constructor ( private _label = '' ) { }
12
13
disabled = false ;
13
14
focus ( ) { }
15
+ getLabel ( ) { return this . _label ; }
14
16
}
15
17
16
18
class FakeHighlightable {
@@ -20,11 +22,11 @@ class FakeHighlightable {
20
22
}
21
23
22
24
class FakeQueryList < T > extends QueryList < T > {
23
- get length ( ) { return this . items . length ; }
24
25
items : T [ ] ;
25
- toArray ( ) {
26
- return this . items ;
27
- }
26
+ get length ( ) { return this . items . length ; }
27
+ get first ( ) { return this . items [ 0 ] ; }
28
+ toArray ( ) { return this . items ; }
29
+ some ( ) { return this . items . some . apply ( this . items , arguments ) ; }
28
30
}
29
31
30
32
@@ -43,7 +45,7 @@ describe('Key managers', () => {
43
45
downArrow : createKeyboardEvent ( 'keydown' , DOWN_ARROW ) ,
44
46
upArrow : createKeyboardEvent ( 'keydown' , UP_ARROW ) ,
45
47
tab : createKeyboardEvent ( 'keydown' , TAB ) ,
46
- unsupported : createKeyboardEvent ( 'keydown' , 65 ) // corresponds to the letter "a"
48
+ unsupported : createKeyboardEvent ( 'keydown' , 192 ) // corresponds to the tilde character (~)
47
49
} ;
48
50
} ) ;
49
51
@@ -52,7 +54,11 @@ describe('Key managers', () => {
52
54
let keyManager : ListKeyManager < FakeFocusable > ;
53
55
54
56
beforeEach ( ( ) => {
55
- itemList . items = [ new FakeFocusable ( ) , new FakeFocusable ( ) , new FakeFocusable ( ) ] ;
57
+ itemList . items = [
58
+ new FakeFocusable ( 'one' ) ,
59
+ new FakeFocusable ( 'two' ) ,
60
+ new FakeFocusable ( 'three' )
61
+ ] ;
56
62
keyManager = new ListKeyManager < FakeFocusable > ( itemList ) ;
57
63
58
64
// first item is already focused
@@ -383,6 +389,65 @@ describe('Key managers', () => {
383
389
384
390
} ) ;
385
391
392
+ describe ( 'typeahead mode' , ( ) => {
393
+ const debounceInterval = 300 ;
394
+
395
+ beforeEach ( ( ) => {
396
+ keyManager . withTypeAhead ( debounceInterval ) ;
397
+ keyManager . setActiveItem ( - 1 ) ;
398
+ } ) ;
399
+
400
+ it ( 'should throw if the items do not implement the getLabel method' , ( ) => {
401
+ const invalidQueryList = new FakeQueryList ( ) ;
402
+
403
+ invalidQueryList . items = [ { disabled : false } ] ;
404
+
405
+ const invalidManager = new ListKeyManager ( invalidQueryList ) ;
406
+
407
+ expect ( ( ) => invalidManager . withTypeAhead ( ) ) . toThrowError ( / m u s t i m p l e m e n t / ) ;
408
+ } ) ;
409
+
410
+ it ( 'should debounce the input key presses' , fakeAsync ( ( ) => {
411
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 79 ) ) ; // types "o"
412
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 78 ) ) ; // types "n"
413
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 69 ) ) ; // types "e"
414
+
415
+ expect ( keyManager . activeItem ) . not . toBe ( itemList . items [ 0 ] ) ;
416
+
417
+ tick ( debounceInterval ) ;
418
+
419
+ expect ( keyManager . activeItem ) . toBe ( itemList . items [ 0 ] ) ;
420
+ } ) ) ;
421
+
422
+ it ( 'should focus the first item that starts with a letter' , fakeAsync ( ( ) => {
423
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 84 ) ) ; // types "t"
424
+
425
+ tick ( debounceInterval ) ;
426
+
427
+ expect ( keyManager . activeItem ) . toBe ( itemList . items [ 1 ] ) ;
428
+ } ) ) ;
429
+
430
+ it ( 'should focus the first item that starts with sequence of letters' , fakeAsync ( ( ) => {
431
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 84 ) ) ; // types "t"
432
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 72 ) ) ; // types "h"
433
+
434
+ tick ( debounceInterval ) ;
435
+
436
+ expect ( keyManager . activeItem ) . toBe ( itemList . items [ 2 ] ) ;
437
+ } ) ) ;
438
+
439
+ it ( 'should cancel any pending timers if a navigation key is pressed' , fakeAsync ( ( ) => {
440
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 84 ) ) ; // types "t"
441
+ keyManager . onKeydown ( createKeyboardEvent ( 'keydown' , 72 ) ) ; // types "h"
442
+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
443
+
444
+ tick ( debounceInterval ) ;
445
+
446
+ expect ( keyManager . activeItem ) . toBe ( itemList . items [ 0 ] ) ;
447
+ } ) ) ;
448
+
449
+ } ) ;
450
+
386
451
} ) ;
387
452
388
453
describe ( 'FocusKeyManager' , ( ) => {
@@ -400,40 +465,40 @@ describe('Key managers', () => {
400
465
spyOn ( itemList . items [ 2 ] , 'focus' ) ;
401
466
} ) ;
402
467
403
- it ( 'should focus subsequent items when down arrow is pressed' , ( ) => {
404
- keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
468
+ it ( 'should focus subsequent items when down arrow is pressed' , ( ) => {
469
+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
405
470
406
- expect ( itemList . items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
407
- expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
408
- expect ( itemList . items [ 2 ] . focus ) . not . toHaveBeenCalled ( ) ;
471
+ expect ( itemList . items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
472
+ expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
473
+ expect ( itemList . items [ 2 ] . focus ) . not . toHaveBeenCalled ( ) ;
409
474
410
- keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
411
- expect ( itemList . items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
412
- expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
413
- expect ( itemList . items [ 2 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
414
- } ) ;
475
+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
476
+ expect ( itemList . items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
477
+ expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
478
+ expect ( itemList . items [ 2 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
479
+ } ) ;
415
480
416
- it ( 'should focus previous items when up arrow is pressed' , ( ) => {
417
- keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
481
+ it ( 'should focus previous items when up arrow is pressed' , ( ) => {
482
+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
418
483
419
- expect ( itemList . items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
420
- expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
484
+ expect ( itemList . items [ 0 ] . focus ) . not . toHaveBeenCalled ( ) ;
485
+ expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
421
486
422
- keyManager . onKeydown ( fakeKeyEvents . upArrow ) ;
487
+ keyManager . onKeydown ( fakeKeyEvents . upArrow ) ;
423
488
424
- expect ( itemList . items [ 0 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
425
- expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
426
- } ) ;
489
+ expect ( itemList . items [ 0 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
490
+ expect ( itemList . items [ 1 ] . focus ) . toHaveBeenCalledTimes ( 1 ) ;
491
+ } ) ;
427
492
428
- it ( 'should allow setting the focused item without calling focus' , ( ) => {
429
- expect ( keyManager . activeItemIndex )
430
- . toBe ( 0 , `Expected first item of the list to be active.` ) ;
493
+ it ( 'should allow setting the focused item without calling focus' , ( ) => {
494
+ expect ( keyManager . activeItemIndex )
495
+ . toBe ( 0 , `Expected first item of the list to be active.` ) ;
431
496
432
- keyManager . updateActiveItemIndex ( 1 ) ;
433
- expect ( keyManager . activeItemIndex )
434
- . toBe ( 1 , `Expected activeItemIndex to update after calling updateActiveItemIndex().` ) ;
435
- expect ( itemList . items [ 1 ] . focus ) . not . toHaveBeenCalledTimes ( 1 ) ;
436
- } ) ;
497
+ keyManager . updateActiveItemIndex ( 1 ) ;
498
+ expect ( keyManager . activeItemIndex )
499
+ . toBe ( 1 , `Expected activeItemIndex to update after calling updateActiveItemIndex().` ) ;
500
+ expect ( itemList . items [ 1 ] . focus ) . not . toHaveBeenCalledTimes ( 1 ) ;
501
+ } ) ;
437
502
438
503
} ) ;
439
504
0 commit comments