@@ -51,8 +51,13 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
51
51
return this . grid . isChildGridRecord ( this . grid . verticalScrollContainer . igxForOf [ index ] ) ;
52
52
}
53
53
54
- public getCellElementByVisibleIndex ( rowIndex , visibleColumnIndex ) {
55
- const cellSelector = this . getCellSelector ( visibleColumnIndex ) ;
54
+ public getCellElementByVisibleIndex ( rowIndex , visibleColumnIndex , isSummary = false ) {
55
+ const cellSelector = this . getCellSelector ( visibleColumnIndex , isSummary ) ;
56
+ if ( isSummary ) {
57
+ const summaryRow = this . grid . summariesRowList . toArray ( ) [ 0 ] . nativeElement ;
58
+ return summaryRow . querySelector (
59
+ `${ cellSelector } [data-visibleIndex="${ visibleColumnIndex } "]` ) ;
60
+ }
56
61
const row = this . getRowByIndex ( rowIndex ) ;
57
62
return row . querySelector (
58
63
`${ cellSelector } [data-rowindex="${ rowIndex } "][data-visibleIndex="${ visibleColumnIndex } "]` ) ;
@@ -192,11 +197,22 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
192
197
// handle scenario where last child row might not be in view
193
198
// parent should scroll to child grid end
194
199
const childContainer = this . grid . nativeElement . parentNode . parentNode ;
195
- const diff =
200
+ const diffBottom =
196
201
childContainer . getBoundingClientRect ( ) . bottom - this . grid . rootGrid . nativeElement . getBoundingClientRect ( ) . bottom ;
197
- const endIsVisible = diff <= 0 ;
202
+ const row = this . grid . getRowByIndex ( rowIndex ) . element . nativeElement ;
203
+ const gridTop = this . _getMaxTop ( this . grid ) ;
204
+ const diffTop = row . getBoundingClientRect ( ) . bottom -
205
+ row . offsetHeight - gridTop ;
206
+ const endIsVisible = diffBottom <= 0 ;
207
+ const topVisible = diffTop >= 0 ;
198
208
if ( ! endIsVisible ) {
199
- this . scrollGrid ( this . grid . parent , diff , ( ) => super . onKeydownEnd ( rowIndex ) ) ;
209
+ this . scrollGrid ( this . grid . parent , diffBottom , ( ) => super . onKeydownEnd ( rowIndex ) ) ;
210
+ } else if ( ! topVisible ) {
211
+ const scrGrid = this . grid . verticalScrollContainer . getVerticalScroll ( ) . scrollTop !== 0 ? this . grid :
212
+ this . getNextScrollable ( this . grid ) . grid ;
213
+ const topGrid = scrGrid . tbody . nativeElement . getBoundingClientRect ( ) . top >
214
+ this . grid . rootGrid . tbody . nativeElement . getBoundingClientRect ( ) . top ? scrGrid : this . grid . rootGrid ;
215
+ this . scrollGrid ( topGrid , diffTop , ( ) => super . onKeydownEnd ( rowIndex ) ) ;
200
216
} else {
201
217
super . onKeydownEnd ( rowIndex , isSummary ) ;
202
218
}
@@ -226,40 +242,103 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
226
242
}
227
243
}
228
244
229
- public performTab ( currentRowEl , rowIndex , visibleColumnIndex ) {
230
- if ( ! this . grid . rowList . find ( row => row . index === rowIndex + 1 ) && this . grid . parent &&
231
- this . grid . unpinnedColumns [ this . grid . unpinnedColumns . length - 1 ] . visibleIndex === visibleColumnIndex ) {
245
+ public performTab ( currentRowEl , rowIndex , visibleColumnIndex , isSummaryRow = false ) {
246
+ const summaryRows = this . grid . summariesRowList . toArray ( ) ;
247
+ const hasSummaries = summaryRows . length > 0 ;
248
+ const isLastDataRow = rowIndex === this . grid . verticalScrollContainer . igxForOf . length - 1 ;
249
+ const nextIsDataRow = this . grid . dataRowList . find ( row => row . index === rowIndex + 1 ) ;
250
+ const isLastColumn = this . grid . unpinnedColumns [ this . grid . unpinnedColumns . length - 1 ] . visibleIndex === visibleColumnIndex ;
251
+ const isLastSummaryRow = hasSummaries && isSummaryRow ;
252
+ if ( ! nextIsDataRow && ! ( isLastDataRow && hasSummaries ) && isLastColumn && ! isSummaryRow ) {
253
+ // navigating in child, next is not summary
232
254
this . navigateDown ( currentRowEl , rowIndex , 0 ) ;
255
+ } else if ( isLastSummaryRow && isLastColumn && this . grid . parent ) {
256
+ // navigating in child summary, next is parent summary or next parent row
257
+ const parent = this . grid . parent ;
258
+ const parentHasSummary = parent . summariesRowList . toArray ( ) . length > 0 ;
259
+ const parentRowIndex = parseInt (
260
+ this . getClosestElemByTag ( currentRowEl , 'igx-child-grid-row' ) . parentNode . getAttribute ( 'data-rowindex' ) , 10 ) ;
261
+ const isLastRowInParent = parent . verticalScrollContainer . igxForOf . length - 1 === parentRowIndex ;
262
+ // check if next is sibling
263
+ const childRowContainer = this . getChildGridRowContainer ( this . grid ) ;
264
+ const nextIsSiblingChild = ! ! childRowContainer . nextElementSibling ;
265
+ if ( isLastRowInParent && parentHasSummary && ! nextIsSiblingChild ) {
266
+ // next is parent summary
267
+ const parentSummary = parent . summariesRowList . toArray ( ) [ 0 ] . nativeElement ;
268
+ parent . navigation . focusNextRow ( parentSummary , 0 , this . grid . rootGrid , true ) ;
269
+ } else {
270
+ // next is sibling or parent
271
+ this . focusNext ( 0 ) ;
272
+ }
273
+ } else if ( isLastDataRow && hasSummaries && isLastColumn && this . grid . parent ) {
274
+ // navigating in child rows, next is child grid's summary row
275
+ this . focusNextRow ( summaryRows [ 0 ] . nativeElement , 0 , this . grid . parent , true ) ;
233
276
} else {
234
- super . performTab ( currentRowEl , rowIndex , visibleColumnIndex ) ;
277
+ // navigating in normal cells
278
+ super . performTab ( currentRowEl , rowIndex , visibleColumnIndex , isSummaryRow ) ;
235
279
}
236
280
}
237
- public performShiftTabKey ( currentRowEl , rowIndex , visibleColumnIndex ) {
238
- if ( visibleColumnIndex === 0 && rowIndex === 0 && this . grid . parent ) {
281
+ public performShiftTabKey ( currentRowEl , rowIndex , visibleColumnIndex , isSummary = false ) {
282
+ if ( visibleColumnIndex === 0 && rowIndex === 0 && this . grid . parent && ! isSummary ) {
239
283
if ( this . grid . allowFiltering ) {
240
284
this . moveFocusToFilterCell ( ) ;
241
285
} else {
242
286
const prevSiblingChild = this . getChildGridRowContainer ( ) . previousElementSibling ;
243
287
if ( prevSiblingChild ) {
244
288
const gridElem = prevSiblingChild . querySelectorAll ( 'igx-hierarchical-grid' ) [ 0 ] ;
245
- const prevGridCols = this . getChildGrid ( gridElem . getAttribute ( 'id' ) , this . grid . parent ) . unpinnedColumns ;
246
- this . navigateUp ( currentRowEl , rowIndex , prevGridCols [ prevGridCols . length - 1 ] . visibleIndex ) ;
289
+ this . performShiftTabIntoChild ( gridElem , currentRowEl , rowIndex ) ;
247
290
} else {
248
291
this . navigateUp ( currentRowEl , rowIndex ,
249
292
this . grid . parent . unpinnedColumns [ this . grid . parent . unpinnedColumns . length - 1 ] . visibleIndex ) ;
250
293
}
251
294
}
252
295
} else if ( visibleColumnIndex === 0 && currentRowEl . previousElementSibling &&
253
296
currentRowEl . previousElementSibling . children [ 0 ] . tagName . toLowerCase ( ) === 'igx-child-grid-row' ) {
254
- const gridElem = currentRowEl . previousElementSibling . querySelector ( 'igx-hierarchical-grid' ) ;
255
- const childGridID = gridElem . getAttribute ( 'id' ) ;
256
- const childGrid = this . getChildGrid ( childGridID , this . grid ) ;
257
- this . navigateUp ( currentRowEl , rowIndex , childGrid . unpinnedColumns [ childGrid . unpinnedColumns . length - 1 ] . visibleIndex ) ;
297
+ const gridElem = this . getLastGridElem ( currentRowEl . previousElementSibling ) ;
298
+ this . performShiftTabIntoChild ( gridElem , currentRowEl , rowIndex ) ;
299
+ } else if ( visibleColumnIndex === 0 && isSummary ) {
300
+ const lastRowIndex = this . grid . verticalScrollContainer . igxForOf . length - 1 ;
301
+ if ( ! this . getIsChildAtIndex ( lastRowIndex ) ) {
302
+ super . goToLastCell ( ) ;
303
+ } else {
304
+ const scrTopPosition = this . grid . verticalScrollContainer . getScrollForIndex ( lastRowIndex , true ) ;
305
+ const verticalScroll = this . grid . verticalScrollContainer . getVerticalScroll ( ) ;
306
+ if ( verticalScroll . scrollTop === scrTopPosition || isNaN ( scrTopPosition ) ) {
307
+ const closestChild = this . getLastGridElem ( this . grid . getRowByIndex ( lastRowIndex ) . nativeElement . parentElement ) ;
308
+ this . performShiftTabIntoChild ( closestChild , currentRowEl , rowIndex ) ;
309
+ } else {
310
+ this . scrollGrid ( this . grid , scrTopPosition - verticalScroll . scrollTop ,
311
+ ( ) => {
312
+ const closestChild = this . getLastGridElem ( this . grid . getRowByIndex ( lastRowIndex ) . nativeElement . parentElement ) ;
313
+ this . performShiftTabIntoChild ( closestChild , currentRowEl , rowIndex ) ;
314
+ } ) ;
315
+ }
316
+ }
258
317
} else {
259
- super . performShiftTabKey ( currentRowEl , rowIndex , visibleColumnIndex ) ;
318
+ super . performShiftTabKey ( currentRowEl , rowIndex , visibleColumnIndex , isSummary ) ;
260
319
}
261
320
}
262
321
322
+ private getLastGridElem ( trContainer ) {
323
+ const children = trContainer . children ;
324
+ const closestChild = children [ children . length - 1 ] . children [ 0 ] . children [ 0 ] ;
325
+ return closestChild ;
326
+ }
327
+
328
+ private performShiftTabIntoChild ( gridElem , currentRowEl , rowIndex ) {
329
+ const childGridID = gridElem . getAttribute ( 'id' ) ;
330
+ const childGrid = this . getChildGrid ( childGridID , this . grid ) || this . getChildGrid ( childGridID , this . grid . parent ) ;
331
+ const lastIndex = childGrid . unpinnedColumns [ childGrid . unpinnedColumns . length - 1 ] . visibleIndex ;
332
+ const summaryRows = childGrid . summariesRowList . toArray ( ) ;
333
+ if ( summaryRows . length > 0 ) {
334
+ // move focus to last summary row cell
335
+ const summaryRow = summaryRows [ 0 ] . nativeElement ;
336
+ this . focusPrevRow ( summaryRow , lastIndex , childGrid , true , true ) ;
337
+ return ;
338
+ }
339
+ this . navigateUp ( currentRowEl , rowIndex , lastIndex ) ;
340
+ }
341
+
263
342
private _focusScrollCellInView ( visibleColumnIndex ) {
264
343
const cellSelector = this . getCellSelector ( visibleColumnIndex ) ;
265
344
const cells = this . grid . nativeElement . querySelectorAll (
@@ -461,8 +540,8 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
461
540
return top ;
462
541
}
463
542
464
- private focusNextRow ( elem , visibleColumnIndex , grid ) {
465
- const cellSelector = this . getCellSelector ( visibleColumnIndex ) ;
543
+ private focusNextRow ( elem , visibleColumnIndex , grid , isSummary ? ) {
544
+ const cellSelector = this . getCellSelector ( visibleColumnIndex , isSummary ) ;
466
545
if ( grid . navigation . isColumnFullyVisible ( visibleColumnIndex ) && grid . navigation . isColumnLeftFullyVisible ( visibleColumnIndex ) ) {
467
546
const cell =
468
547
elem . querySelector ( `${ cellSelector } [data-visibleIndex="${ visibleColumnIndex } "]` ) ;
@@ -471,7 +550,11 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
471
550
const gridBottom = this . _getMinBottom ( grid ) ;
472
551
const diff = cell . getBoundingClientRect ( ) . bottom - gridBottom ;
473
552
const inView = diff <= 0 ;
474
- if ( ! inView ) {
553
+ const scrollTop = closestScrollableGrid . verticalScrollContainer . getVerticalScroll ( ) . scrollTop ;
554
+ const scrollHeight = closestScrollableGrid . verticalScrollContainer . getVerticalScroll ( ) . scrollHeight ;
555
+ const canScroll = ! ( scrollHeight === 0 ||
556
+ Math . round ( scrollTop + closestScrollableGrid . verticalScrollContainer . igxForContainerSize ) === scrollHeight ) ;
557
+ if ( ! inView && canScroll ) {
475
558
this . scrollGrid ( closestScrollableGrid , diff , ( ) => cell . focus ( { preventScroll : true } ) ) ;
476
559
} else {
477
560
cell . focus ( { preventScroll : true } ) ;
@@ -483,9 +566,9 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
483
566
}
484
567
}
485
568
486
- private focusPrevRow ( elem , visibleColumnIndex , grid , inChild ?) {
569
+ private focusPrevRow ( elem , visibleColumnIndex , grid , inChild ?, isSummary ? ) {
487
570
if ( grid . navigation . isColumnFullyVisible ( visibleColumnIndex ) && grid . navigation . isColumnLeftFullyVisible ( visibleColumnIndex ) ) {
488
- const cellSelector = this . getCellSelector ( visibleColumnIndex ) ;
571
+ const cellSelector = this . getCellSelector ( visibleColumnIndex , isSummary ) ;
489
572
const cells = elem . querySelectorAll ( `${ cellSelector } [data-visibleIndex="${ visibleColumnIndex } "]` ) ;
490
573
let cell = cells [ cells . length - 1 ] ;
491
574
const rIndex = parseInt ( elem . getAttribute ( 'data-rowindex' ) , 10 ) ;
@@ -499,7 +582,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
499
582
cell . offsetHeight - gridTop ;
500
583
if ( scrTop !== 0 && diff < 0 && ! inChild ) {
501
584
this . scrollGrid ( scrGrid , diff , ( ) => {
502
- const el = grid . navigation . getRowByIndex ( rIndex ) ;
585
+ const el = ! isSummary ? grid . navigation . getRowByIndex ( rIndex ) : elem ;
503
586
cell = el . querySelectorAll ( `${ cellSelector } [data-visibleIndex="${ visibleColumnIndex } "]` ) [ 0 ] ;
504
587
cell . focus ( { preventScroll : true } ) ;
505
588
} ) ;
@@ -512,7 +595,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
512
595
}
513
596
} else {
514
597
this . horizontalScrollGridToIndex ( grid , visibleColumnIndex , ( ) => {
515
- this . focusPrevRow ( elem , visibleColumnIndex , grid , inChild ) ;
598
+ this . focusPrevRow ( elem , visibleColumnIndex , grid , inChild , isSummary ) ;
516
599
} ) ;
517
600
}
518
601
}
0 commit comments