@progress/kendo-angular-pivotgrid
Version:
PivotGrid package for Angular
224 lines (223 loc) • 7.77 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
const EMPTY_REGEX = /^\s*$/;
/**
* @hidden
*/
export const isPresent = (value) => value !== null && value !== undefined;
/**
* @hidden
*/
export const isBlank = (value) => value === null || value === undefined;
/**
* @hidden
*/
export const isNullOrEmptyString = (value) => isBlank(value) || EMPTY_REGEX.test(value);
/**
* @hidden
* Returns whether two arrays contain the same values.
* Assumes array elements are primitive types
*/
export const areSameArrays = (a1, a2) => {
const areArrays = (isPresent(a1) && Array.isArray(a1) && isPresent(a2) && Array.isArray(a2));
const areOfEqualLength = a1.length === a2.length;
if (!areArrays || !areOfEqualLength) {
return false;
}
for (let i = 0; i < a1.length; i++) {
if (a1[i] !== a2[i]) {
return false;
}
}
return true;
};
/**
* @hidden
*/
export const wheelDelta = (e, axis) => {
const delta = e[`wheelDelta${axis}`];
if (e.wheelDelta && (delta === undefined || delta)) {
return e.wheelDelta;
}
if (e.detail && e.axis === e[axis === 'X' ? 'HORIZONTAL_AXIS' : 'VERTICAL_AXIS']) {
return (-e.detail) * 10;
}
return 0;
};
/**
* @hidden
*/
export const syncScroll = (source, targets) => {
const sourceScrollTop = source.scrollTop;
const sourceScrollLeft = source.scrollLeft;
const targetScrollTop = targets[0].scrollTop;
const targetScrollLeft = targets[1].scrollLeft;
const syncVertically = sourceScrollTop !== targetScrollTop;
const syncHorizontally = sourceScrollLeft !== targetScrollLeft;
if (syncVertically) {
targets[0].scrollTop = sourceScrollTop;
}
else if (syncHorizontally) {
targets[1].scrollLeft = sourceScrollLeft;
}
};
/**
* @hidden
*/
export const syncWheel = (event, tables, prop, axis) => {
const delta = axis === 'Y' ? -(wheelDelta(event, axis)) : wheelDelta(event, axis);
if (delta) {
tables[0][prop] =
tables[1][prop] += delta;
}
};
/**
* @hidden
*/
const getDocument = element => element.ownerDocument.documentElement;
/**
* @hidden
*/
const getWindow = element => element.ownerDocument.defaultView;
/**
* @hidden
*/
export const offset = element => {
const { clientTop, clientLeft } = getDocument(element);
const { pageYOffset, pageXOffset } = getWindow(element);
const { top, left } = element.getBoundingClientRect();
return {
top: top + pageYOffset - clientTop,
left: left + pageXOffset - clientLeft
};
};
/**
* @hidden
*/
export const matchAriaAttributes = (wrapper) => {
const rowHeaderRows = wrapper.querySelectorAll('.k-pivotgrid-row-headers .k-pivotgrid-row');
const rowHeaderCols = rowHeaderRows.length ?
Array.from(rowHeaderRows[0]?.children)?.reduce((acc, curr) => acc += (+curr.getAttribute('colspan')), 0) : 0;
const colHeaderRows = wrapper.querySelectorAll('.k-pivotgrid-column-headers tr');
const colHeaderCells = wrapper.querySelectorAll('.k-pivotgrid-column-headers th');
const valueTableCells = wrapper.querySelectorAll('.k-pivotgrid-values td');
const emptyCell = wrapper.querySelector('.k-pivotgrid-empty-cell');
emptyCell.setAttribute('aria-rowspan', colHeaderRows.length.toString());
emptyCell.setAttribute('aria-colspan', rowHeaderCols.toString());
const firstColHeadersRow = colHeaderRows[0];
const firstColHeaderRowCellsIds = Array.from(firstColHeadersRow?.children).map(el => el.getAttribute('id')).join(' ');
firstColHeadersRow.setAttribute('aria-owns', `${emptyCell.getAttribute('id')} ${firstColHeaderRowCellsIds}`);
rowHeaderRows.forEach((row, index) => {
const valueCellsIds = filterAndMap(Array.from(valueTableCells), c => c.getAttribute('id')?.split('-')[4] === (index + 1).toString(), c => c.getAttribute('id'));
row.setAttribute('aria-owns', valueCellsIds.join(' '));
});
valueTableCells.forEach(cell => {
const cellColIndex = +cell.getAttribute('id')?.split('-')[5];
const colHeaderCellsIds = filterAndMap(Array.from(colHeaderCells), c => {
const headerCellColIndex = +c.getAttribute('id')?.split('-')[5];
const headerCellColspan = +c.getAttribute('colspan');
const colIndexIsEqual = cellColIndex === headerCellColIndex;
const cellColIndexIsWithinHeaderCellRange = headerCellColIndex < cellColIndex && headerCellColspan > 1 && (headerCellColIndex + headerCellColspan - 1 >= cellColIndex);
return colIndexIsEqual || cellColIndexIsWithinHeaderCellRange;
}, c => c.getAttribute('id'));
colHeaderCellsIds.length && cell.setAttribute('aria-describedby', colHeaderCellsIds.join(' '));
});
};
/**
* @hidden
*/
export const position = (target, before) => {
const targetRect = offset(target);
const { offsetWidth, offsetHeight } = target;
const left = targetRect.left + (before ? 0 : offsetWidth);
const top = targetRect.top + offsetHeight / 2;
return { left, top };
};
/**
* @hidden
*/
export const filterAndMap = (arr, predicate, mapper) => arr.reduce((acc, curr) => predicate(curr) ? [...acc, mapper(curr)] : acc, []);
/**
* @hidden
*/
export const cloneDate = (date) => date ? new Date(date.getTime()) : null;
/**
* @hidden
*/
export function clone(obj) {
const result = {};
cloneObject(obj, result);
return result;
}
/**
* @hidden
*/
export function cloneObject(obj, result) {
for (const field in obj) {
if (field === '__proto__' || field === 'constructor' || field === 'prototype') {
continue;
}
if (obj.hasOwnProperty(field)) {
const value = obj[field];
result[field] = cloneValue(value, result[field]);
}
}
}
/**
* @hidden
*/
export function cloneValue(value, nextValue) {
if (Array.isArray(value)) {
return cloneArray(value);
}
else if (value instanceof Date) {
return cloneDate(value);
}
else if (value && typeof value === 'object') {
const newNextValue = nextValue || {};
cloneObject(value, newNextValue);
return newNextValue;
}
return value;
}
/**
* @hidden
*/
export function cloneArray(array) {
return array.map(value => cloneValue(value, undefined));
}
/**
* @hidden
*/
export const swapItems = (arr, i1, i2) => {
const temp = arr[i1];
arr[i1] = arr[i2];
arr[i2] = temp;
};
/**
* @hidden
*/
export const isVisible = (el, container, offsetY, rtl) => {
const elTop = el.offsetTop;
const elBottom = elTop + el.clientHeight;
let rect;
let containerRect;
if (rtl) {
rect = el.getBoundingClientRect();
containerRect = container.getBoundingClientRect();
}
const elLeft = rtl ? rect.left : el.offsetLeft;
const elRight = rtl ? rect.right : elLeft + el.clientWidth;
const containerTop = container.scrollTop;
const containerBottom = containerTop + container.clientHeight;
const containerLeft = rtl ? containerRect.left : container.scrollLeft;
const containerRight = rtl ? containerRect.right : containerLeft + container.clientWidth;
const visibleY = elTop >= containerTop - offsetY && elBottom <= containerBottom - offsetY;
const visibleX = rtl ? elRight <= containerRight && elLeft >= containerLeft : elLeft >= containerLeft && elRight <= containerRight;
return {
visibleX,
visibleY
};
};