UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

451 lines (449 loc) • 20.2 kB
/** * DevExtreme (cjs/__internal/ui/selection/selection.strategy.standard.js) * Version: 25.1.5 * Build date: Wed Sep 03 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 _query = _interopRequireDefault(require("../../../common/data/query")); var _array = require("../../../core/utils/array"); var _array_compare = require("../../../core/utils/array_compare"); var _common = require("../../../core/utils/common"); var _deferred = require("../../../core/utils/deferred"); var _selection_filter = require("../../../core/utils/selection_filter"); var _type = require("../../../core/utils/type"); var _ui = _interopRequireDefault(require("../../../ui/widget/ui.errors")); var _selection = _interopRequireDefault(require("../../ui/selection/selection.strategy")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } class StandardStrategy extends _selection.default { constructor(options) { super(options); this._lastSelectAllPageDeferred = (0, _deferred.Deferred)().reject(); this._initSelectedItemKeyHash() } _initSelectedItemKeyHash() { this._setOption("keyHashIndices", this.options.equalByReference ? null : {}) } getSelectedItemKeys() { return this.options.selectedItemKeys.slice(0) } getSelectedItems() { return this.options.selectedItems.slice(0) } _preserveSelectionUpdate(items, isDeselect) { const { keyOf: keyOf } = this.options; let keyIndicesToRemoveMap; if (!keyOf) { return } const isBatchDeselect = isDeselect && items.length > 1 && !this.options.equalByReference; if (isBatchDeselect) { keyIndicesToRemoveMap = {} } items.forEach((item => { const key = keyOf(item); if (isDeselect) { const keyIndex = this.removeSelectedItem(key, keyIndicesToRemoveMap, item && "object" === typeof item && "disabled" in item ? !!item.disabled : false); if (keyIndicesToRemoveMap && (0, _type.isNumeric)(keyIndex) && keyIndex >= 0) { keyIndicesToRemoveMap[keyIndex] = true } } else { this.addSelectedItem(key, item) } })); if (isBatchDeselect) { this._batchRemoveSelectedItems(keyIndicesToRemoveMap) } } _batchRemoveSelectedItems(keyIndicesToRemoveMap) { const selectedItemKeys = this.options.selectedItemKeys.slice(0); const selectedItems = this.options.selectedItems.slice(0); this.options.selectedItemKeys.length = 0; this.options.selectedItems.length = 0; for (let i = 0; i < selectedItemKeys.length; i += 1) { if (!keyIndicesToRemoveMap[i]) { this.options.selectedItemKeys.push(selectedItemKeys[i]); this.options.selectedItems.push(selectedItems[i]) } } this._initSelectedItemKeyHash(); this.updateSelectedItemKeyHash(this.options.selectedItemKeys) } _loadSelectedItemsCore(keys, isDeselect, isSelectAll, filter) { let forceCombinedFilter = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : false; let deferred = (0, _deferred.Deferred)(); const key = this.options.key(); if (!keys.length && !isSelectAll) { deferred.resolve([]); return deferred } if (isSelectAll && isDeselect && !filter) { deferred.resolve(this.getSelectedItems()); return deferred } const selectionFilterCreator = new _selection_filter.SelectionFilterCreator(keys, isSelectAll); const combinedFilter = selectionFilterCreator.getCombinedFilter(key, filter, forceCombinedFilter); let deselectedItems = []; if (isDeselect) { const { selectedItems: selectedItems } = this.options; deselectedItems = combinedFilter && keys.length !== selectedItems.length ? (0, _query.default)(selectedItems).filter(combinedFilter).toArray() : selectedItems.slice(0) } let filteredItems = deselectedItems.length ? deselectedItems : this.options.plainItems(true).filter(this.options.isSelectableItem).map(this.options.getItemData); const localFilter = selectionFilterCreator.getLocalFilter(this.options.keyOf, this.equalKeys.bind(this), this.options.equalByReference, key); filteredItems = filteredItems.filter(localFilter); if (deselectedItems.length || !isSelectAll && filteredItems.length === keys.length) { deferred.resolve(filteredItems) } else { deferred = this._loadFilteredData(combinedFilter, localFilter, null, isSelectAll) } return deferred } _replaceSelectionUpdate(items) { const { keyOf: keyOf } = this.options; if (!keyOf) { return } const internalKeys = items.map((item => keyOf(item))); this.setSelectedItems(internalKeys, items) } _warnOnIncorrectKeys(keys) { const { allowNullValue: allowNullValue } = this.options; keys.forEach((key => { if ((!allowNullValue || null !== key) && !this.isItemKeySelected(key)) { _ui.default.log("W1002", key) } })) } _isMultiSelectEnabled() { const { mode: mode } = this.options; return "all" === mode || "multiple" === mode } _requestInProgress() { var _this$_lastLoadDeferr; return "pending" === (null === (_this$_lastLoadDeferr = this._lastLoadDeferred) || void 0 === _this$_lastLoadDeferr ? void 0 : _this$_lastLoadDeferr.state()) } _concatRequestsItems(keys, oldRequestItems, isDeselect, updatedKeys) { let selectedItems = []; const deselectedItems = isDeselect ? keys : []; if (updatedKeys) { selectedItems = updatedKeys } else { selectedItems = (0, _array.removeDuplicates)(keys, this.options.selectedItemKeys) } return { addedItems: oldRequestItems.added.concat(selectedItems), removedItems: oldRequestItems.removed.concat(deselectedItems), keys: keys } } _collectLastRequestData(keys, isDeselect, isSelectAll, updatedKeys) { const isDeselectAll = isDeselect && isSelectAll; const oldRequestItems = { added: [], removed: [] }; const multiSelectEnabled = this._isMultiSelectEnabled(); const emptyData = { addedItems: [], removedItems: [], keys: [] }; if (!multiSelectEnabled) { return emptyData } let lastRequestData = this._lastRequestData ?? emptyData; if (this._shouldMergeWithLastRequest) { if (isDeselectAll) { var _this$_lastLoadDeferr2; null === (_this$_lastLoadDeferr2 = this._lastLoadDeferred) || void 0 === _this$_lastLoadDeferr2 || _this$_lastLoadDeferr2.reject(); lastRequestData = {} } else if (!(0, _array_compare.isKeysEqual)(keys, this.options.selectedItemKeys)) { var _lastRequestData, _lastRequestData2; oldRequestItems.added = null === (_lastRequestData = lastRequestData) || void 0 === _lastRequestData ? void 0 : _lastRequestData.addedItems; oldRequestItems.removed = null === (_lastRequestData2 = lastRequestData) || void 0 === _lastRequestData2 ? void 0 : _lastRequestData2.removedItems; if (!isDeselect) { var _this$_lastLoadDeferr3; null === (_this$_lastLoadDeferr3 = this._lastLoadDeferred) || void 0 === _this$_lastLoadDeferr3 || _this$_lastLoadDeferr3.reject() } } } lastRequestData = this._concatRequestsItems(keys, oldRequestItems, isDeselect, this._shouldMergeWithLastRequest ? void 0 : updatedKeys); return lastRequestData } _updateKeysByLastRequestData(keys, isDeselect, isSelectAll) { let currentKeys = keys; if (this._isMultiSelectEnabled() && this._shouldMergeWithLastRequest && this._lastRequestData && !isDeselect && !isSelectAll) { var _this$_lastRequestDat; currentKeys = (0, _array.removeDuplicates)([...keys, ...this._lastRequestData.addedItems], null === (_this$_lastRequestDat = this._lastRequestData) || void 0 === _this$_lastRequestDat ? void 0 : _this$_lastRequestDat.removedItems); currentKeys = (0, _array.getUniqueValues)(currentKeys) } return currentKeys } _loadSelectedItems(keys, isDeselect, isSelectAll, updatedKeys) { let forceCombinedFilter = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : false; const deferred = (0, _deferred.Deferred)(); const filter = this.options.filter(); this._shouldMergeWithLastRequest = this._requestInProgress(); this._lastRequestData = this._collectLastRequestData(keys, isDeselect, isSelectAll, updatedKeys); (0, _deferred.when)(this._lastLoadDeferred).always((() => { const currentKeys = this._updateKeysByLastRequestData(keys, isDeselect, isSelectAll); this._shouldMergeWithLastRequest = false; this._loadSelectedItemsCore(currentKeys, isDeselect, isSelectAll, filter, forceCombinedFilter).done((result => { deferred.resolve(result) })).fail((error => { deferred.reject(error) })) })); this._lastLoadDeferred = deferred; return deferred } selectedItemKeys(keys, preserve, isDeselect, isSelectAll, updatedKeys, forceCombinedFilter) { if (this._isCancelingInProgress) { return (0, _deferred.Deferred)().reject() } const loadingDeferred = this._loadSelectedItems(keys, isDeselect, isSelectAll, updatedKeys, forceCombinedFilter); const selectionDeferred = (0, _deferred.Deferred)(); loadingDeferred.done((items => { this._storeSelectionState(); if (preserve) { this._preserveSelectionUpdate(items, isDeselect) } else { this._replaceSelectionUpdate(items) } this._isCancelingInProgress = true; this._callCallbackIfNotCanceled((() => { this._isCancelingInProgress = false; this.onSelectionChanged(); selectionDeferred.resolve(items) }), (() => { this._isCancelingInProgress = false; this._restoreSelectionState(); selectionDeferred.reject() })) })); return selectionDeferred } addSelectedItem(key, item) { if ((0, _type.isDefined)(item) && !this.options.ignoreDisabledItems && item.disabled) { if (!this.options.disabledItemKeys.includes(key)) { this.options.disabledItemKeys.push(key) } return } const keyHash = this._getKeyHash(key); if (-1 === this._indexOfSelectedItemKey(keyHash)) { if (!(0, _type.isObject)(keyHash) && this.options.keyHashIndices) { this.options.keyHashIndices[keyHash] = [this.options.selectedItemKeys.length] } this.options.selectedItemKeys.push(key); this.options.addedItemKeys.push(key); this.options.addedItems.push(item); this.options.selectedItems.push(item) } } _getSelectedIndexByKey(key, ignoreIndicesMap) { const { selectedItemKeys: selectedItemKeys } = this.options; return selectedItemKeys.findIndex(((_, index) => !(null !== ignoreIndicesMap && void 0 !== ignoreIndicesMap && ignoreIndicesMap[index]) && this.equalKeys(selectedItemKeys[index], key))) } _getSelectedIndexByHash(key, ignoreIndicesMap) { let indices = this.options.keyHashIndices[key]; if (indices && indices.length > 1 && ignoreIndicesMap) { indices = indices.filter((index => !ignoreIndicesMap[index])) } return indices && indices[0] >= 0 ? indices[0] : -1 } _indexOfSelectedItemKey(key, ignoreIndicesMap) { let selectedIndex = -1; if (this.options.equalByReference) { selectedIndex = this.options.selectedItemKeys.indexOf(key) } else if ((0, _type.isObject)(key)) { selectedIndex = this._getSelectedIndexByKey(key, ignoreIndicesMap) } else { selectedIndex = this._getSelectedIndexByHash(key, ignoreIndicesMap) } return selectedIndex } _shiftSelectedKeyIndices(keyIndex) { for (let currentKeyIndex = keyIndex; currentKeyIndex < this.options.selectedItemKeys.length; currentKeyIndex += 1) { const currentKey = this.options.selectedItemKeys[currentKeyIndex]; const currentKeyHash = (0, _common.getKeyHash)(currentKey); const currentKeyIndices = this.options.keyHashIndices[currentKeyHash]; if (!currentKeyIndices) { continue } for (let i = 0; i < currentKeyIndices.length; i += 1) { if (currentKeyIndices[i] > keyIndex) { currentKeyIndices[i] -= 1 } } } } removeSelectedItem(key, keyIndicesToRemoveMap, isDisabled) { if (!this.options.ignoreDisabledItems && isDisabled) { return } const keyHash = this._getKeyHash(key); const isBatchDeselect = !!keyIndicesToRemoveMap; const keyIndex = this._indexOfSelectedItemKey(keyHash, keyIndicesToRemoveMap); if (keyIndex < 0) { return keyIndex } this.options.removedItemKeys.push(key); this.options.removedItems.push(this.options.selectedItems[keyIndex]); if (isBatchDeselect) { return keyIndex } this.options.selectedItemKeys.splice(keyIndex, 1); this.options.selectedItems.splice(keyIndex, 1); if ((0, _type.isObject)(keyHash) || !this.options.keyHashIndices) { return keyIndex } const keyIndices = this.options.keyHashIndices[keyHash]; if (!keyIndices) { return keyIndex } keyIndices.shift(); if (!keyIndices.length) { delete this.options.keyHashIndices[keyHash] } this._shiftSelectedKeyIndices(keyIndex); return keyIndex } _updateAddedItemKeys(keys, items) { for (let i = 0; i < keys.length; i += 1) { if (!this.isItemKeySelected(keys[i])) { this.options.addedItemKeys.push(keys[i]); this.options.addedItems.push(items[i]) } } } _updateRemovedItemKeys(_, oldSelectedKeys, oldSelectedItems) { for (let i = 0; i < oldSelectedKeys.length; i += 1) { if (!this.isItemKeySelected(oldSelectedKeys[i])) { this.options.removedItemKeys.push(oldSelectedKeys[i]); this.options.removedItems.push(oldSelectedItems[i]) } } } _isItemSelectionInProgress(key, checkPending) { const shouldCheckPending = checkPending && this._lastRequestData && this._requestInProgress(); if (shouldCheckPending) { var _this$_lastRequestDat2; const addedItems = (null === (_this$_lastRequestDat2 = this._lastRequestData) || void 0 === _this$_lastRequestDat2 ? void 0 : _this$_lastRequestDat2.addedItems) ?? []; return addedItems.includes(key) } return false } _getKeyHash(key) { return this.options.equalByReference ? key : (0, _common.getKeyHash)(key) } setSelectedItems(keys, items) { this._updateAddedItemKeys(keys, items); const oldSelectedKeys = this.options.selectedItemKeys; const oldSelectedItems = this.options.selectedItems; if (!this.options.equalByReference) { this._initSelectedItemKeyHash(); this.updateSelectedItemKeyHash(keys) } this._setOption("selectedItemKeys", keys); this._setOption("selectedItems", items); this._updateRemovedItemKeys(keys, oldSelectedKeys, oldSelectedItems) } isItemDataSelected(itemData) { let options = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; const key = this.options.keyOf(itemData); return this.isItemKeySelected(key, options) } isItemKeySelected(key) { let options = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; let result = this._isItemSelectionInProgress(key, options.checkPending); if (!result) { const keyHash = this._getKeyHash(key); const index = this._indexOfSelectedItemKey(keyHash); result = -1 !== index } return result } getSelectAllState(visibleOnly) { if (visibleOnly) { return this._getVisibleSelectAllState() } return this._getFullSelectAllState() } loadSelectedItemsWithFilter() { const keyExpr = this.options.key(); const keys = this.getSelectedItemKeys(); const filter = this.options.filter(); if (!keys.length) { return (0, _deferred.Deferred)().resolve([]) } const selectionFilterCreator = new _selection_filter.SelectionFilterCreator(keys); const combinedFilter = selectionFilterCreator.getCombinedFilter(keyExpr, filter, true); return this._loadFilteredData(combinedFilter) } _storeSelectionState() { const { selectedItems: selectedItems, selectedItemKeys: selectedItemKeys, keyHashIndices: keyHashIndices } = this.options; this._storedSelectionState = { keyHashIndices: JSON.stringify(keyHashIndices), selectedItems: [...selectedItems], selectedItemKeys: [...selectedItemKeys] } } _restoreSelectionState() { this._clearItemKeys(); if (!this._storedSelectionState) { return } const { selectedItemKeys: selectedItemKeys, selectedItems: selectedItems, keyHashIndices: keyHashIndices } = this._storedSelectionState; this._setOption("selectedItemKeys", selectedItemKeys); this._setOption("selectedItems", selectedItems); this._setOption("keyHashIndices", JSON.parse(keyHashIndices)) } _onePageSelectAll(isDeselect) { if ("pending" === this._lastSelectAllPageDeferred.state()) { return (0, _deferred.Deferred)().reject() } this._storeSelectionState(); this._selectAllPlainItems(isDeselect); this._lastSelectAllPageDeferred = (0, _deferred.Deferred)(); this._callCallbackIfNotCanceled((() => { this.onSelectionChanged(); this._lastSelectAllPageDeferred.resolve() }), (() => { this._restoreSelectionState(); this._lastSelectAllPageDeferred.reject() })); return this._lastSelectAllPageDeferred } } exports.default = StandardStrategy;