UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

669 lines (664 loc) • 29.4 kB
/** * DevExtreme (cjs/__internal/grids/grid_core/m_utils.js) * Version: 24.2.6 * Build date: Mon Mar 17 2025 * * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine")); var _data_source = _interopRequireDefault(require("../../../common/data/data_source")); var _utils = require("../../../common/data/data_source/utils"); var _utils2 = require("../../../common/data/utils"); var _renderer = _interopRequireDefault(require("../../../core/renderer")); var _common = require("../../../core/utils/common"); var _data = require("../../../core/utils/data"); var _deferred = require("../../../core/utils/deferred"); var _extend = require("../../../core/utils/extend"); var _iterator = require("../../../core/utils/iterator"); var _position = require("../../../core/utils/position"); var _size = require("../../../core/utils/size"); var _string = require("../../../core/utils/string"); var _type = require("../../../core/utils/type"); var _variable_wrapper = _interopRequireDefault(require("../../../core/utils/variable_wrapper")); var _window = require("../../../core/utils/window"); var _format_helper = _interopRequireDefault(require("../../../format_helper")); var _load_panel = _interopRequireDefault(require("../../../ui/load_panel")); var _filtering = _interopRequireDefault(require("../../../ui/shared/filtering")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function(n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) { ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]) } } return n }, _extends.apply(null, arguments) } const DATAGRID_SELECTION_DISABLED_CLASS = "dx-selection-disabled"; const DATAGRID_GROUP_OPENED_CLASS = "dx-datagrid-group-opened"; const DATAGRID_GROUP_CLOSED_CLASS = "dx-datagrid-group-closed"; const DATAGRID_EXPAND_CLASS = "dx-datagrid-expand"; const NO_DATA_CLASS = "nodata"; const SCROLLING_MODE_INFINITE = "infinite"; const SCROLLING_MODE_VIRTUAL = "virtual"; const LEGACY_SCROLLING_MODE = "scrolling.legacyMode"; const SCROLLING_MODE_OPTION = "scrolling.mode"; const ROW_RENDERING_MODE_OPTION = "scrolling.rowRenderingMode"; const DATE_INTERVAL_SELECTORS = { year: value => value && value.getFullYear(), month: value => value && value.getMonth() + 1, day: value => value && value.getDate(), quarter: value => value && Math.floor(value.getMonth() / 3) + 1, hour: value => value && value.getHours(), minute: value => value && value.getMinutes(), second: value => value && value.getSeconds() }; const getIntervalSelector = function() { const data = arguments[1]; const value = this.calculateCellValue(data); if (!(0, _type.isDefined)(value)) { return null } if (isDateType(this.dataType)) { const nameIntervalSelector = arguments[0]; return DATE_INTERVAL_SELECTORS[nameIntervalSelector](value) } if ("number" === this.dataType) { const groupInterval = arguments[0]; return Math.floor(Number(value) / groupInterval) * groupInterval } }; const equalSelectors = function(selector1, selector2) { if ((0, _type.isFunction)(selector1) && (0, _type.isFunction)(selector2)) { if (selector1.originalCallback && selector2.originalCallback) { return selector1.originalCallback === selector2.originalCallback && selector1.columnIndex === selector2.columnIndex } } return selector1 === selector2 }; function isDateType(dataType) { return "date" === dataType || "datetime" === dataType } const setEmptyText = function($container) { $container.get(0).textContent = "\xa0" }; const normalizeSortingInfo = function(sort) { sort = sort || []; const result = (0, _utils2.normalizeSortingInfo)(sort); for (let i = 0; i < sort.length; i++) { if (sort && sort[i] && void 0 !== sort[i].isExpanded) { result[i].isExpanded = sort[i].isExpanded } if (sort && sort[i] && void 0 !== sort[i].groupInterval) { result[i].groupInterval = sort[i].groupInterval } } return result }; const formatValue = function(value, options) { const valueText = _format_helper.default.format(value, options.format) || value && value.toString() || ""; const formatObject = { value: value, valueText: options.getDisplayFormat ? options.getDisplayFormat(valueText) : valueText, target: options.target || "row", groupInterval: options.groupInterval }; return options.customizeText ? options.customizeText.call(options, formatObject) : formatObject.valueText }; const getSummaryText = function(summaryItem, summaryTexts) { const displayFormat = summaryItem.displayFormat || summaryItem.columnCaption && summaryTexts[`${summaryItem.summaryType}OtherColumn`] || summaryTexts[summaryItem.summaryType]; return formatValue(summaryItem.value, { format: summaryItem.valueFormat, getDisplayFormat: valueText => displayFormat ? (0, _string.format)(displayFormat, valueText, summaryItem.columnCaption) : valueText, customizeText: summaryItem.customizeText }) }; const getWidgetInstance = function($element) { const editorData = $element.data && $element.data(); const dxComponents = editorData && editorData.dxComponents; const widgetName = dxComponents && dxComponents[0]; return widgetName && editorData[widgetName] }; const equalFilterParameters = function(filter1, filter2) { if (Array.isArray(filter1) && Array.isArray(filter2)) { if (filter1.length !== filter2.length) { return false } for (let i = 0; i < filter1.length; i++) { if (!equalFilterParameters(filter1[i], filter2[i])) { return false } } return true } if ((0, _type.isFunction)(filter1) && filter1.columnIndex >= 0 && (0, _type.isFunction)(filter2) && filter2.columnIndex >= 0) { return filter1.columnIndex === filter2.columnIndex && (0, _data.toComparable)(filter1.filterValue) === (0, _data.toComparable)(filter2.filterValue) && (0, _data.toComparable)(filter1.selectedFilterOperation) === (0, _data.toComparable)(filter2.selectedFilterOperation) } return (0, _data.toComparable)(filter1) == (0, _data.toComparable)(filter2) }; const createPoint = options => ({ index: options.index, columnIndex: options.columnIndex, x: options.x, y: options.y }); const addPointIfNeed = (points, pointProps, pointCreated) => { let notCreatePoint = false; if (pointCreated) { notCreatePoint = pointCreated(pointProps) } if (!notCreatePoint) { const point = createPoint(pointProps); points.push(point) } }; function normalizeGroupingLoadOptions(group) { if (!Array.isArray(group)) { group = [group] } return group.map(((item, i) => { if ((0, _type.isString)(item)) { return { selector: item, isExpanded: i < group.length - 1 } } return item })) } var _default = exports.default = { renderNoDataText($element) { const that = this; $element = $element || this.element(); if (!$element) { return } const noDataClass = that.addWidgetPrefix("nodata"); let noDataElement = $element.find(`.${noDataClass}`).last(); const isVisible = this._dataController.isEmpty(); const isLoading = this._dataController.isLoading(); if (!noDataElement.length) { noDataElement = (0, _renderer.default)("<span>").addClass(noDataClass) } if (!noDataElement.parent().is($element)) { noDataElement.appendTo($element) } if (isVisible && !isLoading) { noDataElement.removeClass("dx-hidden").text(that._getNoDataText()) } else { noDataElement.addClass("dx-hidden") } }, renderLoadPanel($element, $container, isLocalStore) { const that = this; let loadPanelOptions; that._loadPanel && that._loadPanel.$element().remove(); loadPanelOptions = that.option("loadPanel"); if (loadPanelOptions && ("auto" === loadPanelOptions.enabled ? !isLocalStore : loadPanelOptions.enabled)) { loadPanelOptions = (0, _extend.extend)({ shading: false, message: loadPanelOptions.text, container: $container }, loadPanelOptions); that._loadPanel = that._createComponent((0, _renderer.default)("<div>").appendTo($container), _load_panel.default, loadPanelOptions) } else { that._loadPanel = null } }, calculateLoadPanelPosition($element) { const $window = (0, _renderer.default)((0, _window.getWindow)()); if ((0, _size.getHeight)($element) > (0, _size.getHeight)($window)) { return { of: $window, boundary: $element, collision: "fit" } } return { of: $element } }, getIndexByKey(key, items, keyName) { let index = -1; if (void 0 !== key && Array.isArray(items)) { keyName = arguments.length <= 2 ? "key" : keyName; for (let i = 0; i < items.length; i++) { const item = (0, _type.isDefined)(keyName) ? items[i][keyName] : items[i]; if ((0, _common.equalByValue)(key, item)) { index = i; break } } } return index }, combineFilters(filters, operation) { let resultFilter = []; operation = operation || "and"; for (let i = 0; i < filters.length; i++) { var _filters$i; if (!filters[i]) { continue } if (1 === (null === (_filters$i = filters[i]) || void 0 === _filters$i ? void 0 : _filters$i.length) && "!" === filters[i][0]) { if ("and" === operation) { return ["!"] } if ("or" === operation) { continue } } if (resultFilter.length) { resultFilter.push(operation) } resultFilter.push(filters[i]) } if (1 === resultFilter.length) { resultFilter = resultFilter[0] } if (resultFilter.length) { return resultFilter } return }, checkChanges(changes, changeNames) { let changesWithChangeNamesCount = 0; for (let i = 0; i < changeNames.length; i++) { if (changes[changeNames[i]]) { changesWithChangeNamesCount++ } } return changes.length && changes.length === changesWithChangeNamesCount }, equalFilterParameters: equalFilterParameters, proxyMethod(instance, methodName, defaultResult) { if (!instance[methodName]) { instance[methodName] = function() { const dataSource = this._dataSource; return dataSource ? dataSource[methodName].apply(dataSource, arguments) : defaultResult } } }, formatValue: formatValue, getFormatOptionsByColumn: (column, target) => ({ format: column.format, getDisplayFormat: column.getDisplayFormat, customizeText: column.customizeText, target: target, trueText: column.trueText, falseText: column.falseText }), getDisplayValue(column, value, data, rowType) { if (column.displayValueMap && void 0 !== column.displayValueMap[value]) { return column.displayValueMap[value] } if (column.calculateDisplayValue && data && "group" !== rowType) { return column.calculateDisplayValue(data) } if (column.lookup && !("group" === rowType && (column.calculateGroupValue || column.calculateDisplayValue))) { return column.lookup.calculateCellValue(value) } return value }, getGroupRowSummaryText(summaryItems, summaryTexts) { let result = "("; for (let i = 0; i < summaryItems.length; i++) { const summaryItem = summaryItems[i]; result += (i > 0 ? ", " : "") + getSummaryText(summaryItem, summaryTexts) } return result + ")" }, getSummaryText: getSummaryText, normalizeSortingInfo: normalizeSortingInfo, getFormatByDataType(dataType) { switch (dataType) { case "date": return "shortDate"; case "datetime": return "shortDateShortTime"; default: return } }, getHeaderFilterGroupParameters(column, remoteGrouping) { let result = []; const dataField = column.dataField || column.name; const groupInterval = _filtering.default.getGroupInterval(column); if (groupInterval) { (0, _iterator.each)(groupInterval, ((index, interval) => { result.push(remoteGrouping ? { selector: dataField, groupInterval: interval, isExpanded: index < groupInterval.length - 1 } : getIntervalSelector.bind(column, interval)) })); return result } if (remoteGrouping) { result = [{ selector: dataField, isExpanded: false }] } else { result = function(data) { let result = column.calculateCellValue(data); if (void 0 === result || "" === result) { result = null } return result }; if (column.sortingMethod) { result = [{ selector: result, compare: column.sortingMethod.bind(column) }] } } return result }, equalSortParameters(sortParameters1, sortParameters2, ignoreIsExpanded) { sortParameters1 = normalizeSortingInfo(sortParameters1); sortParameters2 = normalizeSortingInfo(sortParameters2); if (Array.isArray(sortParameters1) && Array.isArray(sortParameters2)) { if (sortParameters1.length !== sortParameters2.length) { return false } for (let i = 0; i < sortParameters1.length; i++) { if (!equalSelectors(sortParameters1[i].selector, sortParameters2[i].selector) || sortParameters1[i].desc !== sortParameters2[i].desc || sortParameters1[i].groupInterval !== sortParameters2[i].groupInterval || !ignoreIsExpanded && Boolean(sortParameters1[i].isExpanded) !== Boolean(sortParameters2[i].isExpanded)) { return false } } return true } return (!sortParameters1 || !sortParameters1.length) === (!sortParameters2 || !sortParameters2.length) }, getPointsByColumns(items, pointCreated) { let isVertical = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : false; let startColumnIndex = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : 0; let needToCheckPrevPoint = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : false; const result = []; const cellsLength = items.length; let $item; let offset = { left: 0, top: 0 }; let itemRect = { width: 0, height: 0 }; let columnIndex = startColumnIndex; let rtlEnabled; for (let i = 0; i <= cellsLength; i++) { var _$item; if (i < cellsLength) { $item = items.eq(i); offset = $item.offset(); itemRect = (0, _position.getBoundingRect)($item.get(0)); rtlEnabled = "rtl" === $item.css("direction") } const offsetRight = offset.left + itemRect.width; const offsetBottom = offset.top + itemRect.height; const pointProps = { index: columnIndex, columnIndex: columnIndex, item: null === (_$item = $item) || void 0 === _$item ? void 0 : _$item.get(0), x: !isVertical && rtlEnabled !== (i === cellsLength) ? offsetRight : offset.left, y: isVertical && i === cellsLength ? offsetBottom : offset.top }; if (!isVertical && i > 0) { const prevItemOffset = items.eq(i - 1).offset(); const { width: prevItemWidth } = (0, _position.getBoundingRect)(items[i - 1]); const prevItemOffsetX = rtlEnabled ? prevItemOffset.left : prevItemOffset.left + prevItemWidth; if (prevItemOffset.top < pointProps.y) { pointProps.y = prevItemOffset.top } if (needToCheckPrevPoint && Math.round(prevItemOffsetX) !== Math.round(pointProps.x)) { const prevPointProps = _extends({}, pointProps, { item: items[i - 1], x: prevItemOffsetX }); if (rtlEnabled) { pointProps.isRightBoundary = true; prevPointProps.isLeftBoundary = true } else { pointProps.isLeftBoundary = true; prevPointProps.isRightBoundary = true } addPointIfNeed(result, prevPointProps, pointCreated) } } addPointIfNeed(result, pointProps, pointCreated); columnIndex++ } return result }, getExpandCellTemplate: () => ({ allowRenderToDetachedContainer: true, render(container, options) { const $container = (0, _renderer.default)(container); if ((0, _type.isDefined)(options.value) && !(options.data && options.data.isContinuation) && !options.row.isNewRow) { const rowsView = options.component.getView("rowsView"); $container.addClass("dx-datagrid-expand").addClass("dx-selection-disabled"); (0, _renderer.default)("<div>").addClass(options.value ? "dx-datagrid-group-opened" : "dx-datagrid-group-closed").appendTo($container); rowsView.setAria("label", options.value ? rowsView.localize("dxDataGrid-ariaCollapse") : rowsView.localize("dxDataGrid-ariaExpand"), $container) } else { setEmptyText($container) } } }), setEmptyText: setEmptyText, isDateType: isDateType, getSelectionRange(focusedElement) { try { if (focusedElement) { return { selectionStart: focusedElement.selectionStart, selectionEnd: focusedElement.selectionEnd } } } catch (e) {} return {} }, setSelectionRange(focusedElement, selectionRange) { try { if (focusedElement && focusedElement.setSelectionRange) { focusedElement.setSelectionRange(selectionRange.selectionStart, selectionRange.selectionEnd) } } catch (e) {} }, focusAndSelectElement(component, $element) { const isFocused = $element.is(":focus"); _events_engine.default.trigger($element, "focus"); const isSelectTextOnEditingStart = component.option("editing.selectTextOnEditStart"); const element = $element.get(0); if (!isFocused && isSelectTextOnEditingStart && $element.is(".dx-texteditor-input") && !$element.is("[readonly]")) { const editor = getWidgetInstance($element.closest(".dx-texteditor")); (0, _deferred.when)(editor && editor._loadItemDeferred).done((() => { element.select() })) } }, getWidgetInstance: getWidgetInstance, getLastResizableColumnIndex(columns, resultWidths) { const hasResizableColumns = columns.some((column => column && !column.command && !column.fixed && false !== column.allowResizing)); let lastColumnIndex; for (lastColumnIndex = columns.length - 1; columns[lastColumnIndex]; lastColumnIndex--) { const column = columns[lastColumnIndex]; const width = resultWidths && resultWidths[lastColumnIndex]; const allowResizing = !hasResizableColumns || false !== column.allowResizing; if (!column.command && !column.fixed && "adaptiveHidden" !== width && allowResizing) { break } } return lastColumnIndex }, isElementInCurrentGrid(controller, $element) { if ($element && $element.length) { const $grid = $element.closest(`.${controller.getWidgetContainerClass()}`).parent(); return $grid.is(controller.component.$element()) } return false }, isVirtualRowRendering(that) { const rowRenderingMode = that.option(ROW_RENDERING_MODE_OPTION); const isVirtualMode = "virtual" === that.option("scrolling.mode"); const isAppendMode = "infinite" === that.option("scrolling.mode"); if (false === that.option(LEGACY_SCROLLING_MODE) && (isVirtualMode || isAppendMode)) { return true } return "virtual" === rowRenderingMode }, getPixelRatio: window => window.devicePixelRatio || 1, getContentHeightLimit(browser) { if (browser.mozilla) { return 8e6 } return 15e6 / this.getPixelRatio((0, _window.getWindow)()) }, normalizeLookupDataSource(lookup) { let lookupDataSourceOptions; if (lookup.items) { lookupDataSourceOptions = lookup.items } else { lookupDataSourceOptions = lookup.dataSource; if ((0, _type.isFunction)(lookupDataSourceOptions) && !_variable_wrapper.default.isWrapped(lookupDataSourceOptions)) { lookupDataSourceOptions = lookupDataSourceOptions({}) } } return (0, _utils.normalizeDataSourceOptions)(lookupDataSourceOptions) }, getWrappedLookupDataSource(column, dataSource, filter) { if (!dataSource) { return [] } const lookupDataSourceOptions = this.normalizeLookupDataSource(column.lookup); if (column.calculateCellValue !== column.defaultCalculateCellValue) { return lookupDataSourceOptions } const hasGroupPaging = dataSource.remoteOperations().groupPaging; const hasLookupOptimization = column.displayField && (0, _type.isString)(column.displayField); let cachedUniqueRelevantItems; let previousTake; let previousSkip; const sliceItems = (items, loadOptions) => { const start = loadOptions.skip ?? 0; const end = loadOptions.take ? start + loadOptions.take : items.length; return items.slice(start, end) }; const lookupDataSource = _extends({}, lookupDataSourceOptions, { __dataGridSourceFilter: filter, load: loadOptions => { const d = new _deferred.Deferred; (loadOptions => { const group = normalizeGroupingLoadOptions(hasLookupOptimization ? [column.dataField, column.displayField] : column.dataField); const d = new _deferred.Deferred; const canUseCache = cachedUniqueRelevantItems && (!hasGroupPaging || loadOptions.skip === previousSkip && loadOptions.take === previousTake); if (canUseCache) { d.resolve(sliceItems(cachedUniqueRelevantItems, loadOptions)) } else { previousSkip = loadOptions.skip; previousTake = loadOptions.take; dataSource.load({ filter: filter, group: group, take: hasGroupPaging ? loadOptions.take : void 0, skip: hasGroupPaging ? loadOptions.skip : void 0 }).done((items => { cachedUniqueRelevantItems = items; d.resolve(hasGroupPaging ? items : sliceItems(items, loadOptions)) })).fail(d.fail) } return d })(loadOptions).done((items => { if (0 === items.length) { d.resolve([]); return } const filter = this.combineFilters(items.flatMap((data => data.key)).map((key => [column.lookup.valueExpr, key])), "or"); const newDataSource = new _data_source.default(_extends({}, lookupDataSourceOptions, loadOptions, { filter: this.combineFilters([filter, loadOptions.filter], "and"), paginate: false })); newDataSource.load().done(d.resolve).fail(d.fail) })).fail(d.fail); return d }, key: column.lookup.valueExpr, byKey(key) { const d = (0, _deferred.Deferred)(); this.load({ filter: [column.lookup.valueExpr, "=", key] }).done((arr => { d.resolve(arr[0]) })); return d.promise() } }); return lookupDataSource }, logHeaderFilterDeprecatedWarningIfNeed(component) { const logWarning = component._logDeprecatedOptionWarning.bind(component); if ((0, _type.isDefined)(component.option("headerFilter.allowSearch"))) { logWarning("headerFilter.allowSearch", { since: "23.1", alias: "headerFilter.search.enabled" }) } if ((0, _type.isDefined)(component.option("headerFilter.searchTimeout"))) { logWarning("headerFilter.searchTimeout", { since: "23.1", alias: "headerFilter.search.timeout" }) } const specificName = "dxPivotGrid" === component.NAME ? "dataSource.fields" : "columns"; const columns = component.option(specificName); if (!Array.isArray(columns)) { return } const logSpecificDeprecatedWarningIfNeed = columns => { columns.forEach((column => { var _column$columns; const headerFilter = column.headerFilter || {}; if ((0, _type.isDefined)(headerFilter.allowSearch)) { logWarning(`${specificName}[].headerFilter.allowSearch`, { since: "23.1", alias: `${specificName}[].headerFilter.search.enabled` }) } if ((0, _type.isDefined)(headerFilter.searchMode)) { logWarning(`${specificName}[].headerFilter.searchMode`, { since: "23.1", alias: `${specificName}[].headerFilter.search.mode` }) } if (null !== (_column$columns = column.columns) && void 0 !== _column$columns && _column$columns.length) { logSpecificDeprecatedWarningIfNeed(column.columns) } })) }; logSpecificDeprecatedWarningIfNeed(columns) }, getComponentBorderWidth(that, $rowsViewElement) { const borderWidth = that.option("showBorders") ? Math.ceil((0, _size.getOuterWidth)($rowsViewElement) - (0, _size.getInnerWidth)($rowsViewElement)) : 0; return borderWidth }, isCustomCommandColumn(columns, commandColumn) { const customCommandColumns = columns.filter((column => column.type === commandColumn.type)); return !!customCommandColumns.length } };