@progress/kendo-angular-grid
Version:
Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.
202 lines (201 loc) • 6.02 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 { InjectionToken } from '@angular/core';
import { isDocumentAvailable } from '@progress/kendo-angular-common';
import { merge, of } from 'rxjs';
export { isChanged, anyChanged, hasObservers } from '@progress/kendo-angular-common';
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 isArray = (value) => Array.isArray(value);
/**
* @hidden
*/
export const isTruthy = (value) => !!value;
/**
* @hidden
*/
export const isNullOrEmptyString = (value) => isBlank(value) || EMPTY_REGEX.test(value);
/**
* @hidden
*/
export const observe = (list) => merge(of(list), list.changes);
/**
* @hidden
*/
export const isUniversal = () => typeof document === 'undefined';
/**
* @hidden
*/
export const isString = (value) => typeof value === 'string';
/**
* @hidden
*/
export const isNumber = (value) => typeof value === "number" && !isNaN(value);
/**
* @hidden
*/
export const extractFormat = (format) => {
if (isString(format) && !isNullOrEmptyString(format) && format.startsWith('{0:')) {
return format.slice(3, format.length - 1);
}
return format;
};
/**
* @hidden
*/
export const not = (fn) => (...args) => !fn(...args);
/**
* @hidden
*/
export const or = (...conditions) => (value) => conditions.reduce((acc, x) => acc || x(value), false);
/**
* @hidden
*/
export const and = (...conditions) => (value) => conditions.reduce((acc, x) => acc && x(value), true);
/**
* @hidden
*/
export const Skip = new InjectionToken("Skip");
/**
* @hidden
*/
export const createPromise = () => {
let resolveFn, rejectFn;
const promise = new Promise((resolve, reject) => {
resolveFn = (data) => {
resolve(data);
return promise;
};
rejectFn = (data) => {
reject(data);
return promise;
};
});
promise.resolve = resolveFn;
promise.reject = rejectFn;
return promise;
};
/** @hidden */
export const iterator = getIterator();
// TODO: Move to kendo-common
function getIterator() {
if (typeof Symbol === 'function' && Symbol.iterator) {
return Symbol.iterator;
}
const keys = Object.getOwnPropertyNames(Map.prototype);
const proto = Map.prototype;
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
if (key !== 'entries' && key !== 'size' && proto[key] === proto.entries) {
return key;
}
}
}
const FRAME_DURATION = 1000 / 60;
const wnd = typeof window !== 'undefined' ? window : {};
/** @hidden */
export const requestAnimationFrame = wnd.requestAnimationFrame || wnd.msRequestAnimationFrame || (callback => setTimeout(callback, FRAME_DURATION));
/** @hidden */
export const cancelAnimationFrame = wnd.cancelAnimationFrame || wnd.msCancelRequestAnimationFrame || clearTimeout;
/**
* @hidden
*/
export const detectIE = () => {
if (!isDocumentAvailable()) {
return;
}
const ua = window.navigator.userAgent;
const msie = ua.indexOf('MSIE ');
const trident = ua.indexOf('Trident/');
return msie > 0 || trident > 0;
};
/**
* @hidden
*/
export const nodesToArray = (nodes) => [].slice.call(nodes);
/**
* @hidden
*/
export const replaceMessagePlaceholder = (message, name, value) => (message ?? '').replace(new RegExp(`{\\s*${name}\\s*}`, 'g'), value);
/**
* @hidden
*/
export const recursiveFlatMap = (item) => isGroupResult(item) ? item.items.flatMap(recursiveFlatMap) : [{ ...item }];
/**
* @hidden
*/
export const isGroupResult = (obj) => {
return 'aggregates' in obj && 'items' in obj && 'field' in obj && 'value' in obj;
};
/**
* @hidden
*/
export const roundDown = (value) => Math.floor(value * 100) / 100;
/**
* @hidden
*/
export const defaultCellRowSpan = (row, column, data) => {
const field = column.field;
let rowspan = 1;
const rowIndex = row.index;
if (!data[0].items) {
//If no groups are present.
rowspan = findRowSpan(data, rowIndex, field);
}
else {
// If groups are present.
const group = row.dataItem.group;
if (field === group.data.field) {
// Set the rowspan to the number of data items in the same group if the column containing the current row matches the grouping field.
rowspan = group.data.items.length;
}
else {
//The index of the current row in the group.
const rowIndex = row.dataItem.group.data.items.indexOf(row.dataItem.data);
const groupItems = row.dataItem.group.data.items;
rowspan = findRowSpan(groupItems, rowIndex, field);
}
}
return rowspan;
};
/**
* @hidden
* Returns the rowspan number based on the provided data array, index of the item, and field that is checked.
*/
const findRowSpan = (data, index, field) => {
let rowspan = 1;
if (typeof data[index][field]?.getTime === 'function') {
while (data[index][field].getTime() === data[index + 1]?.[field].getTime()) {
rowspan++;
index++;
}
}
else {
while (data[index][field] === data[index + 1]?.[field]) {
rowspan++;
index++;
}
}
return rowspan;
};
/**
* @hidden
* Determines whether selection of multiple ranges is enabled in the selectable settings.
*/
export const isMultipleRangesEnabled = (selectableSettings) => {
return selectableSettings &&
typeof selectableSettings === 'object' &&
selectableSettings.selectable.multipleRanges;
};