UNPKG

igniteui-angular

Version:

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

1,169 lines • 139 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { IgxGridNavigationService } from '../grid-navigation.service'; import { first } from 'rxjs/operators'; import { FilterMode } from '../grid-base.component'; export class IgxHierarchicalGridNavigationService extends IgxGridNavigationService { /** * @protected * @param {?=} visibleIndex * @param {?=} isSummary * @return {?} */ getCellSelector(visibleIndex, isSummary = false) { return isSummary ? 'igx-grid-summary-cell' : 'igx-hierarchical-grid-cell'; } /** * @protected * @return {?} */ getRowSelector() { return 'igx-hierarchical-grid-row'; } /** * @protected * @param {?} index * @return {?} */ getRowByIndex(index) { /** @type {?} */ const selector = this.getRowSelector(); /** @type {?} */ const rows = Array.from(this.grid.nativeElement.querySelectorAll(`${selector}[data-rowindex="${index}"]`)); /** @type {?} */ let row; rows.forEach((r) => { /** @type {?} */ const parentGrid = this.getClosestElemByTag(r, 'igx-hierarchical-grid'); if (parentGrid && parentGrid.getAttribute('id') === this.grid.id) { row = r; } }); return row; } /** * @private * @param {?=} grid * @return {?} */ getChildContainer(grid) { /** @type {?} */ const currGrid = grid || this.grid; return currGrid.nativeElement.parentNode.parentNode.parentNode; } /** * @private * @param {?=} grid * @return {?} */ getChildGridRowContainer(grid) { /** @type {?} */ const currGrid = grid || this.grid; return currGrid.nativeElement.parentNode.parentNode; } /** * @private * @param {?} childGridID * @param {?} grid * @return {?} */ getChildGrid(childGridID, grid) { /** @type {?} */ const cgrid = grid.hgridAPI.getChildGrids(true).filter((g) => g.id === childGridID)[0]; return cgrid; } /** * @private * @param {?} grid * @return {?} */ _isScrolledToBottom(grid) { /** @type {?} */ const scrollTop = grid.verticalScrollContainer.getVerticalScroll().scrollTop; /** @type {?} */ const scrollHeight = grid.verticalScrollContainer.getVerticalScroll().scrollHeight; return scrollHeight === 0 || Math.round(scrollTop + grid.verticalScrollContainer.igxForContainerSize) === scrollHeight; } /** * @private * @param {?} index * @return {?} */ getIsChildAtIndex(index) { return this.grid.isChildGridRecord(this.grid.verticalScrollContainer.igxForOf[index]); } /** * @param {?} rowIndex * @param {?} visibleColumnIndex * @param {?=} isSummary * @return {?} */ getCellElementByVisibleIndex(rowIndex, visibleColumnIndex, isSummary = false) { /** @type {?} */ const cellSelector = this.getCellSelector(visibleColumnIndex, isSummary); if (isSummary) { /** @type {?} */ const summaryRow = this.grid.summariesRowList.toArray()[0].nativeElement; return summaryRow.querySelector(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); } /** @type {?} */ const row = this.getRowByIndex(rowIndex); return row.querySelector(`${cellSelector}[data-rowindex="${rowIndex}"][data-visibleIndex="${visibleColumnIndex}"]`); } /** * @param {?} rowElement * @param {?} currentRowIndex * @param {?} visibleColumnIndex * @return {?} */ navigateUp(rowElement, currentRowIndex, visibleColumnIndex) { /** @type {?} */ const prevElem = rowElement.previousElementSibling; if (prevElem) { /** @type {?} */ const nodeName = prevElem.children[0].nodeName.toLowerCase(); /** @type {?} */ 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, currentRowIndex, visibleColumnIndex); } } } else if (currentRowIndex !== 0) { // handle scenario when prev item is child grid but is not yet in view /** @type {?} */ const isPrevChildGrid = this.getIsChildAtIndex(currentRowIndex - 1); if (!isPrevChildGrid) { super.navigateUp(rowElement, currentRowIndex, visibleColumnIndex); } else { this.scrollGrid(this.grid, -rowElement.offsetHeight, () => { rowElement = this.getRowByIndex(currentRowIndex); this.navigateUp(rowElement, currentRowIndex, visibleColumnIndex); }); } } else if (this.grid.parent !== null && currentRowIndex === 0) { // move to prev row in sibling layout or parent this.focusPrev(visibleColumnIndex); } } /** * @param {?} rowElement * @param {?} currentRowIndex * @param {?} visibleColumnIndex * @return {?} */ navigateDown(rowElement, currentRowIndex, visibleColumnIndex) { /** @type {?} */ const nextElem = rowElement.nextElementSibling; if (nextElem) { // next elem is in DOM /** @type {?} */ const nodeName = nextElem.children[0].nodeName.toLowerCase(); /** @type {?} */ 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, currentRowIndex, visibleColumnIndex); } } } else if (currentRowIndex !== this.grid.verticalScrollContainer.igxForOf.length - 1) { // scroll next in view super.navigateDown(rowElement, currentRowIndex, visibleColumnIndex); } else if (this.grid.parent !== null && currentRowIndex === this.grid.verticalScrollContainer.igxForOf.length - 1) { // move to next row in sibling layout or in parent this.focusNext(visibleColumnIndex); } } /** * @param {?} visibleColumnIndex * @return {?} */ navigateTop(visibleColumnIndex) { if (this.grid.parent !== null) { // navigating in child /** @type {?} */ const verticalScroll = this.grid.verticalScrollContainer.getVerticalScroll(); /** @type {?} */ const cellSelector = this.getCellSelector(visibleColumnIndex); if (verticalScroll.scrollTop === 0) { this._focusScrollCellInView(visibleColumnIndex); } else { this.scrollGrid(this.grid, 'top', () => { /** @type {?} */ const cells = this.grid.nativeElement.querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); if (cells.length > 0) { this._focusScrollCellInView(visibleColumnIndex); } }); } } else { super.navigateTop(visibleColumnIndex); } } /** * @param {?} visibleColumnIndex * @return {?} */ navigateBottom(visibleColumnIndex) { // handle scenario where last index is child grid // in that case focus cell in last data row /** @type {?} */ const lastIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; if (this.getIsChildAtIndex(lastIndex)) { /** @type {?} */ const targetIndex = lastIndex - 1; /** @type {?} */ const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(targetIndex, true); /** @type {?} */ const verticalScroll = this.grid.verticalScrollContainer.getVerticalScroll(); /** @type {?} */ const cellSelector = this.getCellSelector(visibleColumnIndex); if (verticalScroll.scrollTop === scrTopPosition) { /** @type {?} */ const cells = this.getRowByIndex(targetIndex).querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); cells[cells.length - 1].focus(); } else { this.scrollGrid(this.grid, scrTopPosition - verticalScroll.scrollTop, () => { /** @type {?} */ const cells = this.getRowByIndex(targetIndex).querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); if (cells.length > 0) { cells[cells.length - 1].focus(); } }); } } else { super.navigateBottom(visibleColumnIndex); } } /** * @return {?} */ goToLastCell() { // handle scenario where last index is child grid // in that case focus last cell in last data row /** @type {?} */ const lastIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; if (this.getIsChildAtIndex(lastIndex)) { /** @type {?} */ const targetIndex = lastIndex - 1; /** @type {?} */ const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(targetIndex, true); /** @type {?} */ const verticalScroll = this.grid.verticalScrollContainer.getVerticalScroll(); if (verticalScroll.scrollTop === scrTopPosition) { this.onKeydownEnd(targetIndex); } else { this.scrollGrid(this.grid, scrTopPosition - verticalScroll.scrollTop, () => { this.onKeydownEnd(targetIndex); }); } } else { super.goToLastCell(); } } /** * @param {?} rowIndex * @param {?=} isSummary * @return {?} */ 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 /** @type {?} */ const childContainer = this.grid.nativeElement.parentNode.parentNode; /** @type {?} */ const diffBottom = childContainer.getBoundingClientRect().bottom - this.grid.rootGrid.nativeElement.getBoundingClientRect().bottom; /** @type {?} */ const row = this.grid.getRowByIndex(rowIndex).element.nativeElement; /** @type {?} */ const rowBottom = row.getBoundingClientRect().bottom; /** @type {?} */ const rowIsVisible = rowBottom <= this.grid.rootGrid.tbody.nativeElement.getBoundingClientRect().bottom; /** @type {?} */ const gridTop = this._getMaxTop(this.grid); /** @type {?} */ const diffTop = row.getBoundingClientRect().bottom - row.offsetHeight - gridTop; /** @type {?} */ const endIsVisible = diffBottom <= 0; /** @type {?} */ const topVisible = diffTop >= 0; if (!endIsVisible && !rowIsVisible) { this.scrollGrid(this.grid.parent, diffBottom, () => super.onKeydownEnd(rowIndex)); } else if (!topVisible) { /** @type {?} */ const scrGrid = this.grid.verticalScrollContainer.getVerticalScroll().scrollTop !== 0 ? this.grid : this.getNextScrollable(this.grid).grid; /** @type {?} */ 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); } } /** * @return {?} */ goToFirstCell() { /** @type {?} */ const verticalScroll = this.grid.verticalScrollContainer.getVerticalScroll(); /** @type {?} */ const horizontalScroll = this.grid.dataRowList.first.virtDirRow.getHorizontalScroll(); 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(); } } /** * @param {?} currentRowEl * @param {?} rowIndex * @param {?} visibleColumnIndex * @param {?=} isSummaryRow * @return {?} */ performTab(currentRowEl, rowIndex, visibleColumnIndex, isSummaryRow = false) { /** @type {?} */ const summaryRows = this.grid.summariesRowList.toArray(); /** @type {?} */ const hasSummaries = summaryRows.length > 0; /** @type {?} */ const isLastDataRow = rowIndex === this.grid.verticalScrollContainer.igxForOf.length - 1; /** @type {?} */ const nextIsDataRow = this.grid.dataRowList.find(row => row.index === rowIndex + 1); /** @type {?} */ const isLastColumn = this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === visibleColumnIndex; /** @type {?} */ const isLastSummaryRow = hasSummaries && isSummaryRow; /** @type {?} */ const nextIndex = rowIndex + 1; /** @type {?} */ const virt = this.grid.verticalScrollContainer; /** @type {?} */ 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 /** @type {?} */ const childContainer = this.getChildGridRowContainer(); /** @type {?} */ const nextIsSiblingChild = this.grid.parent ? !!childContainer.nextElementSibling : false; if (nextIsSiblingChild) { this.focusNextChildDOMElem(childContainer, this.grid.parent); } else if (isNextChild) { /** @type {?} */ 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 { this.navigateDown(currentRowEl, rowIndex, 0); } } else if (isLastSummaryRow && isLastColumn && this.grid.parent) { // navigating in child summary, next is parent summary or next parent row /** @type {?} */ const parent = this.grid.parent; /** @type {?} */ const parentHasSummary = parent.summariesRowList.toArray().length > 0; /** @type {?} */ const parentRowIndex = parseInt(this.getClosestElemByTag(currentRowEl, 'igx-child-grid-row').parentNode.getAttribute('data-rowindex'), 10); /** @type {?} */ const isLastRowInParent = parent.verticalScrollContainer.igxForOf.length - 1 === parentRowIndex; // check if next is sibling /** @type {?} */ const childRowContainer = this.getChildGridRowContainer(this.grid); /** @type {?} */ const nextIsSiblingChild = !!childRowContainer.nextElementSibling; if (isLastRowInParent && parentHasSummary && !nextIsSiblingChild) { // next is parent summary /** @type {?} */ const parentSummary = parent.summariesRowList.toArray()[0].nativeElement; parent.navigation.focusNextRow(parentSummary, 0, this.grid.rootGrid, true); } else { // next is sibling or parent this.focusNext(0); } } 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, rowIndex, visibleColumnIndex, isSummaryRow); } } /** * @private * @param {?} currentRowEl * @param {?} grid * @return {?} */ focusNextChildDOMElem(currentRowEl, grid) { /** @type {?} */ const gridElem = currentRowEl.nextElementSibling.querySelector('igx-hierarchical-grid'); /** @type {?} */ const childGridID = gridElem.getAttribute('id'); /** @type {?} */ const childGrid = this.getChildGrid(childGridID, grid); if (childGrid.allowFiltering && childGrid.filterMode === FilterMode.quickFilter) { childGrid.navigation.moveFocusToFilterCell(true); return; } this.focusNextChild(currentRowEl.nextElementSibling, 0, grid); } /** * @param {?} column * @param {?} eventArgs * @return {?} */ navigatePrevFilterCell(column, eventArgs) { if (column.visibleIndex === 0 && this.grid.parent) { eventArgs.preventDefault(); /** @type {?} */ let targetGrid = this.grid.parent; /** @type {?} */ const prevSiblingChild = this.getChildGridRowContainer().previousElementSibling; if (prevSiblingChild) { /** @type {?} */ 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); } } /** * @param {?} column * @param {?} eventArgs * @return {?} */ navigateNextFilterCell(column, eventArgs) { /** @type {?} */ const cols = this.grid.filteringService.unpinnedFilterableColumns; /** @type {?} */ const nextFilterableIndex = cols.indexOf(column) + 1; if (nextFilterableIndex >= this.grid.filteringService.unpinnedFilterableColumns.length) { // next is not filter cell /** @type {?} */ const dataRows = this.grid.rowList.toArray(); /** @type {?} */ const hasRows = dataRows.length !== 0; /** @type {?} */ const summaryRows = this.grid.summariesRowList.toArray(); /** @type {?} */ 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); } } /** * @param {?} currentRowEl * @param {?} rowIndex * @param {?} visibleColumnIndex * @param {?=} isSummary * @return {?} */ performShiftTabKey(currentRowEl, rowIndex, visibleColumnIndex, isSummary = false) { if (visibleColumnIndex === 0 && rowIndex === 0 && this.grid.parent && !isSummary) { if (this.grid.allowFiltering && this.grid.filterMode === FilterMode.quickFilter) { this.moveFocusToFilterCell(); } else { /** @type {?} */ const prevSiblingChild = this.getChildGridRowContainer().previousElementSibling; if (prevSiblingChild) { /** @type {?} */ const gridElem = prevSiblingChild.querySelectorAll('igx-hierarchical-grid')[0]; this.performShiftTabIntoChild(gridElem, currentRowEl, rowIndex); } else { this.navigateUp(currentRowEl, rowIndex, this.grid.parent.unpinnedColumns[this.grid.parent.unpinnedColumns.length - 1].visibleIndex); } } } else if (visibleColumnIndex === 0 && currentRowEl.previousElementSibling && currentRowEl.previousElementSibling.children[0].tagName.toLowerCase() === 'igx-child-grid-row') { /** @type {?} */ const gridElem = this.getLastGridElem(currentRowEl.previousElementSibling); this.performShiftTabIntoChild(gridElem, currentRowEl, rowIndex); } else if (visibleColumnIndex === 0 && isSummary) { /** @type {?} */ const lastRowIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; if (lastRowIndex === -1) { // no child data if (this.grid.allowFiltering && this.grid.filterMode === FilterMode.quickFilter) { this.moveFocusToFilterCell(); } else { this.navigateUp(currentRowEl, rowIndex, this.grid.parent.unpinnedColumns[this.grid.parent.unpinnedColumns.length - 1].visibleIndex); } } else if (!this.getIsChildAtIndex(lastRowIndex)) { super.goToLastCell(); } else { /** @type {?} */ const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(lastRowIndex, true); /** @type {?} */ const verticalScroll = this.grid.verticalScrollContainer.getVerticalScroll(); if (verticalScroll.scrollTop === scrTopPosition || isNaN(scrTopPosition)) { /** @type {?} */ const closestChild = this.getLastGridElem(this.grid.getRowByIndex(lastRowIndex).nativeElement.parentElement); this.performShiftTabIntoChild(closestChild, currentRowEl, rowIndex); } else { this.scrollGrid(this.grid, scrTopPosition - verticalScroll.scrollTop, () => { /** @type {?} */ const closestChild = this.getLastGridElem(this.grid.getRowByIndex(lastRowIndex).nativeElement.parentElement); this.performShiftTabIntoChild(closestChild, currentRowEl, rowIndex); }); } } } else { super.performShiftTabKey(currentRowEl, rowIndex, visibleColumnIndex, isSummary); } } /** * @private * @param {?} trContainer * @return {?} */ getLastGridElem(trContainer) { /** @type {?} */ const children = trContainer.children; /** @type {?} */ const closestChild = children[children.length - 1].children[0].children[0]; return closestChild; } /** * @private * @param {?} gridElem * @param {?} currentRowEl * @param {?} rowIndex * @return {?} */ performShiftTabIntoChild(gridElem, currentRowEl, rowIndex) { /** @type {?} */ const childGridID = gridElem.getAttribute('id'); /** @type {?} */ const childGrid = this.getChildGrid(childGridID, this.grid) || this.getChildGrid(childGridID, this.grid.parent); /** @type {?} */ const lastIndex = childGrid.unpinnedColumns[childGrid.unpinnedColumns.length - 1].visibleIndex; /** @type {?} */ const summaryRows = childGrid.summariesRowList.toArray(); if (summaryRows.length > 0 && summaryRows[0].summaryCells.length > 0) { // move focus to last summary row cell /** @type {?} */ 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 { // move to next cell this.navigateUp(currentRowEl, rowIndex, lastIndex); } } /** * @private * @param {?} visibleColumnIndex * @return {?} */ _focusScrollCellInView(visibleColumnIndex) { /** @type {?} */ const cellSelector = this.getCellSelector(visibleColumnIndex); /** @type {?} */ const cells = this.grid.nativeElement.querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); /** @type {?} */ const cell = cells[0]; /** @type {?} */ const childContainer = this.grid.nativeElement.parentNode.parentNode; /** @type {?} */ const scrTop = this.grid.parent.verticalScrollContainer.getVerticalScroll().scrollTop; /** @type {?} */ const dc = childContainer.parentNode.parentNode; /** @type {?} */ const scrWith = parseInt(dc.style.top, 10); if (scrTop === 0 || scrWith === 0) { // cell is in view cell.focus({ preventScroll: true }); } else { // scroll parent so that cell is in view this.scrollGrid(this.grid.parent, scrWith, () => cell.focus({ preventScroll: true })); } } /** * @private * @param {?} elem * @param {?} visibleColumnIndex * @param {?} grid * @return {?} */ focusNextChild(elem, visibleColumnIndex, grid) { /** @type {?} */ const gridElem = elem.querySelector('igx-hierarchical-grid'); /** @type {?} */ const childGridID = gridElem.getAttribute('id'); /** @type {?} */ 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. /** @type {?} */ 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); } } /** * @private * @param {?} elem * @param {?} visibleColumnIndex * @param {?} grid * @return {?} */ focusPrevChild(elem, visibleColumnIndex, grid) { /** @type {?} */ const grids = []; /** @type {?} */ const gridElems = Array.from(elem.querySelectorAll('igx-hierarchical-grid')); /** @type {?} */ const childLevel = grid.childLayoutList.first.level; gridElems.forEach((hg) => { /** @type {?} */ const parentRow = this.getClosestElemByTag(hg, 'igx-child-grid-row'); if (parentRow && parseInt(parentRow.getAttribute('data-level'), 10) === childLevel) { grids.push(hg); } }); /** @type {?} */ const gridElem = grids[grids.length - 1]; /** @type {?} */ const childGridID = gridElem.getAttribute('id'); /** @type {?} */ 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. /** @type {?} */ const lastCellIndex = childGrid.unpinnedColumns[childGrid.unpinnedColumns.length - 1].visibleIndex; visibleColumnIndex = Math.min(lastCellIndex, visibleColumnIndex); /** @type {?} */ const isScrolledToBottom = this._isScrolledToBottom(childGrid); /** @type {?} */ const lastIndex = childGrid.verticalScrollContainer.igxForOf.length - 1; if (!isScrolledToBottom) { // scroll to end this.scrollGrid(childGrid, 'bottom', () => this.focusPrevChild(elem, visibleColumnIndex, grid)); } else { /** @type {?} */ const lastRowInChild = childGrid.getRowByIndex(lastIndex); /** @type {?} */ 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); } } } /** * @private * @param {?} visibleColumnIndex * @param {?=} grid * @return {?} */ focusPrev(visibleColumnIndex, grid) { /** @type {?} */ const currGrid = grid || this.grid; /** @type {?} */ let parentContainer = this.getChildContainer(currGrid); /** @type {?} */ let childRowContainer = this.getChildGridRowContainer(currGrid); /** @type {?} */ const prevIsSiblingChild = !!childRowContainer.previousElementSibling; /** @type {?} */ 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); } }); } } /** * @private * @param {?} grid * @return {?} */ getNextParentInfo(grid) { // find next parent that is not at bottom /** @type {?} */ let currGrid = grid.parent; /** @type {?} */ let nextElem = this.getChildContainer(grid).nextElementSibling; while (!nextElem && currGrid.parent !== null) { nextElem = this.getChildContainer(currGrid).nextElementSibling; currGrid = currGrid.parent; } return { grid: currGrid, nextElement: nextElem }; } /** * @private * @param {?} grid * @return {?} */ getNextScrollable(grid) { /** @type {?} */ let currGrid = grid.parent; if (!currGrid) { return { grid: grid, prev: null }; } /** @type {?} */ let nonScrollable = currGrid.verticalScrollContainer.getVerticalScroll().scrollTop === 0; /** @type {?} */ let prev = grid; while (nonScrollable && currGrid.parent !== null) { prev = currGrid; currGrid = currGrid.parent; nonScrollable = currGrid.verticalScrollContainer.getVerticalScroll().scrollTop === 0; } return { grid: currGrid, prev: prev }; } /** * @private * @param {?} visibleColumnIndex * @param {?=} grid * @return {?} */ focusNext(visibleColumnIndex, grid) { /** @type {?} */ const currGrid = grid || this.grid; /** @type {?} */ const parentInfo = this.getNextParentInfo(currGrid); /** @type {?} */ const nextParentGrid = parentInfo.grid; /** @type {?} */ let nextParentElem = parentInfo.nextElement; /** @type {?} */ let childRowContainer = this.getChildGridRowContainer(currGrid); /** @type {?} */ const nextIsSiblingChild = !!childRowContainer.nextElementSibling; /** @type {?} */ let next = childRowContainer.nextElementSibling || nextParentElem; /** @type {?} */ const verticalScroll = nextParentGrid.verticalScrollContainer.getVerticalScroll(); 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) { 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); } }); } } /** * @private * @param {?} grid * @return {?} */ getNextScrollableDown(grid) { /** @type {?} */ let currGrid = grid.parent; if (!currGrid) { return { grid: grid, prev: null }; } /** @type {?} */ let scrollTop = currGrid.verticalScrollContainer.getVerticalScroll().scrollTop; /** @type {?} */ let scrollHeight = currGrid.verticalScrollContainer.getVerticalScroll().scrollHeight; /** @type {?} */ let nonScrollable = scrollHeight === 0 || Math.round(scrollTop + currGrid.verticalScrollContainer.igxForContainerSize) === scrollHeight; /** @type {?} */ let prev = grid; while (nonScrollable && currGrid.parent !== null) { prev = currGrid; currGrid = currGrid.parent; scrollTop = currGrid.verticalScrollContainer.getVerticalScroll().scrollTop; scrollHeight = currGrid.verticalScrollContainer.getVerticalScroll().scrollHeight; nonScrollable = scrollHeight === 0 || Math.round(scrollTop + currGrid.verticalScrollContainer.igxForContainerSize) === scrollHeight; } return { grid: currGrid, prev: prev }; } /** * @private * @param {?} grid * @return {?} */ _getMinBottom(grid) { /** @type {?} */ let currGrid = grid; /** @type {?} */ let bottom = currGrid.tbody.nativeElement.getBoundingClientRect().bottom; while (currGrid.parent) { currGrid = currGrid.parent; bottom = Math.min(bottom, currGrid.tbody.nativeElement.getBoundingClientRect().bottom); } return bottom; } /** * @private * @param {?} grid * @return {?} */ _getMaxTop(grid) { /** @type {?} */ let currGrid = grid; /** @type {?} */ let top = currGrid.tbody.nativeElement.getBoundingClientRect().top; while (currGrid.parent) { currGrid = currGrid.parent; top = Math.max(top, currGrid.tbody.nativeElement.getBoundingClientRect().top); } return top; } /** * @private * @param {?} elem * @param {?} visibleColumnIndex * @param {?} grid * @param {?=} isSummary * @return {?} */ focusNextRow(elem, visibleColumnIndex, grid, isSummary) { /** @type {?} */ const cellSelector = this.getCellSelector(visibleColumnIndex, isSummary); if (grid.navigation.isColumnFullyVisible(visibleColumnIndex) && grid.navigation.isColumnLeftFullyVisible(visibleColumnIndex)) { /** @type {?} */ const cell = elem.querySelector(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); /** @type {?} */ const closestScrollableGrid = this.getNextScrollableDown(grid).grid; // const diff = cell.getBoundingClientRect().bottom - grid.rootGrid.tbody.nativeElement.getBoundingClientRect().bottom; /** @type {?} */ const gridBottom = this._getMinBottom(grid); /** @type {?} */ const diff = cell.getBoundingClientRect().bottom - gridBottom; /** @type {?} */ const inView = diff <= 0; /** @type {?} */ const scrollTop = closestScrollableGrid.verticalScrollContainer.getVerticalScroll().scrollTop; /** @type {?} */ const scrollHeight = closestScrollableGrid.verticalScrollContainer.getVerticalScroll().scrollHeight; /** @type {?} */ 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 { /** @type {?} */ const cellElem = elem.querySelector(`${cellSelector}`); /** @type {?} */ const rowIndex = parseInt(cellElem.getAttribute('data-rowindex'), 10); grid.navigation.performHorizontalScrollToCell(rowIndex, visibleColumnIndex); } } /** * @private * @param {?} elem * @param {?} visibleColumnIndex * @param {?} grid * @param {?=} inChild * @param {?=} isSummary * @return {?} */ focusPrevRow(elem, visibleColumnIndex, grid, inChild, isSummary) { if (grid.navigation.isColumnFullyVisible(visibleColumnIndex) && grid.navigation.isColumnLeftFullyVisible(visibleColumnIndex)) { /** @type {?} */ const cellSelector = this.getCellSelector(visibleColumnIndex, isSummary); /** @type {?} */ const cells = elem.querySelectorAll(`${cellSelector}[data-visibleIndex="${visibleColumnIndex}"]`); /** @type {?} */ let cell = cells[cells.length - 1]; /** @type {?} */ const rIndex = parseInt(elem.getAttribute('data-rowindex'), 10); /** @type {?} */ const scrGrid = grid.verticalScrollContainer.getVerticalScroll().scrollTop !== 0 ? grid : this.getNextScrollable(grid).grid; /** @type {?} */ const topGrid = scrGrid.tbody.nativeElement.getBoundingClientRect().top > grid.rootGrid.tbody.nativeElement.getBoundingClientRect().top ? scrGrid : grid.rootGrid; /** @type {?} */ const gridTop = this._getMaxTop(grid); /** @type {?} */ const scrTop = scrGrid.verticalScrollContainer.getVerticalScroll().scrollTop; /** @type {?} */ const diff = cell.getBoundingClientRect().bottom - cell.offsetHeight - gridTop; if (scrTop !== 0 && diff < 0 && !inChild) { this.scrollGrid(scrGrid, diff, () => { /** @type {?} */ 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); }); } } /** * @private * @param {?} grid * @param {?} visibleColumnIndex * @param {?} callBackFunc * @return {?} */ horizontalScrollGridToIndex(grid, visibleColumnIndex, callBackFunc) { /** @type {?} */ const unpinnedIndex = this.getColumnUnpinnedIndex(visibleColumnIndex); grid.parentVirtDir.onChunkLoad .pipe(first()) .subscribe(callBackFunc); grid.dataRowList.toArray()[0].virtDirRow.scrollTo(unpinnedIndex); } /** * @private * @param {?} grid * @param {?} target * @param {?} callBackFunc * @return {?} */ scrollGrid(grid, target, callBackFunc) { grid.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.verticalScrollContainer.igxForOf.length - 1); break; case 'next': grid.verticalScrollContainer.scrollNext(); break; case 'prev': grid.verticalScrollContainer.scrollPrev(); break; } } grid.verticalScrollContainer.onChunkLoad .pipe(first()) .subscribe(callBackFunc); }); } /** * @private * @param {?} rowElement * @param {?} currentRowIndex * @param {?} visibleColumnIndex * @return {?} */ _navigateUpInChild(rowElement, currentRowIndex, visibleColumnIndex) { /** @type {?} */ const prevElem = rowElement.previousElementSibling; /** @type {?} */ const scrollable = this.getNextScrollable(this.grid); /** @type {?} */ const grid = scrollable.grid; /** @type {?} */ const scrTop = grid.verticalScrollContainer.getVerticalScroll().scrollTop; /** @type {?} */ const containerTop = scrollable.prev.nativeElement.parentNode.parentNode.parentNode.parentNode; /** @type {?} */ const top = parseInt(containerTop.style.top, 10); if (scrTop !== 0 && top < 0) { this.scrollGrid(grid, -prevElem.offsetHeight, () => super.navigateUp(rowElement, currentRowIndex, visibleColumnIndex)); } else { super.navigateUp(rowElement, currentRowIndex, visibleColumnIndex); } } /** * @private * @param {?} rowElement * @param {?} currentRowIndex * @param {?} visibleColumnIndex * @return {?} */ _navigateDownInChild(rowElement, currentRowIndex, visibleColumnIndex) { /** @type {?} */ const nextElem = rowElement.nextElementSibling; /** @type {?} */ const childContainer = this.grid.nativeElement.parentNode.parentNode; /** @type {?} */ const diff = childContainer.getBoundingClientRect().bottom - this.grid.rootGrid.nativeElement.getBoundingClientRect().bottom; /** @type {?} */ const endIsVisible = diff < 0; /** @type {?} */ const scrollable = this.getNextScrollableDown(this.grid); /** @type {?} */ const grid = scrollable.grid; if (!endIsVisible) { this.scrollGrid(grid, nextElem.offsetHeight, () => super.navigateDown(rowElement, currentRowIndex, visibleColumnIndex)); } else { super.navigateDown(rowElement, currentRowIndex, visibleColumnIndex); } } /** * @private * @param {?} sourceElem * @param {?} targetTag * @return {?} */ getClosestElemByTag(sourceElem, targetTag) { /** @type {?} */ let result = sourceElem; while (result !== null && result.nodeType === 1) { if (result.tagName.toLowerCase() === targetTag.toLowerCase()) { return result; } result = result.parentNode; } return null; } } if (false) { /** @type {?} */ IgxHierarchicalGridNavigationService.prototype.grid; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGllcmFyY2hpY2FsLWdyaWQtbmF2aWdhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vaWduaXRldWktYW5ndWxhci8iLCJzb3VyY2VzIjpbImxpYi9ncmlkcy9oaWVyYXJjaGljYWwtZ3JpZC9oaWVyYXJjaGljYWwtZ3JpZC1uYXZpZ2F0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXRFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFHcEQsTUFBTSxPQUFPLG9DQUFxQyxTQUFRLHdCQUF3Qjs7Ozs7OztJQUdwRSxlQUFlLENBQUMsWUFBcUIsRUFBRSxTQUFTLEdBQUcsS0FBSztRQUM5RCxPQUFPLFNBQVMsQ0FBQyxDQUFDLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxDQUFDLDRCQUE0QixDQUFDO0lBQzlFLENBQUM7Ozs7O0lBRVMsY0FBYztRQUNwQixPQUFPLDJCQUEyQixDQUFDO0lBQ3ZDLENBQUM7Ozs7OztJQUVTLGFBQWEsQ0FBQyxLQUFLOztjQUNuQixRQUFRLEdBQUcsSUFBSSxDQUFDLGNBQWMsRUFBRTs7Y0FDaEMsSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsZ0JBQWdCLENBQzVELEdBQUcsUUFBUSxtQkFBbUIsS0FBSyxJQUFJLENBQUMsQ0FBQzs7WUFDekMsR0FBRztRQUNQLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTs7a0JBQ1QsVUFBVSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLEVBQUUsdUJBQXVCLENBQUM7WUFDdkUsSUFBSSxVQUFVLElBQUksVUFBVSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRTtnQkFDMUQsR0FBRyxHQUFHLENBQUMsQ0FBQzthQUNmO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLEdBQUcsQ0FBQztJQUNmLENBQUM7Ozs7OztJQUVPLGlCQUFpQixDQUFDLElBQUs7O2NBQ3JCLFFBQVEsR0FBRyxJQUFJLElBQUksSUFBSSxDQUFDLElBQUk7UUFDbEMsT0FBTyxRQUFRLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDO0lBQ25FLENBQUM7Ozs7OztJQUVPLHdCQUF3QixDQUFDLElBQUs7O2NBQzVCLFFBQVEsR0FBRyxJQUFJLElBQUksSUFBSSxDQUFDLElBQUk7UUFDbEMsT0FBTyxRQUFRLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7SUFDeEQsQ0FBQzs7Ozs7OztJQUVPLFlBQVksQ0FBQyxXQUFXLEVBQUUsSUFBSTs7Y0FDNUIsS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdEYsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQzs7Ozs7O0lBRU8sbUJBQW1CLENBQUMsSUFBSTs7Y0FDdEIsU0FBUyxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLFNBQVM7O2NBQ3RFLFlBQVksR0FBRyxJQUFJLENBQUMsdUJBQXVCLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxZQUFZO1FBQ2xGLE9BQU8sWUFBWSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsR0FBSSxJQUFJLENBQUMsdUJBQXVCLENBQUMsbUJBQW1CLENBQUMsS0FBSyxZQUFZLENBQUM7SUFDNUgsQ0FBQzs7Ozs7O0lBQ08saUJBQWlCLENBQUMsS0FBSztRQUMzQixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUMxRixDQUFDOzs7Ozs7O0lBRU0sNEJBQTRCLENBQUMsUUFBUSxFQUFFLGtCQUFrQixFQUFFLFNBQVMsR0FBRyxLQUFLOztjQUN6RSxZQUFZLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxrQkFBa0IsRUFBRSxTQUFTLENBQUM7UUFDeEUsSUFBSSxTQUFTLEVBQUU7O2tCQUNMLFVBQVUsR0FBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQ