@@ -23,6 +23,7 @@ class FakeBaseTreeKeyManagerItem {
2323 _children : FakeBaseTreeKeyManagerItem [ ] = [ ] ;
2424
2525 isDisabled ?: boolean = false ;
26+ skipItem ?: boolean = false ;
2627
2728 constructor ( private _label : string ) { }
2829
@@ -263,13 +264,33 @@ describe('TreeKeyManager', () => {
263264 expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 0 ) ;
264265 } ) ;
265266
267+ it ( 'should focus the first non-disabled item when Home is pressed' , ( ) => {
268+ itemList . get ( 0 ) ! . isDisabled = true ;
269+ keyManager . onClick ( itemList . get ( 2 ) ! ) ;
270+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 2 ) ;
271+
272+ keyManager . onKeydown ( fakeKeyEvents . home ) ;
273+
274+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 1 ) ;
275+ } ) ;
276+
266277 it ( 'should focus the last item when End is pressed' , ( ) => {
267278 keyManager . onClick ( itemList . get ( 0 ) ! ) ;
268279 expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 0 ) ;
269280
270281 keyManager . onKeydown ( fakeKeyEvents . end ) ;
271282 expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( itemList . length - 1 ) ;
272283 } ) ;
284+
285+ it ( 'should focus the last non-disabled item when End is pressed' , ( ) => {
286+ itemList . get ( itemList . length - 1 ) ! . isDisabled = true ;
287+ keyManager . onClick ( itemList . get ( 0 ) ! ) ;
288+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 0 ) ;
289+
290+ keyManager . onKeydown ( fakeKeyEvents . end ) ;
291+
292+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( itemList . length - 2 ) ;
293+ } ) ;
273294 } ) ;
274295
275296 describe ( 'up/down key events' , ( ) => {
@@ -946,6 +967,195 @@ describe('TreeKeyManager', () => {
946967 expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( - 1 ) ;
947968 } ) ) ;
948969 } ) ;
970+
971+ describe ( 'focusItem' , ( ) => {
972+ beforeEach ( ( ) => {
973+ keyManager . onInitialFocus ( ) ;
974+ } ) ;
975+
976+ it ( 'should focus the provided index' , ( ) => {
977+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 0 ) ;
978+
979+ keyManager . focusItem ( 1 ) ;
980+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 1 ) ;
981+ } ) ;
982+
983+ it ( 'should be able to set the active item by reference' , ( ) => {
984+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 0 ) ;
985+
986+ keyManager . focusItem ( itemList . get ( 2 ) ! ) ;
987+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 2 ) ;
988+ } ) ;
989+
990+ it ( 'should be able to set the active item without emitting an event' , ( ) => {
991+ const spy = jasmine . createSpy ( 'change spy' ) ;
992+ const subscription = keyManager . change . subscribe ( spy ) ;
993+
994+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 0 ) ;
995+
996+ keyManager . focusItem ( 2 , { emitChangeEvent : false } ) ;
997+
998+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 2 ) ;
999+ expect ( spy ) . not . toHaveBeenCalled ( ) ;
1000+
1001+ subscription . unsubscribe ( ) ;
1002+ } ) ;
1003+
1004+ it ( 'should not emit an event if the item did not change' , ( ) => {
1005+ const spy = jasmine . createSpy ( 'change spy' ) ;
1006+ const subscription = keyManager . change . subscribe ( spy ) ;
1007+
1008+ keyManager . focusItem ( 2 ) ;
1009+ keyManager . focusItem ( 2 ) ;
1010+
1011+ expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
1012+
1013+ subscription . unsubscribe ( ) ;
1014+ } ) ;
1015+ } ) ;
1016+
1017+ describe ( 'focusFirstItem' , ( ) => {
1018+ beforeEach ( ( ) => {
1019+ keyManager . onInitialFocus ( ) ;
1020+ } ) ;
1021+
1022+ it ( 'should focus the first item' , ( ) => {
1023+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1024+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1025+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 2 ) ;
1026+
1027+ keyManager . focusFirstItem ( ) ;
1028+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 0 ) ;
1029+ } ) ;
1030+
1031+ it ( 'should set the active item to the second item if the first one is disabled' , ( ) => {
1032+ itemList . get ( 0 ) ! . isDisabled = true ;
1033+
1034+ keyManager . focusFirstItem ( ) ;
1035+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 1 ) ;
1036+ } ) ;
1037+ } ) ;
1038+
1039+ describe ( 'focusLastItem' , ( ) => {
1040+ beforeEach ( ( ) => {
1041+ keyManager . onInitialFocus ( ) ;
1042+ } ) ;
1043+
1044+ it ( 'should focus the last item' , ( ) => {
1045+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 0 ) ;
1046+
1047+ keyManager . focusLastItem ( ) ;
1048+ expect ( keyManager . getActiveItemIndex ( ) )
1049+ . withContext ( 'active item index' )
1050+ . toBe ( itemList . length - 1 ) ;
1051+ } ) ;
1052+
1053+ it ( 'should set the active item to the second-to-last item if the last is disabled' , ( ) => {
1054+ itemList . get ( itemList . length - 1 ) ! . isDisabled = true ;
1055+
1056+ keyManager . focusLastItem ( ) ;
1057+ expect ( keyManager . getActiveItemIndex ( ) )
1058+ . withContext ( 'active item index' )
1059+ . toBe ( itemList . length - 2 ) ;
1060+ } ) ;
1061+ } ) ;
1062+
1063+ describe ( 'focusNextItem' , ( ) => {
1064+ beforeEach ( ( ) => {
1065+ keyManager . onInitialFocus ( ) ;
1066+ } ) ;
1067+
1068+ it ( 'should focus the next item' , ( ) => {
1069+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 0 ) ;
1070+
1071+ keyManager . focusNextItem ( ) ;
1072+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 1 ) ;
1073+ } ) ;
1074+
1075+ it ( 'should skip disabled items' , ( ) => {
1076+ itemList . get ( 1 ) ! . isDisabled = true ;
1077+
1078+ keyManager . focusNextItem ( ) ;
1079+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 2 ) ;
1080+ } ) ;
1081+ } ) ;
1082+
1083+ describe ( 'focusPreviousItem' , ( ) => {
1084+ beforeEach ( ( ) => {
1085+ keyManager . onInitialFocus ( ) ;
1086+ } ) ;
1087+
1088+ it ( 'should focus the previous item' , ( ) => {
1089+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1090+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 1 ) ;
1091+
1092+ keyManager . focusPreviousItem ( ) ;
1093+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 0 ) ;
1094+ } ) ;
1095+
1096+ it ( 'should skip disabled items' , ( ) => {
1097+ itemList . get ( 1 ) ! . isDisabled = true ;
1098+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1099+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 2 ) ;
1100+
1101+ keyManager . focusPreviousItem ( ) ;
1102+ expect ( keyManager . getActiveItemIndex ( ) ) . withContext ( 'active item index' ) . toBe ( 0 ) ;
1103+ } ) ;
1104+ } ) ;
1105+
1106+ describe ( 'skip predicate' , ( ) => {
1107+ beforeEach ( ( ) => {
1108+ keyManager = new TreeKeyManager ( {
1109+ items : itemList ,
1110+ skipPredicate : item => item . skipItem ?? false ,
1111+ } ) ;
1112+ keyManager . onInitialFocus ( ) ;
1113+ } ) ;
1114+
1115+ it ( 'should be able to skip items with a custom predicate' , ( ) => {
1116+ itemList . get ( 1 ) ! . skipItem = true ;
1117+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 0 ) ;
1118+
1119+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1120+
1121+ expect ( keyManager . getActiveItemIndex ( ) ) . toBe ( 2 ) ;
1122+ } ) ;
1123+ } ) ;
1124+
1125+ describe ( 'focus' , ( ) => {
1126+ beforeEach ( ( ) => {
1127+ keyManager . onInitialFocus ( ) ;
1128+
1129+ for ( const item of itemList ) {
1130+ spyOn ( item , 'focus' ) ;
1131+ }
1132+ } ) ;
1133+
1134+ it ( 'calls .focus() on focused items' , ( ) => {
1135+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1136+
1137+ expect ( itemList . get ( 0 ) ! . focus ) . not . toHaveBeenCalled ( ) ;
1138+ expect ( itemList . get ( 1 ) ! . focus ) . toHaveBeenCalledTimes ( 1 ) ;
1139+ expect ( itemList . get ( 2 ) ! . focus ) . not . toHaveBeenCalled ( ) ;
1140+
1141+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1142+ expect ( itemList . get ( 0 ) ! . focus ) . not . toHaveBeenCalled ( ) ;
1143+ expect ( itemList . get ( 1 ) ! . focus ) . toHaveBeenCalledTimes ( 1 ) ;
1144+ expect ( itemList . get ( 2 ) ! . focus ) . toHaveBeenCalledTimes ( 1 ) ;
1145+ } ) ;
1146+
1147+ it ( 'calls .focus() on focused items, when pressing up key' , ( ) => {
1148+ keyManager . onKeydown ( fakeKeyEvents . downArrow ) ;
1149+
1150+ expect ( itemList . get ( 0 ) ! . focus ) . not . toHaveBeenCalled ( ) ;
1151+ expect ( itemList . get ( 1 ) ! . focus ) . toHaveBeenCalledTimes ( 1 ) ;
1152+
1153+ keyManager . onKeydown ( fakeKeyEvents . upArrow ) ;
1154+
1155+ expect ( itemList . get ( 0 ) ! . focus ) . toHaveBeenCalledTimes ( 1 ) ;
1156+ expect ( itemList . get ( 1 ) ! . focus ) . toHaveBeenCalledTimes ( 1 ) ;
1157+ } ) ;
1158+ } ) ;
9491159 } ) ;
9501160 }
9511161} ) ;
0 commit comments