@@ -13,40 +13,63 @@ import {PartialObserver} from 'rxjs';
13
13
import { CELL_SELECTOR , ROW_SELECTOR , TABLE_SELECTOR } from './constants' ;
14
14
import { closest } from './polyfill' ;
15
15
16
- /** Service responsible for moving cell focus around in response to keyboard events. */
17
- @Injectable ( )
16
+ /**
17
+ * Service responsible for moving cell focus around in response to keyboard events.
18
+ * May be overridden to customize the keyboard behavior of popover edit.
19
+ */
20
+ @Injectable ( { providedIn : 'root' } )
18
21
export class FocusDispatcher {
22
+ /** Observes keydown events triggered from the table. */
19
23
readonly keyObserver : PartialObserver < KeyboardEvent > ;
20
24
21
- constructor ( private readonly _directionality : Directionality ) {
22
- this . keyObserver = { next : ( evt ) => this . handleKey ( evt ) } ;
25
+ constructor ( protected readonly directionality : Directionality ) {
26
+ this . keyObserver = { next : ( evt ) => this . handleKeyboardEvent ( evt ) } ;
23
27
}
24
28
25
- moveFocusHorizontally ( currentCell , offset : number ) {
26
- const allCells =
27
- Array . from ( closest ( currentCell , TABLE_SELECTOR ) . querySelectorAll ( CELL_SELECTOR ) ) ;
28
- const currentIndex = allCells . indexOf ( currentCell ) ;
29
+ /**
30
+ * Moves focus to earlier or later cells (in dom order) by offset cells relative to
31
+ * currentCell.
32
+ */
33
+ moveFocusHorizontally ( currentCell : HTMLElement , offset : number ) : void {
34
+ const cells =
35
+ Array . from ( closest ( currentCell , TABLE_SELECTOR ) ! . querySelectorAll ( CELL_SELECTOR ) ) as
36
+ HTMLElement [ ] ;
37
+ const currentIndex = cells . indexOf ( currentCell ) ;
29
38
const newIndex = currentIndex + offset ;
30
39
31
40
if ( cells [ newIndex ] ) {
32
41
cells [ newIndex ] . focus ( ) ;
33
42
}
34
43
}
35
44
36
- moveFocusVertically ( currentCell : HTMLElement , offset : number ) {
37
- const currentRow = closest ( currentCell , ROW_SELECTOR ) ;
38
- const rows = Array . from ( closest ( currentRow , TABLE_SELECTOR ) . querySelectorAll ( ROW_SELECTOR ) ) ;
39
- const currentRowIndex = rows . indexOf ( currentRowIndex ) ;
40
- const currentIndexWithinRow = Array . from ( currentRow . querySelectorAll ( CELL_SELECTOR ) ) ;
45
+ /** Moves focus to up or down by row by offset cells relative to currentCell. */
46
+ moveFocusVertically ( currentCell : HTMLElement , offset : number ) : void {
47
+ const currentRow = closest ( currentCell , ROW_SELECTOR ) ! ;
48
+ const rows = Array . from ( closest ( currentRow , TABLE_SELECTOR ) ! . querySelectorAll ( ROW_SELECTOR ) ) ;
49
+ const currentRowIndex = rows . indexOf ( currentRow ) ;
50
+ const currentIndexWithinRow =
51
+ Array . from ( currentRow . querySelectorAll ( CELL_SELECTOR ) ) . indexOf ( currentCell ) ;
41
52
const newRowIndex = currentRowIndex + offset ;
42
53
43
- if ( rows [ newRowIndex ] && rows [ newRowIndex ] [ currentIndexWithinRow ] ) {
44
- rows [ newRowIndex ] [ currentIndexWithinRow ] . focus ( ) ;
54
+ if ( rows [ newRowIndex ] ) {
55
+ const rowToFocus =
56
+ Array . from ( rows [ newRowIndex ] . querySelectorAll ( CELL_SELECTOR ) ) as HTMLElement [ ] ;
57
+
58
+ if ( rowToFocus [ currentIndexWithinRow ] ) {
59
+ rowToFocus [ currentIndexWithinRow ] . focus ( ) ;
60
+ }
45
61
}
46
62
}
47
63
48
- protected handleKey ( key : string , cell : HTMLElement ) {
49
- switch ( key ) {
64
+ /** Translates arrow keydown events into focus move operations. */
65
+ protected handleKeyboardEvent ( evt : KeyboardEvent ) : void {
66
+ const cell = closest ( evt . target , CELL_SELECTOR ) as HTMLElement | null ;
67
+
68
+ if ( ! cell ) {
69
+ return ;
70
+ }
71
+
72
+ switch ( evt . key ) {
50
73
case 'ArrowUp' :
51
74
this . moveFocusVertically ( cell , - 1 ) ;
52
75
break ;
@@ -59,7 +82,10 @@ export class FocusDispatcher {
59
82
case 'ArrowRight' :
60
83
this . moveFocusHorizontally ( cell , this . directionality . value === 'ltr' ? 1 : - 1 ) ;
61
84
break ;
62
- defualt: break ;
85
+ default :
86
+ return ;
63
87
}
88
+
89
+ evt . preventDefault ( ) ;
64
90
}
65
91
}
0 commit comments