@@ -80,6 +80,8 @@ export interface ListBaseProperties extends Properties<Item> {
8080 focusedElement ?: dxElementWrapper ;
8181}
8282
83+ type Direction = 'prev' | 'next' ;
84+
8385export class ListBase extends CollectionWidget < ListBaseProperties > {
8486 static ItemClass = ListItem ;
8587
@@ -120,78 +122,88 @@ export class ListBase extends CollectionWidget<ListBaseProperties> {
120122 _selectionChangeEventInstance ?: any ;
121123
122124 _supportedKeys ( ) : Record < string , ( e : KeyboardEvent , options ?: Record < string , unknown > ) => void > {
123- const that = this ;
125+ return {
126+ ...super . _supportedKeys ( ) ,
127+ leftArrow : noop ,
128+ rightArrow : noop ,
129+ pageUp ( e ) {
130+ this . _moveFocusPerPage ( e , 'prev' ) ;
131+ } ,
132+ pageDown ( e ) {
133+ this . _moveFocusPerPage ( e , 'next' ) ;
134+ } ,
135+ } ;
136+ }
124137
125- const moveFocusPerPage = function ( direction ) {
126- let $item = getEdgeVisibleItem ( direction ) ;
138+ _moveFocusPerPage ( e : KeyboardEvent , direction : Direction ) : void {
139+ if ( this . _isLastItemFocused ( direction ) ) {
140+ return ;
141+ }
127142
128- const { focusedElement } = that . option ( ) ;
129- // @ts -expect-error ts-error
130- const isFocusedItem = $item . is ( focusedElement ) ;
143+ e . preventDefault ( ) ;
144+ e . stopPropagation ( ) ;
131145
132- if ( isFocusedItem ) {
133- scrollListTo ( $item , direction ) ;
134- $item = getEdgeVisibleItem ( direction ) ;
135- }
146+ let $item = this . _getEdgeVisibleItem ( direction ) ;
147+ const { focusedElement } = this . option ( ) ;
136148
137- that . option ( 'focusedElement' , getPublicElement ( $item ) ) ;
138- that . scrollToItem ( $item ) ;
139- } ;
149+ const isFocusedItem = $item . is ( $ ( focusedElement ) ) ;
140150
141- function getEdgeVisibleItem ( direction ) {
142- const scrollTop = that . scrollTop ( ) ;
143- const containerHeight = getHeight ( that . $element ( ) ) ;
151+ if ( isFocusedItem ) {
152+ this . scrollTo ( this . _getItemLocation ( $item , direction ) ) ;
153+ $item = this . _getEdgeVisibleItem ( direction ) ;
154+ }
144155
145- const { focusedElement } = that . option ( ) ;
156+ this . option ( 'focusedElement' , getPublicElement ( $item ) ) ;
157+ this . scrollToItem ( $item ) ;
158+ }
146159
147- let $item = $ ( focusedElement ) ;
148- let isItemVisible = true ;
160+ _isLastItemFocused ( direction : Direction ) : boolean {
161+ const lastItemInDirection = direction === 'prev' ? this . _itemElements ( ) . first ( ) : this . _itemElements ( ) . last ( ) ;
162+ const { focusedElement } = this . option ( ) ;
149163
150- if ( ! $item . length ) {
151- return $ ( ) ;
152- }
164+ return lastItemInDirection . is ( $ ( focusedElement ) ) ;
165+ }
153166
154- while ( isItemVisible ) {
155- const $nextItem = $item [ direction ] ( ) ;
167+ _getEdgeVisibleItem ( direction : Direction ) : dxElementWrapper {
168+ const scrollTop = this . scrollTop ( ) ;
169+ const containerHeight = getHeight ( this . $element ( ) ) ;
156170
157- if ( ! $nextItem . length ) {
158- break ;
159- }
171+ const { focusedElement } = this . option ( ) ;
160172
161- const nextItemLocation = $nextItem . position ( ) . top + getOuterHeight ( $nextItem ) / 2 ;
162- isItemVisible = nextItemLocation < containerHeight + scrollTop && nextItemLocation > scrollTop ;
173+ let $item = $ ( focusedElement ) ;
174+ let isItemVisible = true ;
163175
164- if ( isItemVisible ) {
165- $item = $nextItem ;
166- }
167- }
168-
169- return $item ;
176+ if ( ! $item . length ) {
177+ return $ ( ) ;
170178 }
171179
172- function scrollListTo ( $item , direction ) {
173- let resultPosition = $item . position ( ) . top ;
180+ while ( isItemVisible ) {
181+ const $nextItem = $item [ direction ] ( ) ;
174182
175- if ( direction === 'prev' ) {
176- resultPosition = $item . position ( ) . top - getHeight ( that . $element ( ) ) + getOuterHeight ( $item ) ;
183+ if ( ! $nextItem . length ) {
184+ break ;
177185 }
178186
179- that . scrollTo ( resultPosition ) ;
187+ const nextItemLocation = ( $nextItem . position ( ) ?. top ?? 0 ) + getOuterHeight ( $nextItem ) / 2 ;
188+ isItemVisible = nextItemLocation < containerHeight + scrollTop && nextItemLocation > scrollTop ;
189+
190+ if ( isItemVisible ) {
191+ $item = $nextItem ;
192+ }
180193 }
181194
182- return {
183- ...super . _supportedKeys ( ) ,
184- leftArrow : noop ,
185- rightArrow : noop ,
186- pageUp ( ) {
187- moveFocusPerPage ( 'prev' ) ;
188- return false ;
189- } ,
190- pageDown ( ) {
191- moveFocusPerPage ( 'next' ) ;
192- return false ;
193- } ,
194- } ;
195+ return $item ;
196+ }
197+
198+ _getItemLocation ( $item : dxElementWrapper , direction : Direction ) : number {
199+ if ( direction === 'prev' ) {
200+ // @ts -expect-error ts-error
201+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
202+ return $item . position ( ) . top - getHeight ( this . $element ( ) ) + getOuterHeight ( $item ) ;
203+ }
204+
205+ // @ts -expect-error ts-error
206+ return $item . position ( ) . top ;
195207 }
196208
197209 _getDefaultOptions ( ) : ListBaseProperties {
0 commit comments