devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
657 lines (655 loc) • 29.1 kB
JavaScript
/**
* DevExtreme (cjs/ui/collection/ui.collection_widget.edit.js)
* Version: 23.2.6
* Build date: Wed May 01 2024
*
* Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
exports.default = void 0;
var _renderer = _interopRequireDefault(require("../../core/renderer"));
var _events_engine = _interopRequireDefault(require("../../events/core/events_engine"));
var _uiCollection_widget = _interopRequireDefault(require("./ui.collection_widget.base"));
var _ui = _interopRequireDefault(require("../widget/ui.errors"));
var _extend = require("../../core/utils/extend");
var _iterator = require("../../core/utils/iterator");
var _common = require("../../core/utils/common");
var _type = require("../../core/utils/type");
var _uiCollection_widgetEditStrategy = _interopRequireDefault(require("./ui.collection_widget.edit.strategy.plain"));
var _data = require("../../core/utils/data");
var _data_source = require("../../data/data_source/data_source");
var _utils = require("../../data/data_source/utils");
var _selection = _interopRequireDefault(require("../selection/selection"));
var _deferred = require("../../core/utils/deferred");
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
}
}
const ITEM_DELETING_DATA_KEY = "dxItemDeleting";
const NOT_EXISTING_INDEX = -1;
const indexExists = function(index) {
return -1 !== index
};
const CollectionWidget = _uiCollection_widget.default.inherit({
_setOptionsByReference: function() {
this.callBase();
(0, _extend.extend)(this._optionsByReference, {
selectedItem: true
})
},
_getDefaultOptions: function() {
return (0, _extend.extend)(this.callBase(), {
selectionMode: "none",
selectionRequired: false,
selectByClick: true,
selectedItems: [],
selectedItemKeys: [],
maxFilterLengthInRequest: 1500,
keyExpr: null,
selectedIndex: -1,
selectedItem: null,
onSelectionChanged: null,
onItemReordered: null,
onItemDeleting: null,
onItemDeleted: null
})
},
ctor: function(element, options) {
this._userOptions = options || {};
this.callBase(element, options)
},
_init: function() {
this._initEditStrategy();
this.callBase();
this._initKeyGetter();
this._initSelectionModule()
},
_initKeyGetter: function() {
this._keyGetter = (0, _data.compileGetter)(this.option("keyExpr"))
},
_getKeysByItems: function(selectedItems) {
return this._editStrategy.getKeysByItems(selectedItems)
},
_getItemsByKeys: function(selectedItemKeys, selectedItems) {
return this._editStrategy.getItemsByKeys(selectedItemKeys, selectedItems)
},
_getKeyByIndex: function(index) {
return this._editStrategy.getKeyByIndex(index)
},
_getIndexByKey: function(key) {
return this._editStrategy.getIndexByKey(key)
},
_getIndexByItemData: function(itemData) {
return this._editStrategy.getIndexByItemData(itemData)
},
_isKeySpecified: function() {
return !!this._dataController.key()
},
_getCombinedFilter: function() {
return this._dataController.filter()
},
key: function() {
if (this.option("keyExpr")) {
return this.option("keyExpr")
}
return this._dataController.key()
},
keyOf: function(item) {
let key = item;
if (this.option("keyExpr")) {
key = this._keyGetter(item)
} else if (this._dataController.store()) {
key = this._dataController.keyOf(item)
}
return key
},
_nullValueSelectionSupported: function() {
return false
},
_initSelectionModule: function() {
const that = this;
const itemsGetter = that._editStrategy.itemsGetter;
this._selection = new _selection.default({
allowNullValue: this._nullValueSelectionSupported(),
mode: this.option("selectionMode"),
maxFilterLengthInRequest: this.option("maxFilterLengthInRequest"),
equalByReference: !this._isKeySpecified(),
onSelectionChanged: function(args) {
if (args.addedItemKeys.length || args.removedItemKeys.length) {
that.option("selectedItems", that._getItemsByKeys(args.selectedItemKeys, args.selectedItems));
that._updateSelectedItems(args)
}
},
filter: that._getCombinedFilter.bind(that),
totalCount: function() {
const items = that.option("items");
const totalCount = that._dataController.totalCount();
return totalCount >= 0 ? totalCount : that._getItemsCount(items)
},
key: that.key.bind(that),
keyOf: that.keyOf.bind(that),
load: function(options) {
var _dataController$loadO;
const dataController = that._dataController;
options.customQueryParams = null === (_dataController$loadO = dataController.loadOptions()) || void 0 === _dataController$loadO ? void 0 : _dataController$loadO.customQueryParams;
options.userData = dataController.userData();
if (dataController.store()) {
return dataController.loadFromStore(options).done((function(loadResult) {
if (that._disposed) {
return
}
const items = (0, _utils.normalizeLoadResult)(loadResult).data;
dataController.applyMapFunction(items)
}))
} else {
return (new _deferred.Deferred).resolve(this.plainItems())
}
},
dataFields: function() {
return that._dataController.select()
},
plainItems: itemsGetter.bind(that._editStrategy)
})
},
_getItemsCount: function(items) {
return items.reduce((itemsCount, item) => itemsCount + (item.items ? this._getItemsCount(item.items) : 1), 0)
},
_initEditStrategy: function() {
const Strategy = _uiCollection_widgetEditStrategy.default;
this._editStrategy = new Strategy(this)
},
_getSelectedItemIndices: function(keys) {
const that = this;
const indices = [];
keys = keys || this._selection.getSelectedItemKeys();
that._editStrategy.beginCache();
(0, _iterator.each)(keys, (function(_, key) {
const selectedIndex = that._getIndexByKey(key);
if (indexExists(selectedIndex)) {
indices.push(selectedIndex)
}
}));
that._editStrategy.endCache();
return indices
},
_initMarkup: function() {
this._rendering = true;
if (!this._dataController.isLoading()) {
this._syncSelectionOptions().done(() => this._normalizeSelectedItems())
}
this.callBase()
},
_render: function() {
this.callBase();
this._rendering = false
},
_fireContentReadyAction: function() {
this._rendering = false;
this._rendered = true;
this.callBase.apply(this, arguments)
},
_syncSelectionOptions: function(byOption) {
byOption = byOption || this._chooseSelectOption();
let selectedItem;
let selectedIndex;
let selectedItemKeys;
let selectedItems;
switch (byOption) {
case "selectedIndex":
selectedItem = this._editStrategy.getItemDataByIndex(this.option("selectedIndex"));
if ((0, _type.isDefined)(selectedItem)) {
this._setOptionWithoutOptionChange("selectedItems", [selectedItem]);
this._setOptionWithoutOptionChange("selectedItem", selectedItem);
this._setOptionWithoutOptionChange("selectedItemKeys", this._editStrategy.getKeysByItems([selectedItem]))
} else {
this._setOptionWithoutOptionChange("selectedItems", []);
this._setOptionWithoutOptionChange("selectedItemKeys", []);
this._setOptionWithoutOptionChange("selectedItem", null)
}
break;
case "selectedItems":
selectedItems = this.option("selectedItems") || [];
selectedIndex = selectedItems.length ? this._editStrategy.getIndexByItemData(selectedItems[0]) : -1;
if (this.option("selectionRequired") && !indexExists(selectedIndex)) {
return this._syncSelectionOptions("selectedIndex")
}
this._setOptionWithoutOptionChange("selectedItem", selectedItems[0]);
this._setOptionWithoutOptionChange("selectedIndex", selectedIndex);
this._setOptionWithoutOptionChange("selectedItemKeys", this._editStrategy.getKeysByItems(selectedItems));
break;
case "selectedItem":
selectedItem = this.option("selectedItem");
selectedIndex = this._editStrategy.getIndexByItemData(selectedItem);
if (this.option("selectionRequired") && !indexExists(selectedIndex)) {
return this._syncSelectionOptions("selectedIndex")
}
if ((0, _type.isDefined)(selectedItem)) {
this._setOptionWithoutOptionChange("selectedItems", [selectedItem]);
this._setOptionWithoutOptionChange("selectedIndex", selectedIndex);
this._setOptionWithoutOptionChange("selectedItemKeys", this._editStrategy.getKeysByItems([selectedItem]))
} else {
this._setOptionWithoutOptionChange("selectedItems", []);
this._setOptionWithoutOptionChange("selectedItemKeys", []);
this._setOptionWithoutOptionChange("selectedIndex", -1)
}
break;
case "selectedItemKeys":
selectedItemKeys = this.option("selectedItemKeys");
if (this.option("selectionRequired")) {
const selectedItemIndex = this._getIndexByKey(selectedItemKeys[0]);
if (!indexExists(selectedItemIndex)) {
return this._syncSelectionOptions("selectedIndex")
}
}
return this._selection.setSelection(selectedItemKeys)
}
return (new _deferred.Deferred).resolve().promise()
},
_chooseSelectOption: function() {
let optionName = "selectedIndex";
const isOptionDefined = function(optionName) {
const optionValue = this.option(optionName);
const length = (0, _type.isDefined)(optionValue) && optionValue.length;
return length || optionName in this._userOptions
}.bind(this);
if (isOptionDefined("selectedItems")) {
optionName = "selectedItems"
} else if (isOptionDefined("selectedItem")) {
optionName = "selectedItem"
} else if (isOptionDefined("selectedItemKeys")) {
optionName = "selectedItemKeys"
}
return optionName
},
_compareKeys: function(oldKeys, newKeys) {
if (oldKeys.length !== newKeys.length) {
return false
}
for (let i = 0; i < newKeys.length; i++) {
if (oldKeys[i] !== newKeys[i]) {
return false
}
}
return true
},
_normalizeSelectedItems: function() {
if ("none" === this.option("selectionMode")) {
this._setOptionWithoutOptionChange("selectedItems", []);
this._syncSelectionOptions("selectedItems")
} else if ("single" === this.option("selectionMode")) {
const newSelection = this.option("selectedItems");
if (newSelection.length > 1 || !newSelection.length && this.option("selectionRequired") && this.option("items") && this.option("items").length) {
const currentSelection = this._selection.getSelectedItems();
let normalizedSelection = void 0 === newSelection[0] ? currentSelection[0] : newSelection[0];
if (void 0 === normalizedSelection) {
normalizedSelection = this._editStrategy.itemsGetter()[0]
}
if (this.option("grouped") && normalizedSelection && normalizedSelection.items) {
normalizedSelection.items = [normalizedSelection.items[0]]
}
this._selection.setSelection(this._getKeysByItems([normalizedSelection]));
this._setOptionWithoutOptionChange("selectedItems", [normalizedSelection]);
return this._syncSelectionOptions("selectedItems")
} else {
this._selection.setSelection(this._getKeysByItems(newSelection))
}
} else {
const newKeys = this._getKeysByItems(this.option("selectedItems"));
const oldKeys = this._selection.getSelectedItemKeys();
if (!this._compareKeys(oldKeys, newKeys)) {
this._selection.setSelection(newKeys)
}
}
return (new _deferred.Deferred).resolve().promise()
},
_itemClickHandler: function(e) {
let itemSelectPromise = (new _deferred.Deferred).resolve();
const callBase = this.callBase;
this._createAction(function(e) {
var _this$_itemSelectHand;
itemSelectPromise = null !== (_this$_itemSelectHand = this._itemSelectHandler(e.event)) && void 0 !== _this$_itemSelectHand ? _this$_itemSelectHand : itemSelectPromise
}.bind(this), {
validatingTargetName: "itemElement"
})({
itemElement: (0, _renderer.default)(e.currentTarget),
event: e
});
itemSelectPromise.always(() => {
callBase.apply(this, arguments)
})
},
_itemSelectHandler: function(e) {
var _itemSelectPromise;
let itemSelectPromise;
if (!this.option("selectByClick")) {
return
}
const $itemElement = e.currentTarget;
if (this.isItemSelected($itemElement)) {
this.unselectItem(e.currentTarget)
} else {
itemSelectPromise = this.selectItem(e.currentTarget)
}
return null === (_itemSelectPromise = itemSelectPromise) || void 0 === _itemSelectPromise ? void 0 : _itemSelectPromise.promise()
},
_selectedItemElement: function(index) {
return this._itemElements().eq(index)
},
_postprocessRenderItem: function(args) {
if ("none" !== this.option("selectionMode")) {
const $itemElement = (0, _renderer.default)(args.itemElement);
const normalizedItemIndex = this._editStrategy.getNormalizedIndex($itemElement);
const isItemSelected = this._isItemSelected(normalizedItemIndex);
this._processSelectableItem($itemElement, isItemSelected)
}
},
_processSelectableItem: function($itemElement, isSelected) {
$itemElement.toggleClass(this._selectedItemClass(), isSelected);
this._setAriaSelectionAttribute($itemElement, String(isSelected))
},
_updateSelectedItems: function(args) {
const that = this;
const addedItemKeys = args.addedItemKeys;
const removedItemKeys = args.removedItemKeys;
if (that._rendered && (addedItemKeys.length || removedItemKeys.length)) {
const selectionChangePromise = that._selectionChangePromise;
if (!that._rendering) {
const addedSelection = [];
let normalizedIndex;
const removedSelection = [];
that._editStrategy.beginCache();
for (let i = 0; i < addedItemKeys.length; i++) {
normalizedIndex = that._getIndexByKey(addedItemKeys[i]);
addedSelection.push(normalizedIndex);
that._addSelection(normalizedIndex)
}
for (let i = 0; i < removedItemKeys.length; i++) {
normalizedIndex = that._getIndexByKey(removedItemKeys[i]);
removedSelection.push(normalizedIndex);
that._removeSelection(normalizedIndex)
}
that._editStrategy.endCache();
that._updateSelection(addedSelection, removedSelection)
}(0, _deferred.when)(selectionChangePromise).done((function() {
that._fireSelectionChangeEvent(args.addedItems, args.removedItems)
}))
}
},
_fireSelectionChangeEvent: function(addedItems, removedItems) {
this._createActionByOption("onSelectionChanged", {
excludeValidators: ["disabled", "readOnly"]
})({
addedItems: addedItems,
removedItems: removedItems
})
},
_updateSelection: _common.noop,
_setAriaSelectionAttribute: function($target, value) {
this.setAria("selected", value, $target)
},
_removeSelection: function(normalizedIndex) {
const $itemElement = this._editStrategy.getItemElement(normalizedIndex);
if (indexExists(normalizedIndex)) {
this._processSelectableItem($itemElement, false);
_events_engine.default.triggerHandler($itemElement, "stateChanged", false)
}
},
_addSelection: function(normalizedIndex) {
const $itemElement = this._editStrategy.getItemElement(normalizedIndex);
if (indexExists(normalizedIndex)) {
this._processSelectableItem($itemElement, true);
_events_engine.default.triggerHandler($itemElement, "stateChanged", true)
}
},
_isItemSelected: function(index) {
const key = this._getKeyByIndex(index);
return this._selection.isItemSelected(key, {
checkPending: true
})
},
_optionChanged: function(args) {
switch (args.name) {
case "selectionMode":
this._invalidate();
break;
case "dataSource":
if (!args.value || Array.isArray(args.value) && !args.value.length) {
this.option("selectedItemKeys", [])
}
this.callBase(args);
break;
case "selectedIndex":
case "selectedItem":
case "selectedItems":
case "selectedItemKeys":
this._syncSelectionOptions(args.name).done(() => this._normalizeSelectedItems());
break;
case "keyExpr":
this._initKeyGetter();
break;
case "selectionRequired":
this._normalizeSelectedItems();
break;
case "selectByClick":
case "onSelectionChanged":
case "onItemDeleting":
case "onItemDeleted":
case "onItemReordered":
case "maxFilterLengthInRequest":
break;
default:
this.callBase(args)
}
},
_clearSelectedItems: function() {
this._setOptionWithoutOptionChange("selectedItems", []);
this._syncSelectionOptions("selectedItems")
},
_waitDeletingPrepare: function($itemElement) {
if ($itemElement.data("dxItemDeleting")) {
return (new _deferred.Deferred).resolve().promise()
}
$itemElement.data("dxItemDeleting", true);
const deferred = new _deferred.Deferred;
const deletingActionArgs = {
cancel: false
};
const deletePromise = this._itemEventHandler($itemElement, "onItemDeleting", deletingActionArgs, {
excludeValidators: ["disabled", "readOnly"]
});
(0, _deferred.when)(deletePromise).always(function(value) {
const deletePromiseExists = !deletePromise;
const deletePromiseResolved = !deletePromiseExists && "resolved" === deletePromise.state();
const argumentsSpecified = !!arguments.length;
const shouldDelete = deletePromiseExists || deletePromiseResolved && !argumentsSpecified || deletePromiseResolved && value;
(0, _deferred.when)((0, _deferred.fromPromise)(deletingActionArgs.cancel)).always((function() {
$itemElement.data("dxItemDeleting", false)
})).done((function(cancel) {
shouldDelete && !cancel ? deferred.resolve() : deferred.reject()
})).fail(deferred.reject)
}.bind(this));
return deferred.promise()
},
_deleteItemFromDS: function($item) {
const dataController = this._dataController;
const deferred = new _deferred.Deferred;
const disabledState = this.option("disabled");
const dataStore = dataController.store();
if (!dataStore) {
return (new _deferred.Deferred).resolve().promise()
}
if (!dataStore.remove) {
throw _ui.default.Error("E1011")
}
this.option("disabled", true);
dataStore.remove(dataController.keyOf(this._getItemData($item))).done((function(key) {
if (void 0 !== key) {
deferred.resolve()
} else {
deferred.reject()
}
})).fail((function() {
deferred.reject()
}));
deferred.always(function() {
this.option("disabled", disabledState)
}.bind(this));
return deferred
},
_tryRefreshLastPage: function() {
const deferred = new _deferred.Deferred;
if (this._isLastPage() || this.option("grouped")) {
deferred.resolve()
} else {
this._refreshLastPage().done((function() {
deferred.resolve()
}))
}
return deferred.promise()
},
_refreshLastPage: function() {
this._expectLastItemLoading();
return this._dataController.load()
},
_updateSelectionAfterDelete: function(index) {
const key = this._getKeyByIndex(index);
this._selection.deselect([key])
},
_updateIndicesAfterIndex: function(index) {
const itemElements = this._itemElements();
for (let i = index + 1; i < itemElements.length; i++) {
(0, _renderer.default)(itemElements[i]).data(this._itemIndexKey(), i - 1)
}
},
_simulateOptionChange: function(optionName) {
const optionValue = this.option(optionName);
if (optionValue instanceof _data_source.DataSource) {
return
}
this._optionChangedAction({
name: optionName,
fullName: optionName,
value: optionValue
})
},
isItemSelected: function(itemElement) {
return this._isItemSelected(this._editStrategy.getNormalizedIndex(itemElement))
},
selectItem: function(itemElement) {
if ("none" === this.option("selectionMode")) {
return
}
const itemIndex = this._editStrategy.getNormalizedIndex(itemElement);
if (!indexExists(itemIndex)) {
return
}
const key = this._getKeyByIndex(itemIndex);
if (this._selection.isItemSelected(key)) {
return
}
if ("single" === this.option("selectionMode")) {
return this._selection.setSelection([key])
} else {
const selectedItemKeys = this.option("selectedItemKeys") || [];
return this._selection.setSelection([...selectedItemKeys, key], [key])
}
},
unselectItem: function(itemElement) {
const itemIndex = this._editStrategy.getNormalizedIndex(itemElement);
if (!indexExists(itemIndex)) {
return
}
const selectedItemKeys = this._selection.getSelectedItemKeys();
if (this.option("selectionRequired") && selectedItemKeys.length <= 1) {
return
}
const key = this._getKeyByIndex(itemIndex);
if (!this._selection.isItemSelected(key, {
checkPending: true
})) {
return
}
this._selection.deselect([key])
},
_deleteItemElementByIndex: function(index) {
this._updateSelectionAfterDelete(index);
this._updateIndicesAfterIndex(index);
this._editStrategy.deleteItemAtIndex(index)
},
_afterItemElementDeleted: function($item, deletedActionArgs) {
const changingOption = this._dataController.getDataSource() ? "dataSource" : "items";
this._simulateOptionChange(changingOption);
this._itemEventHandler($item, "onItemDeleted", deletedActionArgs, {
beforeExecute: function() {
$item.remove()
},
excludeValidators: ["disabled", "readOnly"]
});
this._renderEmptyMessage()
},
deleteItem: function(itemElement) {
const that = this;
const deferred = new _deferred.Deferred;
const $item = this._editStrategy.getItemElement(itemElement);
const index = this._editStrategy.getNormalizedIndex(itemElement);
const itemResponseWaitClass = this._itemResponseWaitClass();
if (indexExists(index)) {
this._waitDeletingPrepare($item).done((function() {
$item.addClass(itemResponseWaitClass);
const deletedActionArgs = that._extendActionArgs($item);
that._deleteItemFromDS($item).done((function() {
that._deleteItemElementByIndex(index);
that._afterItemElementDeleted($item, deletedActionArgs);
that._tryRefreshLastPage().done((function() {
deferred.resolveWith(that)
}))
})).fail((function() {
$item.removeClass(itemResponseWaitClass);
deferred.rejectWith(that)
}))
})).fail((function() {
deferred.rejectWith(that)
}))
} else {
deferred.rejectWith(that)
}
return deferred.promise()
},
reorderItem: function(itemElement, toItemElement) {
const deferred = new _deferred.Deferred;
const that = this;
const strategy = this._editStrategy;
const $movingItem = strategy.getItemElement(itemElement);
const $destinationItem = strategy.getItemElement(toItemElement);
const movingIndex = strategy.getNormalizedIndex(itemElement);
const destinationIndex = strategy.getNormalizedIndex(toItemElement);
const changingOption = this._dataController.getDataSource() ? "dataSource" : "items";
const canMoveItems = indexExists(movingIndex) && indexExists(destinationIndex) && movingIndex !== destinationIndex;
if (canMoveItems) {
deferred.resolveWith(this)
} else {
deferred.rejectWith(this)
}
return deferred.promise().done((function() {
$destinationItem[strategy.itemPlacementFunc(movingIndex, destinationIndex)]($movingItem);
strategy.moveItemAtIndexToIndex(movingIndex, destinationIndex);
this._updateIndicesAfterIndex(movingIndex);
that.option("selectedItems", that._getItemsByKeys(that._selection.getSelectedItemKeys(), that._selection.getSelectedItems()));
if ("items" === changingOption) {
that._simulateOptionChange(changingOption)
}
that._itemEventHandler($movingItem, "onItemReordered", {
fromIndex: strategy.getIndex(movingIndex),
toIndex: strategy.getIndex(destinationIndex)
}, {
excludeValidators: ["disabled", "readOnly"]
})
}))
}
});
var _default = CollectionWidget;
exports.default = _default;
module.exports = exports.default;
module.exports.default = exports.default;