@progress/kendo-angular-grid
Version:
Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.
163 lines (162 loc) • 4.82 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { isDocumentAvailable } from "@progress/kendo-angular-common";
const focusableRegex = /^(?:a|input|select|option|textarea|button|object)$/i;
const NODE_NAME_PREDICATES = {};
const toClassList = (classNames) => String(classNames).trim().split(' ');
/**
* @hidden
*/
export const hasClasses = (element, classNames) => {
const namesList = toClassList(classNames);
return Boolean(toClassList(element.className).find((className) => namesList.indexOf(className) >= 0));
};
/**
* @hidden
*/
export const matchesClasses = (classNames) => (element) => hasClasses(element, classNames);
/**
* @hidden
*/
export const matchesNodeName = (nodeName) => {
if (!NODE_NAME_PREDICATES[nodeName]) {
NODE_NAME_PREDICATES[nodeName] = (element) => String(element.nodeName).toLowerCase() === nodeName.toLowerCase();
}
return NODE_NAME_PREDICATES[nodeName];
};
/**
* @hidden
*/
export const closest = (node, predicate) => {
while (node && !predicate(node)) {
node = node.parentNode;
}
return node;
};
/**
* @hidden
*/
export const closestInScope = (node, predicate, scope) => {
while (node && node !== scope && !predicate(node)) {
node = node.parentNode;
}
if (node !== scope) {
return node;
}
};
/**
* @hidden
*/
export const contains = (parent, node, matchSelf = false) => {
const outside = !closest(node, (child) => child === parent);
if (outside) {
return false;
}
const el = closest(node, (child) => child === node);
return el && (matchSelf || el !== parent);
};
/**
* @hidden
*/
export const isVisible = (element) => {
if (!isDocumentAvailable()) {
return;
}
const rect = element.getBoundingClientRect();
const hasSize = rect.width > 0 && rect.height > 0;
const hasPosition = rect.x !== 0 && rect.y !== 0;
// Elements can have zero size due to styling, but they will still count as visible.
// For example, the selection checkbox has no size, but is made visible through styling.
return (hasSize || hasPosition) && window.getComputedStyle(element).visibility !== 'hidden';
};
/**
* @hidden
*/
export const isFocusable = (element) => {
if (!element.tagName) {
return false;
}
const tagName = element.tagName.toLowerCase();
const hasTabIndex = Boolean(element.getAttribute('tabIndex'));
const focusable = !element.disabled && focusableRegex.test(tagName);
return focusable || hasTabIndex;
};
/**
* @hidden
*/
export const isFocusableWithTabKey = (element, checkVisibility = true) => {
if (!isFocusable(element)) {
return false;
}
const visible = !checkVisibility || isVisible(element);
const ariaHidden = element.getAttribute('aria-hidden') === 'true';
const tabIndex = element.getAttribute('tabIndex');
return visible && !ariaHidden && tabIndex !== '-1';
};
/**
* @hidden
*/
export const findElement = (node, predicate, matchSelf = true) => {
if (!node) {
return;
}
if (matchSelf && predicate(node)) {
return node;
}
node = node.firstChild;
while (node) {
if (node.nodeType === 1) {
const element = findElement(node, predicate);
if (element) {
return element;
}
}
node = node.nextSibling;
}
};
/**
* @hidden
*/
export const findLastElement = (node, predicate, matchSelf = true) => {
let last = null;
findElement(node, (node) => {
if (predicate(node)) {
last = node;
}
return false;
}, matchSelf);
return last;
};
/**
* @hidden
*/
export const findFocusable = (element, checkVisibility = true) => {
return findElement(element, (node) => isFocusableWithTabKey(node, checkVisibility));
};
/**
* @hidden
*/
export const findFocusableChild = (element, checkVisibility = true) => {
return findElement(element, (node) => isFocusableWithTabKey(node, checkVisibility), false);
};
/**
* @hidden
*/
export const findLastFocusableChild = (element, checkVisibility = true) => {
return findLastElement(element, (node) => isFocusableWithTabKey(node, checkVisibility), false);
};
/**
* @hidden
*/
export function rtlScrollPosition(position, element, initial) {
let result = position;
if (initial < 0) {
result = -position;
}
else if (initial > 0) {
result = element.scrollWidth - element.offsetWidth - position;
}
return result;
}