UNPKG

@catull/igniteui-angular

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

811 lines 136 kB
import { __decorate } from "tslib"; import { IgxGridNavigationService } from '../grid-navigation.service'; import { first } from 'rxjs/operators'; import { isIE } from '../../core/utils'; import { FilterMode } from '../common/enums'; import { Injectable } from '@angular/core'; let IgxHierarchicalGridNavigationService = class IgxHierarchicalGridNavigationService extends IgxGridNavigationService { getCellSelector(visibleIndex, isSummary = false) { return isSummary ? 'igx-grid-summary-cell' : 'igx-hierarchical-grid-cell'; } getRowSelector() { return 'igx-hierarchical-grid-row'; } getRowByIndex(index) { const row = super.getRowByIndex(index); return row; } getChildContainer(grid) { const currGrid = grid || this.grid; return currGrid.nativeElement.parentNode.parentNode.parentNode; } getChildGridRowContainer(grid) { const currGrid = grid || this.grid; return currGrid.nativeElement.parentNode.parentNode; } getChildGrid(childGridID, grid) { const cgrid = grid.hgridAPI.getChildGrids(true).filter((g) => g.id === childGridID)[0]; return cgrid; } _isScrolledToBottom(grid) { const scrollTop = grid.verticalScrollContainer.scrollPosition; const scrollHeight = grid.verticalScrollContainer.getScroll().scrollHeight; return scrollHeight === 0 || Math.round(scrollTop + grid.verticalScrollContainer.igxForContainerSize) === scrollHeight; } getIsChildAtIndex(index) { return this.grid.isChildGridRecord(this.grid.dataView[index]); } getCellElementByVisibleIndex(rowIndex, visibleColumnIndex, isSummary = false) { const cellSelector = this.getCellSelector(visibleColumnIndex, isSummary); if (isSummary) { const summaryRow = this.grid.summariesRowList.toArray()[0].nativeElement; return summaryRow.querySelector(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); } const row = this.getRowByIndex(rowIndex); return row.querySelector(`${cellSelector}[data-rowindex="${rowIndex}"][data-visibleIndex="${visibleColumnIndex}"]`); } navigateUp(rowElement, selectedNode) { if (selectedNode.isSummaryRow) { return; } const prevElem = rowElement.previousElementSibling; const visibleColumnIndex = selectedNode.column; const currentRowIndex = selectedNode.row; if (prevElem) { const nodeName = prevElem.children[0].nodeName.toLowerCase(); const isElemChildGrid = nodeName.toLowerCase() === 'igx-child-grid-row'; if (isElemChildGrid) { this.focusPrevChild(prevElem, visibleColumnIndex, this.grid); } else { if (this.grid.parent !== null) { // currently navigating in child grid this._navigateUpInChild(rowElement, currentRowIndex, visibleColumnIndex); } else { super.navigateUp(rowElement, selectedNode); } } } else if (currentRowIndex !== 0) { // handle scenario when prev item is child grid but is not yet in view const isPrevChildGrid = this.getIsChildAtIndex(currentRowIndex - 1); if (!isPrevChildGrid) { super.navigateUp(rowElement, selectedNode); } else { this.scrollGrid(this.grid, -rowElement.offsetHeight, () => { rowElement = this.getRowByIndex(currentRowIndex); this.navigateUp(rowElement, selectedNode); }); } } else if (this.grid.parent !== null && currentRowIndex === 0) { // move to prev row in sibling layout or parent this.focusPrev(visibleColumnIndex); } } navigateDown(rowElement, selectedNode) { if (selectedNode.isSummaryRow) { return; } const nextElem = rowElement.nextElementSibling; const visibleColumnIndex = selectedNode.column; const currentRowIndex = selectedNode.row; if (nextElem) { // next elem is in DOM const nodeName = nextElem.children[0].nodeName.toLowerCase(); const isNextElemChildGrid = nodeName.toLowerCase() === 'igx-child-grid-row'; if (isNextElemChildGrid) { this.focusNextChild(nextElem, visibleColumnIndex, this.grid); } else { if (this.grid.parent !== null) { // currently navigating in child grid this._navigateDownInChild(rowElement, currentRowIndex, visibleColumnIndex); } else { super.navigateDown(rowElement, selectedNode); } } } else if (currentRowIndex !== this.grid.dataView.length - 1) { // scroll next in view super.navigateDown(rowElement, selectedNode); } else if (this.grid.parent !== null && currentRowIndex === this.grid.dataView.length - 1) { // move to next row in sibling layout or in parent this.focusNext(visibleColumnIndex); } } navigateTop(visibleColumnIndex) { if (this.grid.parent !== null) { // navigating in child const childContainer = this.grid.nativeElement.parentNode.parentNode; const diff = childContainer.getBoundingClientRect().top - this.grid.rootGrid.tbody.nativeElement.getBoundingClientRect().top; const topIsVisible = diff >= 0; const scrollable = this.getNextScrollable(this.grid); if (!topIsVisible) { this.scrollGrid(scrollable.grid, diff, () => super.navigateTop(visibleColumnIndex)); } else { super.navigateTop(visibleColumnIndex); } } else { super.navigateTop(visibleColumnIndex); } } navigateBottom(visibleColumnIndex) { // handle scenario where last index is child grid // in that case focus cell in last data row const lastIndex = this.grid.dataView.length - 1; if (this.getIsChildAtIndex(lastIndex)) { const targetIndex = lastIndex - 1; const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(targetIndex, true); const verticalScrollTop = this.grid.verticalScrollContainer.scrollPosition; const cellSelector = this.getCellSelector(visibleColumnIndex); if (verticalScrollTop === scrTopPosition) { const cells = this.getRowByIndex(targetIndex).querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); cells[cells.length - 1].focus(); } else { this.scrollGrid(this.grid, scrTopPosition - verticalScrollTop, () => { const cells = this.getRowByIndex(targetIndex).querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); if (cells.length > 0) { cells[cells.length - 1].focus(); } }); } } else if (this.grid.parent !== null) { const childContainer = this.grid.nativeElement.parentNode.parentNode; const diff = childContainer.getBoundingClientRect().bottom - this.grid.rootGrid.tbody.nativeElement.getBoundingClientRect().bottom; const endIsVisible = diff < 0; const scrollable = this.getNextScrollableDown(this.grid); if (!endIsVisible) { this.scrollGrid(scrollable.grid, diff, () => super.navigateBottom(visibleColumnIndex)); } else { super.navigateBottom(visibleColumnIndex); } } else { super.navigateBottom(visibleColumnIndex); } } goToLastCell() { // handle scenario where last index is child grid // in that case focus last cell in last data row const lastIndex = this.grid.dataView.length - 1; if (this.getIsChildAtIndex(lastIndex)) { const targetIndex = lastIndex - 1; const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(targetIndex, true); const verticalScrollTop = this.grid.verticalScrollContainer.scrollPosition; if (verticalScrollTop === scrTopPosition) { this.onKeydownEnd(targetIndex); } else { this.scrollGrid(this.grid, scrTopPosition - verticalScrollTop, () => { this.onKeydownEnd(targetIndex); }); } } else { super.goToLastCell(); } } onKeydownEnd(rowIndex, isSummary = false) { if (this.grid.parent && !isSummary) { // handle scenario where last child row might not be in view // parent should scroll to child grid end const childContainer = this.grid.nativeElement.parentNode.parentNode; const diffBottom = childContainer.getBoundingClientRect().bottom - this.grid.rootGrid.nativeElement.getBoundingClientRect().bottom; const row = this.grid.getRowByIndex(rowIndex).element.nativeElement; const rowBottom = row.getBoundingClientRect().bottom; const rowIsVisible = rowBottom <= this.grid.rootGrid.tbody.nativeElement.getBoundingClientRect().bottom; const gridTop = this._getMaxTop(this.grid); const diffTop = row.getBoundingClientRect().bottom - row.offsetHeight - gridTop; const endIsVisible = diffBottom <= 0; const topVisible = diffTop >= 0; if (!endIsVisible && !rowIsVisible) { this.scrollGrid(this.grid.parent, diffBottom, () => super.onKeydownEnd(rowIndex)); } else if (!topVisible) { const scrGrid = this.grid.verticalScrollContainer.scrollPosition !== 0 ? this.grid : this.getNextScrollable(this.grid).grid; const topGrid = scrGrid.tbody.nativeElement.getBoundingClientRect().top > this.grid.rootGrid.tbody.nativeElement.getBoundingClientRect().top ? scrGrid : this.grid.rootGrid; this.scrollGrid(topGrid, diffTop, () => super.onKeydownEnd(rowIndex)); } else { super.onKeydownEnd(rowIndex, isSummary); } } else { super.onKeydownEnd(rowIndex, isSummary); } } goToFirstCell() { const verticalScroll = this.grid.verticalScrollContainer.getScroll(); const horizontalScroll = this.grid.dataRowList.first.virtDirRow.getScroll(); if (verticalScroll.scrollTop === 0 && this.grid.parent) { // scroll parent so that current child is in view if (!horizontalScroll.clientWidth || parseInt(horizontalScroll.scrollLeft, 10) <= 1 || this.grid.pinnedColumns.length) { this.navigateTop(0); } else { this.horizontalScroll(this.grid.dataRowList.first.index).scrollTo(0); this.grid.parentVirtDir.onChunkLoad .pipe(first()) .subscribe(() => { this.navigateTop(0); }); } } else { super.goToFirstCell(); } } performTab(currentRowEl, selectedNode) { if (this.grid.rowInEditMode) { super.performTab(currentRowEl, selectedNode); return; } const rowIndex = selectedNode.row; const visibleColumnIndex = selectedNode.column; const isSummaryRow = selectedNode.isSummaryRow; const summaryRows = this.grid.summariesRowList.toArray(); const hasSummaries = summaryRows.length > 0; const isLastDataRow = rowIndex === this.grid.dataView.length - 1; const nextIsDataRow = this.grid.dataRowList.find(row => row.index === rowIndex + 1); const isLastColumn = this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === visibleColumnIndex; const isLastSummaryRow = hasSummaries && isSummaryRow; const nextIndex = rowIndex + 1; const virt = this.grid.verticalScrollContainer; const isNextChild = nextIndex <= virt.igxForOf.length - 1 && this.grid.isChildGridRecord(virt.igxForOf[nextIndex]); if (!nextIsDataRow && !(isLastDataRow && hasSummaries) && isLastColumn && !isSummaryRow) { // navigating in child, next is not summary const childContainer = this.getChildGridRowContainer(); const nextIsSiblingChild = this.grid.parent ? !!childContainer.nextElementSibling : false; if (nextIsSiblingChild) { this.focusNextChildDOMElem(childContainer, this.grid.parent); } else if (isNextChild) { const isInView = virt.state.startIndex + virt.state.chunkSize > nextIndex; if (!isInView) { this.scrollGrid(this.grid, 'next', () => { this.focusNextChildDOMElem(currentRowEl, this.grid); }); } else { this.focusNextChildDOMElem(currentRowEl, this.grid); } } else if (this.grid.parent && this.grid.parent.summariesRowList.length > 0) { this._navigateToNextParentRow(currentRowEl); } else { this.navigateDown(currentRowEl, { row: rowIndex, column: 0 }); } } else if (isLastSummaryRow && isLastColumn && this.grid.parent) { this._navigateToNextParentRow(currentRowEl); } else if (isLastDataRow && hasSummaries && isLastColumn && this.grid.parent) { // navigating in child rows, next is child grid's summary row this.focusNextRow(summaryRows[0].nativeElement, 0, this.grid.parent, true); } else { super.performTab(currentRowEl, selectedNode); } } _navigateToNextParentRow(currentRowEl) { // next is parent summary or next parent row const parent = this.grid.parent; const parentHasSummary = parent.summariesRowList.length > 0; const parentRowIndex = parseInt(this.getClosestElemByTag(currentRowEl, 'igx-child-grid-row').parentNode.getAttribute('data-rowindex'), 10); const isLastRowInParent = parent.dataView.length - 1 === parentRowIndex; // check if next is sibling const childRowContainer = this.getChildGridRowContainer(this.grid); const nextIsSiblingChild = !!childRowContainer.nextElementSibling; if (isLastRowInParent && parentHasSummary && !nextIsSiblingChild) { // next is parent summary const parentSummary = parent.summariesRowList.first.nativeElement; parent.navigation.focusNextRow(parentSummary, 0, parent, true); } else { // next is sibling or parent this.focusNext(0); } } focusNextChildDOMElem(currentRowEl, grid) { const gridElem = currentRowEl.nextElementSibling.querySelector('igx-hierarchical-grid'); const childGridID = gridElem.getAttribute('id'); const childGrid = this.getChildGrid(childGridID, grid); if (childGrid.allowFiltering && childGrid.filterMode === FilterMode.quickFilter) { childGrid.navigation.moveFocusToFilterCell(true); return; } this.focusNextChild(currentRowEl.nextElementSibling, 0, grid); } navigatePrevFilterCell(column, eventArgs) { if (column.visibleIndex === 0 && this.grid.parent) { eventArgs.preventDefault(); let targetGrid = this.grid.parent; const prevSiblingChild = this.getChildGridRowContainer().previousElementSibling; if (prevSiblingChild) { const gridElem = prevSiblingChild.querySelectorAll('igx-hierarchical-grid')[0]; targetGrid = this.getChildGrid(gridElem.getAttribute('id'), this.grid.parent); } this.focusPrev(targetGrid.unpinnedColumns[targetGrid.unpinnedColumns.length - 1].visibleIndex); } else { super.navigatePrevFilterCell(column, eventArgs); } } navigateNextFilterCell(column, eventArgs) { const cols = this.grid.filteringService.unpinnedFilterableColumns; const nextFilterableIndex = cols.indexOf(column) + 1; if (nextFilterableIndex >= this.grid.filteringService.unpinnedFilterableColumns.length) { // next is not filter cell const dataRows = this.grid.rowList.toArray(); const hasRows = dataRows.length !== 0; const summaryRows = this.grid.summariesRowList.toArray(); const hasSummaries = summaryRows.length > 0 && summaryRows[0].summaryCells.length > 0; if (hasRows) { this.focusNextRow(dataRows[0].nativeElement, 0, this.grid, false); } else if (hasSummaries) { this.focusNextRow(summaryRows[0].nativeElement, 0, this.grid, true); } else { this.focusNext(0); } eventArgs.preventDefault(); } else { super.navigateNextFilterCell(column, eventArgs); } } performShiftTabKey(currentRowEl, selectedNode) { if (this.grid.rowInEditMode) { super.performShiftTabKey(currentRowEl, selectedNode); return; } const rowIndex = selectedNode.row; const visibleColumnIndex = selectedNode.column; const isSummary = selectedNode.isSummaryRow; if (visibleColumnIndex === 0 && rowIndex === 0 && this.grid.parent && !isSummary) { if (this.grid.allowFiltering && this.grid.filterMode === FilterMode.quickFilter) { this.moveFocusToFilterCell(); } else { const prevSiblingChild = this.getChildGridRowContainer().previousElementSibling; if (prevSiblingChild) { const gridElem = prevSiblingChild.querySelectorAll('igx-hierarchical-grid')[0]; this.performShiftTabIntoChild(gridElem, currentRowEl, rowIndex); } else { const selNode = { row: rowIndex, column: this.grid.parent.unpinnedColumns[this.grid.parent.unpinnedColumns.length - 1].visibleIndex }; this.navigateUp(currentRowEl, selNode); } } } else if (visibleColumnIndex === 0 && currentRowEl.previousElementSibling && currentRowEl.previousElementSibling.children[0].tagName.toLowerCase() === 'igx-child-grid-row') { const gridElem = this.getLastGridElem(currentRowEl.previousElementSibling); this.performShiftTabIntoChild(gridElem, currentRowEl, rowIndex); } else if (visibleColumnIndex === 0 && isSummary) { const lastRowIndex = this.grid.dataView.length - 1; if (lastRowIndex === -1) { // no child data if (this.grid.allowFiltering && this.grid.filterMode === FilterMode.quickFilter) { this.moveFocusToFilterCell(); } else { const selNode = { row: rowIndex, column: this.grid.parent.unpinnedColumns[this.grid.parent.unpinnedColumns.length - 1].visibleIndex }; this.navigateUp(currentRowEl, selNode); } } else if (!this.getIsChildAtIndex(lastRowIndex)) { super.goToLastCell(); } else { const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(lastRowIndex, true); const verticalScrollTop = this.grid.verticalScrollContainer.scrollPosition; if (verticalScrollTop === scrTopPosition || isNaN(scrTopPosition)) { const closestChild = this.getLastGridElem(this.grid.getRowByIndex(lastRowIndex).nativeElement.parentElement); this.performShiftTabIntoChild(closestChild, currentRowEl, rowIndex); } else { this.scrollGrid(this.grid, scrTopPosition - verticalScrollTop, () => { const closestChild = this.getLastGridElem(this.grid.getRowByIndex(lastRowIndex).nativeElement.parentElement); this.performShiftTabIntoChild(closestChild, currentRowEl, rowIndex); }); } } } else { super.performShiftTabKey(currentRowEl, selectedNode); } } getFocusableGrid() { return (isIE() && this.grid.rootGrid) ? this.grid.rootGrid : this.grid; } getLastGridElem(trContainer) { const children = trContainer.children; const closestChild = children[children.length - 1].children[0].children[0]; return closestChild; } performShiftTabIntoChild(gridElem, currentRowEl, rowIndex) { const childGridID = gridElem.getAttribute('id'); const childGrid = this.getChildGrid(childGridID, this.grid) || this.getChildGrid(childGridID, this.grid.parent); const lastIndex = childGrid.unpinnedColumns[childGrid.unpinnedColumns.length - 1].visibleIndex; const summaryRows = childGrid.summariesRowList.toArray(); if (summaryRows.length > 0 && summaryRows[0].summaryCells.length > 0) { // move focus to last summary row cell const summaryRow = summaryRows[0].nativeElement; this.focusPrevRow(summaryRow, lastIndex, childGrid, true, true); } else if (childGrid.rowList.toArray().length === 0 && childGrid.allowFiltering && childGrid.filterMode === FilterMode.quickFilter) { // move to filter cell childGrid.navigation.moveFocusToFilterCell(); } else if (childGrid.rowList.length === 0) { // move to prev child or parent row const prevChild = this.getSibling(childGrid); if (prevChild) { this.performShiftTabIntoChild(prevChild, currentRowEl, rowIndex); } else { const selNode = { row: rowIndex, column: this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex }; this.navigateUp(currentRowEl, selNode); } } else { // move to prev cell childGrid.navigation.goToLastCell(); } } getSibling(childGrid) { const prevChildRow = childGrid.childRow.nativeElement.previousElementSibling; if (prevChildRow) { return prevChildRow.children[0].children[0]; } return null; } focusNextChild(elem, visibleColumnIndex, grid) { const gridElem = elem.querySelector('igx-hierarchical-grid'); const childGridID = gridElem.getAttribute('id'); const childGrid = this.getChildGrid(childGridID, grid); if (childGrid.rowList.toArray().length === 0) { this.focusNext(visibleColumnIndex, childGrid); return; } // Update column index since the next child can have in general less columns than visibleColumnIndex value. const lastCellIndex = childGrid.unpinnedColumns[childGrid.unpinnedColumns.length - 1].visibleIndex; visibleColumnIndex = Math.min(lastCellIndex, visibleColumnIndex); if (childGrid.verticalScrollContainer.state.startIndex !== 0) { // scroll to top this.scrollGrid(childGrid, 'top', () => this.focusNextRow(elem, visibleColumnIndex, childGrid)); } else { this.focusNextRow(elem, visibleColumnIndex, childGrid); } } focusPrevChild(elem, visibleColumnIndex, grid) { const grids = []; const gridElems = Array.from(elem.querySelectorAll('igx-hierarchical-grid')); const childLevel = grid.childLayoutList.first.level; gridElems.forEach((hg) => { const parentRow = this.getClosestElemByTag(hg, 'igx-child-grid-row'); if (parentRow && parseInt(parentRow.getAttribute('data-level'), 10) === childLevel) { grids.push(hg); } }); const gridElem = grids[grids.length - 1]; const childGridID = gridElem.getAttribute('id'); const childGrid = this.getChildGrid(childGridID, grid); if (childGrid.rowList.toArray().length === 0) { this.focusPrev(visibleColumnIndex, childGrid); return; } // Update column index since the previous child can have in general less columns than visibleColumnIndex value. const lastCellIndex = childGrid.unpinnedColumns[childGrid.unpinnedColumns.length - 1].visibleIndex; visibleColumnIndex = Math.min(lastCellIndex, visibleColumnIndex); const isScrolledToBottom = this._isScrolledToBottom(childGrid); const lastIndex = childGrid.dataView.length - 1; if (!isScrolledToBottom) { // scroll to end this.scrollGrid(childGrid, 'bottom', () => this.focusPrevChild(elem, visibleColumnIndex, grid)); } else { const lastRowInChild = childGrid.getRowByIndex(lastIndex); const isChildGrid = lastRowInChild.nativeElement.nodeName.toLowerCase() === 'igx-child-grid-row'; if (isChildGrid) { this.focusPrevChild(lastRowInChild.nativeElement.parentNode, visibleColumnIndex, childGrid); } else { this.focusPrevRow(lastRowInChild.nativeElement, visibleColumnIndex, childGrid, true); } } } focusPrev(visibleColumnIndex, grid) { const currGrid = grid || this.grid; let parentContainer = this.getChildContainer(currGrid); let childRowContainer = this.getChildGridRowContainer(currGrid); const prevIsSiblingChild = !!childRowContainer.previousElementSibling; let prev = childRowContainer.previousElementSibling || parentContainer.previousElementSibling; if (prev) { if (prevIsSiblingChild) { this.focusPrevChild(prev, visibleColumnIndex, currGrid.parent); } else { this.focusPrevRow(prev, visibleColumnIndex, currGrid.parent); } } else { this.scrollGrid(currGrid.parent, 'prev', () => { parentContainer = this.getChildContainer(grid); childRowContainer = this.getChildGridRowContainer(grid); prev = childRowContainer.previousElementSibling || parentContainer.previousElementSibling; if (prevIsSiblingChild) { this.focusPrevChild(prev, visibleColumnIndex, currGrid.parent); } else { this.focusPrevRow(prev, visibleColumnIndex, currGrid.parent); } }); } } getNextParentInfo(grid) { // find next parent that is not at bottom let currGrid = grid.parent; let nextElem = this.getChildContainer(grid).nextElementSibling; while (!nextElem && currGrid.parent !== null) { nextElem = this.getChildContainer(currGrid).nextElementSibling; currGrid = currGrid.parent; } return { grid: currGrid, nextElement: nextElem }; } getNextScrollable(grid) { let currGrid = grid.parent; if (!currGrid) { return { grid: grid, prev: null }; } let nonScrollable = currGrid.verticalScrollContainer.scrollPosition === 0; let prev = grid; while (nonScrollable && currGrid.parent !== null) { prev = currGrid; currGrid = currGrid.parent; nonScrollable = currGrid.verticalScrollContainer.scrollPosition === 0; } return { grid: currGrid, prev: prev }; } focusNext(visibleColumnIndex, grid) { const currGrid = grid || this.grid; const parentInfo = this.getNextParentInfo(currGrid); const nextParentGrid = parentInfo.grid; let nextParentElem = parentInfo.nextElement; let childRowContainer = this.getChildGridRowContainer(currGrid); const nextIsSiblingChild = !!childRowContainer.nextElementSibling; let next = childRowContainer.nextElementSibling || nextParentElem; const verticalScroll = nextParentGrid.verticalScrollContainer.getScroll(); const parentState = nextParentGrid.verticalScrollContainer.state; const atLastChunk = parentState.startIndex + parentState.chunkSize === nextParentGrid.dataView.length; if (next) { if (nextIsSiblingChild) { this.focusNextChild(next, visibleColumnIndex, nextParentGrid); } else { this.focusNextRow(next, visibleColumnIndex, grid || nextParentGrid); } } else if (verticalScroll.scrollTop !== verticalScroll.scrollHeight - nextParentGrid.verticalScrollContainer.igxForContainerSize && !atLastChunk) { this.scrollGrid(nextParentGrid, 'next', () => { nextParentElem = parentInfo.nextElement; childRowContainer = this.getChildGridRowContainer(); next = childRowContainer.nextElementSibling || nextParentElem; if (next && nextIsSiblingChild) { this.focusNextChild(next, visibleColumnIndex, nextParentGrid); } else if (next) { this.focusNextRow(next, visibleColumnIndex, grid || nextParentGrid); } }); } } getNextScrollableDown(grid) { let currGrid = grid.parent; if (!currGrid) { return { grid: grid, prev: null }; } let scrollTop = currGrid.verticalScrollContainer.scrollPosition; let scrollHeight = currGrid.verticalScrollContainer.getScroll().scrollHeight; let nonScrollable = scrollHeight === 0 || Math.round(scrollTop + currGrid.verticalScrollContainer.igxForContainerSize) === scrollHeight; let prev = grid; while (nonScrollable && currGrid.parent !== null) { prev = currGrid; currGrid = currGrid.parent; scrollTop = currGrid.verticalScrollContainer.scrollPosition; scrollHeight = currGrid.verticalScrollContainer.getScroll().scrollHeight; nonScrollable = scrollHeight === 0 || Math.round(scrollTop + currGrid.verticalScrollContainer.igxForContainerSize) === scrollHeight; } return { grid: currGrid, prev: prev }; } _getMinBottom(grid) { let currGrid = grid; let bottom = currGrid.tbody.nativeElement.getBoundingClientRect().bottom; while (currGrid.parent) { currGrid = currGrid.parent; bottom = Math.min(bottom, currGrid.tbody.nativeElement.getBoundingClientRect().bottom); } return bottom; } _getMaxTop(grid) { let currGrid = grid; let top = currGrid.tbody.nativeElement.getBoundingClientRect().top; while (currGrid.parent) { currGrid = currGrid.parent; top = Math.max(top, currGrid.tbody.nativeElement.getBoundingClientRect().top); } return top; } focusNextRow(elem, visibleColumnIndex, grid, isSummary) { const cellSelector = this.getCellSelector(visibleColumnIndex, isSummary); if (grid.navigation.isColumnFullyVisible(visibleColumnIndex)) { const cell = elem.querySelector(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); const closestScrollableGrid = this.getNextScrollableDown(grid).grid; // const diff = cell.getBoundingClientRect().bottom - grid.rootGrid.tbody.nativeElement.getBoundingClientRect().bottom; const gridBottom = this._getMinBottom(grid); const diff = cell.getBoundingClientRect().bottom - gridBottom; const inView = diff <= 0; const scrollTop = closestScrollableGrid.verticalScrollContainer.scrollPosition; const scrollHeight = closestScrollableGrid.verticalScrollContainer.getScroll().scrollHeight; const canScroll = !(scrollHeight === 0 || Math.round(scrollTop + closestScrollableGrid.verticalScrollContainer.igxForContainerSize) === scrollHeight); if (!inView && canScroll) { this.scrollGrid(closestScrollableGrid, diff, () => cell.focus({ preventScroll: true })); } else { cell.focus({ preventScroll: true }); } } else { const cellElem = elem.querySelector(`${cellSelector}`); const rowIndex = parseInt(cellElem.getAttribute('data-rowindex'), 10); grid.navigation.performHorizontalScrollToCell(rowIndex, visibleColumnIndex); } } focusPrevRow(elem, visibleColumnIndex, grid, inChild, isSummary) { if (grid.navigation.isColumnFullyVisible(visibleColumnIndex)) { const cellSelector = this.getCellSelector(visibleColumnIndex, isSummary); const cells = elem.querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); let cell = cells[cells.length - 1]; const rIndex = parseInt(elem.getAttribute('data-rowindex'), 10); const scrGrid = grid.verticalScrollContainer.scrollPosition !== 0 ? grid : this.getNextScrollable(grid).grid; const topGrid = scrGrid.tbody.nativeElement.getBoundingClientRect().top > grid.rootGrid.tbody.nativeElement.getBoundingClientRect().top ? scrGrid : grid.rootGrid; const gridTop = this._getMaxTop(grid); const scrTop = scrGrid.verticalScrollContainer.scrollPosition; const diff = cell.getBoundingClientRect().bottom - cell.offsetHeight - gridTop; if (scrTop !== 0 && diff < 0 && !inChild) { this.scrollGrid(scrGrid, diff, () => { const el = !isSummary ? grid.navigation.getRowByIndex(rIndex) : elem; cell = el.querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`)[0]; cell.focus({ preventScroll: true }); }); } else if (diff < 0 && inChild) { this.scrollGrid(topGrid, diff, () => { cell.focus({ preventScroll: true }); }); } else { cell.focus({ preventScroll: true }); } } else { this.horizontalScrollGridToIndex(grid, visibleColumnIndex, () => { this.focusPrevRow(elem, visibleColumnIndex, grid, inChild, isSummary); }); } } horizontalScrollGridToIndex(grid, visibleColumnIndex, callBackFunc) { const unpinnedIndex = this.getColumnUnpinnedIndex(visibleColumnIndex); grid.parentVirtDir.onChunkLoad .pipe(first()) .subscribe(callBackFunc); if (grid.dataRowList.length > 0) { grid.dataRowList.first.virtDirRow.scrollTo(unpinnedIndex); } else { grid.headerContainer.scrollTo(unpinnedIndex); } } scrollGrid(grid, target, callBackFunc) { this.getFocusableGrid().nativeElement.focus({ preventScroll: true }); requestAnimationFrame(() => { if (typeof target === 'number') { grid.verticalScrollContainer.addScrollTop(target); } else { switch (target) { case 'top': grid.verticalScrollContainer.scrollTo(0); break; case 'bottom': grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); break; case 'next': grid.verticalScrollContainer.scrollNext(); break; case 'prev': grid.verticalScrollContainer.scrollPrev(); break; } } grid.verticalScrollContainer.onChunkLoad .pipe(first()) .subscribe(callBackFunc); }); } _navigateUpInChild(rowElement, currentRowIndex, visibleColumnIndex) { const prevElem = rowElement.previousElementSibling; const scrollable = this.getNextScrollable(this.grid); const grid = scrollable.grid; const scrTop = grid.verticalScrollContainer.scrollPosition; const containerTop = scrollable.prev.nativeElement.parentNode.parentNode.parentNode.parentNode; const top = parseInt(containerTop.style.top, 10); if (scrTop !== 0 && top < 0) { this.scrollGrid(grid, -prevElem.offsetHeight, () => super.navigateUp(rowElement, { row: currentRowIndex, column: visibleColumnIndex })); } else { super.navigateUp(rowElement, { row: currentRowIndex, column: visibleColumnIndex }); } } _navigateDownInChild(rowElement, currentRowIndex, visibleColumnIndex) { const nextElem = rowElement.nextElementSibling; const childContainer = this.grid.nativeElement.parentNode.parentNode; const diff = childContainer.getBoundingClientRect().bottom - this.grid.rootGrid.nativeElement.getBoundingClientRect().bottom; const endIsVisible = diff < 0; const scrollable = this.getNextScrollableDown(this.grid); const grid = scrollable.grid; if (!endIsVisible) { this.scrollGrid(grid, nextElem.offsetHeight, () => super.navigateDown(rowElement, { row: currentRowIndex, column: visibleColumnIndex })); } else { super.navigateDown(rowElement, { row: currentRowIndex, column: visibleColumnIndex }); } } getNextRowByIndex(nextIndex) { return this.grid.dataRowList.find(element => element.index === nextIndex).element.nativeElement; } }; IgxHierarchicalGridNavigationService = __decorate([ Injectable() ], IgxHierarchicalGridNavigationService); export { IgxHierarchicalGridNavigationService }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGllcmFyY2hpY2FsLWdyaWQtbmF2aWdhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vaWduaXRldWktYW5ndWxhci8iLCJzb3VyY2VzIjpbImxpYi9ncmlkcy9oaWVyYXJjaGljYWwtZ3JpZC9oaWVyYXJjaGljYWwtZ3JpZC1uYXZpZ2F0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXRFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV2QyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDeEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRTdDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHM0MsSUFBYSxvQ0FBb0MsR0FBakQsTUFBYSxvQ0FBcUMsU0FBUSx3QkFBd0I7SUFHcEUsZUFBZSxDQUFDLFlBQXFCLEVBQUUsU0FBUyxHQUFHLEtBQUs7UUFDOUQsT0FBTyxTQUFTLENBQUMsQ0FBQyxDQUFDLHVCQUF1QixDQUFDLENBQUMsQ0FBQyw0QkFBNEIsQ0FBQztJQUM5RSxDQUFDO0lBRVMsY0FBYztRQUNwQixPQUFPLDJCQUEyQixDQUFDO0lBQ3ZDLENBQUM7SUFFUyxhQUFhLENBQUMsS0FBSztRQUN6QixNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBUSxDQUFDO1FBQzlDLE9BQU8sR0FBRyxDQUFDO0lBQ2YsQ0FBQztJQUVPLGlCQUFpQixDQUFDLElBQUs7UUFDM0IsTUFBTSxRQUFRLEdBQUcsSUFBSSxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDbkMsT0FBTyxRQUFRLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDO0lBQ25FLENBQUM7SUFFTyx3QkFBd0IsQ0FBQyxJ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