@catull/igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
811 lines • 136 kB
JavaScript
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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