igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
1,169 lines • 139 kB
JavaScript
/**
* @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