devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,059 lines (1,058 loc) • 68.2 kB
JavaScript
/**
* DevExtreme (cjs/__internal/grids/grid_core/validating/m_validating.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.validatingRowsViewExtender = exports.validatingModule = exports.validatingEditorFactoryExtender = exports.validatingEditingExtender = exports.validatingDataControllerExtender = exports.ValidatingController = void 0;
var _events_engine = _interopRequireDefault(require("../../../../common/core/events/core/events_engine"));
var _pointer = _interopRequireDefault(require("../../../../common/core/events/pointer"));
var _message = _interopRequireDefault(require("../../../../common/core/localization/message"));
var _array_utils = require("../../../../common/data/array_utils");
var _renderer = _interopRequireDefault(require("../../../../core/renderer"));
var _browser = _interopRequireDefault(require("../../../../core/utils/browser"));
var _common = require("../../../../core/utils/common");
var _deferred = require("../../../../core/utils/deferred");
var _extend = require("../../../../core/utils/extend");
var _iterator = require("../../../../core/utils/iterator");
var _size = require("../../../../core/utils/size");
var _string = require("../../../../core/utils/string");
var _type = require("../../../../core/utils/type");
var _button = _interopRequireDefault(require("../../../../ui/button"));
var _load_indicator = _interopRequireDefault(require("../../../../ui/load_indicator"));
var _ui = _interopRequireDefault(require("../../../../ui/overlay/ui.overlay"));
var _themes = require("../../../../ui/themes");
var _validation_engine = _interopRequireDefault(require("../../../../ui/validation_engine"));
var _validator = _interopRequireDefault(require("../../../../ui/validator"));
var _selectors = require("../../../../ui/widget/selectors");
var _ui2 = _interopRequireDefault(require("../../../../ui/widget/ui.errors"));
var _const = require("../editing/const");
var _m_modules = _interopRequireDefault(require("../m_modules"));
var _m_utils = _interopRequireDefault(require("../m_utils"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const INVALIDATE_CLASS = "invalid";
const REVERT_TOOLTIP_CLASS = "revert-tooltip";
const INVALID_MESSAGE_CLASS = "dx-invalid-message";
const INVALID_MESSAGE_ID = "dxInvalidMessage";
const WIDGET_INVALID_MESSAGE_CLASS = "invalid-message";
const INVALID_MESSAGE_ALWAYS_CLASS = "dx-invalid-message-always";
const REVERT_BUTTON_CLASS = "dx-revert-button";
const REVERT_BUTTON_ID = "dxRevertButton";
const VALIDATOR_CLASS = "validator";
const PENDING_INDICATOR_CLASS = "dx-pending-indicator";
const VALIDATION_PENDING_CLASS = "dx-validation-pending";
const CONTENT_CLASS = "content";
const INSERT_INDEX = "__DX_INSERT_INDEX__";
const PADDING_BETWEEN_TOOLTIPS = 2;
const EDIT_MODE_ROW = "row";
const EDIT_MODE_FORM = "form";
const EDIT_MODE_BATCH = "batch";
const EDIT_MODE_CELL = "cell";
const EDIT_MODE_POPUP = "popup";
const GROUP_CELL_CLASS = "dx-group-cell";
const FORM_BASED_MODES = ["popup", "form"];
const COMMAND_TRANSPARENT = "transparent";
const VALIDATION_STATUS = {
valid: "valid",
invalid: "invalid",
pending: "pending"
};
const EDIT_DATA_INSERT_TYPE = "insert";
const EDIT_DATA_REMOVE_TYPE = "remove";
const VALIDATION_CANCELLED = "cancel";
const validationResultIsValid = function(result) {
return (0, _type.isDefined)(result) && "cancel" !== result
};
const cellValueShouldBeValidated = function(value, rowOptions) {
return void 0 !== value || void 0 === value && rowOptions && !rowOptions.isNewRow
};
class ValidatingController extends _m_modules.default.Controller {
constructor() {
super(...arguments);
this._isValidationInProgress = false;
this._disableApplyValidationResults = false
}
init() {
this._editingController = this.getController("editing");
this._editorFactoryController = this.getController("editorFactory");
this._columnsController = this.getController("columns");
this.createAction("onRowValidating");
if (!this._validationState) {
this.initValidationState()
}
}
initValidationState() {
this._validationState = [];
this._validationStateCache = {}
}
_rowIsValidated(change) {
const validationData = this._getValidationData(null === change || void 0 === change ? void 0 : change.key);
return !!validationData && !!validationData.validated
}
_getValidationData(key, create) {
const keyHash = (0, _common.getKeyHash)(key);
const isObjectKeyHash = (0, _type.isObject)(keyHash);
let validationData;
if (isObjectKeyHash) {
validationData = this._validationState.filter((data => (0, _common.equalByValue)(data.key, key)))[0]
} else {
validationData = this._validationStateCache[keyHash]
}
if (!validationData && create) {
validationData = {
key: key,
isValid: true
};
this._validationState.push(validationData);
if (!isObjectKeyHash) {
this._validationStateCache[keyHash] = validationData
}
}
return validationData
}
_getBrokenRules(validationData, validationResults) {
let brokenRules;
if (validationResults) {
brokenRules = validationResults.brokenRules || validationResults.brokenRule && [validationResults.brokenRule]
} else {
brokenRules = validationData.brokenRules || []
}
return brokenRules
}
_rowValidating(validationData, validationResults) {
const deferred = new _deferred.Deferred;
const change = this._editingController.getChangeByKey(null === validationData || void 0 === validationData ? void 0 : validationData.key);
const brokenRules = this._getBrokenRules(validationData, validationResults);
const isValid = validationResults ? validationResults.isValid : validationData.isValid;
const parameters = {
brokenRules: brokenRules,
isValid: isValid,
key: change.key,
newData: change.data,
oldData: this._editingController._getOldData(change.key),
promise: null,
errorText: this.getHiddenValidatorsErrorText(brokenRules)
};
this.executeAction("onRowValidating", parameters);
(0, _deferred.when)((0, _deferred.fromPromise)(parameters.promise)).always((() => {
validationData.isValid = parameters.isValid;
validationData.errorText = parameters.errorText;
deferred.resolve(parameters)
}));
return deferred.promise()
}
getHiddenValidatorsErrorText(brokenRules) {
const brokenRulesMessages = [];
(0, _iterator.each)(brokenRules, ((_, brokenRule) => {
const {
column: column
} = brokenRule;
const isGroupExpandColumn = column && void 0 !== column.groupIndex && !column.showWhenGrouped;
const isVisibleColumn = column && column.visible;
if (!brokenRule.validator.$element().parent().length && (!isVisibleColumn || isGroupExpandColumn)) {
brokenRulesMessages.push(brokenRule.message)
}
}));
return brokenRulesMessages.join(", ")
}
validate(isFull) {
let isValid = true;
const editingController = this._editingController;
const deferred = new _deferred.Deferred;
const completeList = [];
const editMode = editingController.getEditMode();
isFull = isFull || editMode === EDIT_MODE_ROW;
if (this._isValidationInProgress) {
return deferred.resolve(false).promise()
}
this._isValidationInProgress = true;
if (isFull) {
editingController.addDeferred(deferred);
const changes = editingController.getChanges();
(0, _iterator.each)(changes, ((index, _ref) => {
let {
type: type,
key: key
} = _ref;
if ("remove" !== type) {
const validationData = this._getValidationData(key, true);
const validationResult = this.validateGroup(validationData);
completeList.push(validationResult);
validationResult.done((validationResult => {
validationData.validated = true;
isValid = isValid && validationResult.isValid
}))
}
}))
} else if (this._currentCellValidator) {
const validationResult = this.validateGroup(this._currentCellValidator._findGroup());
completeList.push(validationResult);
validationResult.done((validationResult => {
isValid = validationResult.isValid
}))
}(0, _deferred.when)(...completeList).done((() => {
this._isValidationInProgress = false;
deferred.resolve(isValid)
}));
return deferred.promise()
}
validateGroup(validationData) {
var _validationResult;
const result = new _deferred.Deferred;
const validateGroup = validationData && _validation_engine.default.getGroupConfig(validationData);
let validationResult;
if (null !== validateGroup && void 0 !== validateGroup && validateGroup.validators.length) {
this.resetRowValidationResults(validationData);
validationResult = _validation_engine.default.validateGroup(validationData)
}(0, _deferred.when)((null === (_validationResult = validationResult) || void 0 === _validationResult ? void 0 : _validationResult.complete) || validationResult).done((validationResult => {
(0, _deferred.when)(this._rowValidating(validationData, validationResult)).done(result.resolve)
}));
return result.promise()
}
isRowDataModified(change) {
return !(0, _type.isEmptyObject)(change.data)
}
updateValidationState(change) {
const editMode = this._editingController.getEditMode();
const {
key: key
} = change;
const validationData = this._getValidationData(key, true);
if (!FORM_BASED_MODES.includes(editMode)) {
if ("insert" === change.type && !this.isRowDataModified(change)) {
validationData.isValid = true;
return
}
this.setDisableApplyValidationResults(true);
const groupConfig = _validation_engine.default.getGroupConfig(validationData);
if (groupConfig) {
const validationResult = _validation_engine.default.validateGroup(validationData);
(0, _deferred.when)(validationResult.complete || validationResult).done((validationResult => {
validationData.isValid = validationResult.isValid;
validationData.brokenRules = validationResult.brokenRules
}))
} else if (!validationData.brokenRules || !validationData.brokenRules.length) {
validationData.isValid = true
}
this.setDisableApplyValidationResults(false)
} else {
validationData.isValid = true
}
}
setValidator(validator) {
this._currentCellValidator = validator
}
renderCellPendingIndicator($container) {
let $indicator = $container.find(".dx-pending-indicator");
if (!$indicator.length) {
const $indicatorContainer = $container;
$indicator = (0, _renderer.default)("<div>").appendTo($indicatorContainer).addClass("dx-pending-indicator");
this._createComponent($indicator, _load_indicator.default);
$container.addClass("dx-validation-pending")
}
}
disposeCellPendingIndicator($container) {
const $indicator = $container.find(".dx-pending-indicator");
if ($indicator.length) {
const indicator = _load_indicator.default.getInstance($indicator);
if (indicator) {
indicator.dispose();
indicator.$element().remove()
}
$container.removeClass("dx-validation-pending")
}
}
validationStatusChanged(result) {
const {
validator: validator
} = result;
const validationGroup = validator.option("validationGroup");
const {
column: column
} = validator.option("dataGetter")();
this.updateCellValidationResult({
rowKey: validationGroup.key,
columnIndex: column.index,
validationResult: result
})
}
validatorInitialized(arg) {
arg.component.on("validating", this.validationStatusChanged.bind(this));
arg.component.on("validated", this.validationStatusChanged.bind(this))
}
validatorDisposing(arg) {
const validator = arg.component;
const validationGroup = validator.option("validationGroup");
const {
column: column
} = validator.option("dataGetter")();
const result = this.getCellValidationResult({
rowKey: null === validationGroup || void 0 === validationGroup ? void 0 : validationGroup.key,
columnIndex: column.index
});
if (validationResultIsValid(result) && result.status === VALIDATION_STATUS.pending) {
this.cancelCellValidationResult({
change: validationGroup,
columnIndex: column.index
})
}
}
applyValidationResult($container, result) {
const {
validator: validator
} = result;
const validationGroup = validator.option("validationGroup");
const {
column: column
} = validator.option("dataGetter")();
result.brokenRules && result.brokenRules.forEach((rule => {
rule.columnIndex = column.index;
rule.column = column
}));
if ($container) {
const validationResult = this.getCellValidationResult({
rowKey: validationGroup.key,
columnIndex: column.index
});
const requestIsDisabled = validationResultIsValid(validationResult) && validationResult.disabledPendingId === result.id;
if (this._disableApplyValidationResults || requestIsDisabled) {
return
}
if (result.status === VALIDATION_STATUS.invalid) {
const $focus = $container.find(":focus");
if (!(0, _selectors.focused)($focus)) {
_events_engine.default.trigger($focus, "focus");
_events_engine.default.trigger($focus, _pointer.default.down)
}
}
const editor = !column.editCellTemplate && this._editorFactoryController.getEditorInstance($container);
if (result.status === VALIDATION_STATUS.pending) {
if (editor) {
editor.option("validationStatus", VALIDATION_STATUS.pending)
} else {
this.renderCellPendingIndicator($container)
}
} else if (editor) {
editor.option("validationStatus", VALIDATION_STATUS.valid)
} else {
this.disposeCellPendingIndicator($container)
}
$container.toggleClass(this.addWidgetPrefix("invalid"), result.status === VALIDATION_STATUS.invalid)
}
}
_syncInternalEditingData(parameters) {
var _parameters$row;
const editingController = this._editingController;
const change = editingController.getChangeByKey(parameters.key);
const oldDataFromState = editingController._getOldData(parameters.key);
const oldData = null === (_parameters$row = parameters.row) || void 0 === _parameters$row ? void 0 : _parameters$row.oldData;
if (change && oldData && !oldDataFromState) {
editingController._addInternalData({
key: parameters.key,
oldData: oldData
})
}
}
createValidator(parameters, $container) {
const editingController = this._editingController;
const {
column: column
} = parameters;
let {
showEditorAlways: showEditorAlways
} = column;
if ((0, _type.isDefined)(column.command) || !column.validationRules || !Array.isArray(column.validationRules) || !column.validationRules.length) {
return
}
const editIndex = editingController.getIndexByKey(parameters.key, editingController.getChanges());
let needCreateValidator = editIndex > -1;
if (!needCreateValidator) {
if (!showEditorAlways) {
var _this$_columnsControl;
const visibleColumns = (null === (_this$_columnsControl = this._columnsController) || void 0 === _this$_columnsControl ? void 0 : _this$_columnsControl.getVisibleColumns()) || [];
showEditorAlways = visibleColumns.some((column => column.showEditorAlways))
}
const isEditRow = (0, _common.equalByValue)(this.option("editing.editRowKey"), parameters.key);
const isCellOrBatchEditingAllowed = editingController.isCellOrBatchEditMode() && editingController.allowUpdating({
row: parameters.row
});
needCreateValidator = isEditRow || isCellOrBatchEditingAllowed && showEditorAlways;
if (isCellOrBatchEditingAllowed && showEditorAlways) {
var _parameters$row2;
editingController._addInternalData({
key: parameters.key,
oldData: (null === (_parameters$row2 = parameters.row) || void 0 === _parameters$row2 ? void 0 : _parameters$row2.oldData) ?? parameters.data
})
}
}
if (needCreateValidator) {
if ($container && !$container.length) {
_ui2.default.log("E1050");
return
}
this._syncInternalEditingData(parameters);
const validationData = this._getValidationData(parameters.key, true);
const getValue = () => {
const change = editingController.getChangeByKey(null === validationData || void 0 === validationData ? void 0 : validationData.key);
const value = column.calculateCellValue((null === change || void 0 === change ? void 0 : change.data) || {});
return void 0 !== value ? value : parameters.value
};
const useDefaultValidator = $container && $container.hasClass("dx-widget");
$container && $container.addClass(this.addWidgetPrefix("validator"));
const validator = new _validator.default($container || (0, _renderer.default)("<div>"), {
name: column.caption,
validationRules: (0, _extend.extend)(true, [], column.validationRules),
validationGroup: validationData,
adapter: useDefaultValidator ? null : {
getValue: getValue,
applyValidationResults: result => {
this.applyValidationResult($container, result)
}
},
dataGetter() {
const key = null === validationData || void 0 === validationData ? void 0 : validationData.key;
const change = editingController.getChangeByKey(key);
const oldData = editingController._getOldData(key);
return {
data: (0, _array_utils.createObjectWithChanges)(oldData, null === change || void 0 === change ? void 0 : change.data),
column: column
}
},
onInitialized: this.validatorInitialized.bind(this),
onDisposing: this.validatorDisposing.bind(this)
});
if (useDefaultValidator) {
const adapter = validator.option("adapter");
if (adapter) {
const originBypass = adapter.bypass;
const defaultAdapterBypass = () => parameters.row.isNewRow && !this._isValidationInProgress && !editingController.isCellModified(parameters);
adapter.getValue = getValue;
adapter.validationRequestsCallbacks = [];
adapter.bypass = () => originBypass.call(adapter) || defaultAdapterBypass()
}
}
return validator
}
return
}
setDisableApplyValidationResults(flag) {
this._disableApplyValidationResults = flag
}
getDisableApplyValidationResults() {
return this._disableApplyValidationResults
}
isCurrentValidatorProcessing(_ref2) {
let {
rowKey: rowKey,
columnIndex: columnIndex
} = _ref2;
return this._currentCellValidator && (0, _common.equalByValue)(this._currentCellValidator.option("validationGroup").key, rowKey) && this._currentCellValidator.option("dataGetter")().column.index === columnIndex
}
validateCell(validator) {
const cellParams = {
rowKey: validator.option("validationGroup").key,
columnIndex: validator.option("dataGetter")().column.index,
validationResult: null
};
let validationResult = this.getCellValidationResult(cellParams);
const stateRestored = validationResultIsValid(validationResult);
const adapter = validator.option("adapter");
if (!stateRestored) {
validationResult = validator.validate()
} else {
const currentCellValue = adapter.getValue();
if (!(0, _common.equalByValue)(currentCellValue, validationResult.value)) {
validationResult = validator.validate()
}
}
const deferred = new _deferred.Deferred;
if (stateRestored && validationResult.status === VALIDATION_STATUS.pending) {
this.updateCellValidationResult(cellParams);
adapter.applyValidationResults(validationResult)
}(0, _deferred.when)(validationResult.complete || validationResult).done((validationResult => {
stateRestored && adapter.applyValidationResults(validationResult);
deferred.resolve(validationResult)
}));
return deferred.promise()
}
updateCellValidationResult(_ref3) {
let {
rowKey: rowKey,
columnIndex: columnIndex,
validationResult: validationResult
} = _ref3;
const validationData = this._getValidationData(rowKey);
if (!validationData) {
return
}
if (!validationData.validationResults) {
validationData.validationResults = {}
}
let result;
if (validationResult) {
result = (0, _extend.extend)({}, validationResult);
validationData.validationResults[columnIndex] = result;
if (validationResult.status === VALIDATION_STATUS.pending) {
if (this._editingController.getEditMode() === EDIT_MODE_CELL) {
result.deferred = new _deferred.Deferred;
result.complete.always((() => {
result.deferred.resolve()
}));
this._editingController.addDeferred(result.deferred)
}
if (this._disableApplyValidationResults) {
result.disabledPendingId = validationResult.id;
return
}
}
} else {
result = validationData.validationResults[columnIndex]
}
if (result && result.disabledPendingId) {
delete result.disabledPendingId
}
}
getCellValidationResult(_ref4) {
var _validationData$valid;
let {
rowKey: rowKey,
columnIndex: columnIndex
} = _ref4;
const validationData = this._getValidationData(rowKey, true);
return null === validationData || void 0 === validationData || null === (_validationData$valid = validationData.validationResults) || void 0 === _validationData$valid ? void 0 : _validationData$valid[columnIndex]
}
removeCellValidationResult(_ref5) {
let {
change: change,
columnIndex: columnIndex
} = _ref5;
const validationData = this._getValidationData(null === change || void 0 === change ? void 0 : change.key);
if (validationData && validationData.validationResults) {
this.cancelCellValidationResult({
change: change,
columnIndex: columnIndex
});
delete validationData.validationResults[columnIndex]
}
}
cancelCellValidationResult(_ref6) {
let {
change: change,
columnIndex: columnIndex
} = _ref6;
const validationData = this._getValidationData(change.key);
if (change && validationData.validationResults) {
const result = validationData.validationResults[columnIndex];
if (result) {
result.deferred && result.deferred.reject("cancel");
validationData.validationResults[columnIndex] = "cancel"
}
}
}
resetRowValidationResults(validationData) {
if (validationData) {
validationData.validationResults && delete validationData.validationResults;
delete validationData.validated
}
}
isInvalidCell(_ref7) {
let {
rowKey: rowKey,
columnIndex: columnIndex
} = _ref7;
const result = this.getCellValidationResult({
rowKey: rowKey,
columnIndex: columnIndex
});
return validationResultIsValid(result) && result.status === VALIDATION_STATUS.invalid
}
getCellValidator(_ref8) {
let {
rowKey: rowKey,
columnIndex: columnIndex
} = _ref8;
const validationData = this._getValidationData(rowKey);
const groupConfig = validationData && _validation_engine.default.getGroupConfig(validationData);
const validators = groupConfig && groupConfig.validators;
return validators && validators.filter((v => {
const {
column: column
} = v.option("dataGetter")();
return column ? column.index === columnIndex : false
}))[0]
}
setCellValidationStatus(cellOptions) {
const validationResult = this.getCellValidationResult({
rowKey: cellOptions.key,
columnIndex: cellOptions.column.index
});
if ((0, _type.isDefined)(validationResult)) {
cellOptions.validationStatus = "cancel" !== validationResult ? validationResult.status : "cancel"
} else {
delete cellOptions.validationStatus
}
}
}
exports.ValidatingController = ValidatingController;
const validatingEditingExtender = Base => class extends Base {
processDataItemTreeListHack(item) {
super.processDataItem.apply(this, arguments)
}
processItemsTreeListHack(items, e) {
return super.processItems.apply(this, arguments)
}
_addChange(changeParams) {
const change = super._addChange.apply(this, arguments);
if (change && "remove" !== changeParams.type) {
this._validatingController.updateValidationState(change)
}
return change
}
_handleChangesChange(args) {
super._handleChangesChange.apply(this, arguments);
args.value.forEach((change => {
if (void 0 === this._validatingController._getValidationData(change.key)) {
this._validatingController.updateValidationState(change)
}
}))
}
_updateRowAndPageIndices() {
const that = this;
const startInsertIndex = that.getView("rowsView").getTopVisibleItemIndex();
let rowIndex = startInsertIndex;
(0, _iterator.each)(that.getChanges(), ((_, _ref9) => {
let {
key: key,
type: type
} = _ref9;
const validationData = this._validatingController._getValidationData(key);
if (validationData && !validationData.isValid && validationData.pageIndex !== that._pageIndex) {
validationData.pageIndex = that._pageIndex;
if ("insert" === type) {
validationData.rowIndex = startInsertIndex
} else {
validationData.rowIndex = rowIndex
}
rowIndex++
}
}))
}
_getValidationGroupsInForm(detailOptions) {
const validationData = this._validatingController._getValidationData(detailOptions.key, true);
return {
validationGroup: validationData
}
}
_validateEditFormAfterUpdate(row, isCustomSetCellValue) {
if (isCustomSetCellValue && this._editForm) {
this._editForm.validate()
}
super._validateEditFormAfterUpdate.apply(this, arguments)
}
_prepareEditCell(params) {
const isNotCanceled = super._prepareEditCell.apply(this, arguments);
if (isNotCanceled && params.column.showEditorAlways) {
this._validatingController.updateValidationState({
key: params.key
})
}
return isNotCanceled
}
processItems(items, changeType) {
const changes = this.getChanges();
const getIndexByChange = (change, items) => {
let index = -1;
const isInsert = "insert" === change.type;
const {
key: key
} = change;
(0, _iterator.each)(items, ((i, item) => {
if ((0, _common.equalByValue)(key, isInsert ? item.key : this._dataController.keyOf(item))) {
index = i;
return false
}
return
}));
return index
};
items = super.processItems(items, changeType);
const itemsCount = items.length;
if (this.getEditMode() === EDIT_MODE_BATCH && "prepend" !== changeType && "append" !== changeType) {
changes.forEach((change => {
const {
key: key
} = change;
const validationData = this._validatingController._getValidationData(key);
if (validationData && change.type && validationData.pageIndex === this._pageIndex && (null === change || void 0 === change ? void 0 : change.pageIndex) !== this._pageIndex) {
! function(change, validationData) {
const data = {
key: change.key
};
const index = getIndexByChange(change, items);
if (index >= 0) {
return
}
validationData.rowIndex = validationData.rowIndex > itemsCount ? validationData.rowIndex % itemsCount : validationData.rowIndex;
const {
rowIndex: rowIndex
} = validationData;
data[INSERT_INDEX] = 1;
items.splice(rowIndex, 0, data)
}(change, validationData)
}
}))
}
return items
}
processDataItem(item) {
const isInserted = item.data[INSERT_INDEX];
const key = isInserted ? item.data.key : item.key;
const editMode = this.getEditMode();
if (editMode === EDIT_MODE_BATCH && isInserted && key) {
const changes = this.getChanges();
const editIndex = _m_utils.default.getIndexByKey(key, changes);
if (editIndex >= 0) {
const change = changes[editIndex];
if ("insert" !== change.type) {
const oldData = this._getOldData(change.key);
item.data = (0, _extend.extend)(true, {}, oldData, change.data);
item.key = key
}
}
}
super.processDataItem.apply(this, arguments)
}
_createInvisibleColumnValidators(changes) {
const that = this;
const columns = this._columnsController.getColumns();
const invisibleColumns = this._columnsController.getInvisibleColumns().filter((column => !column.isBand));
const groupColumns = this._columnsController.getGroupColumns().filter((column => !column.showWhenGrouped && -1 === invisibleColumns.indexOf(column)));
const invisibleColumnValidators = [];
const isCellVisible = (column, rowKey) => this._dataController.getRowIndexByKey(rowKey) >= 0 && invisibleColumns.indexOf(column) < 0;
invisibleColumns.push(...groupColumns);
if (!FORM_BASED_MODES.includes(this.getEditMode())) {
(0, _iterator.each)(columns, ((_, column) => {
changes.forEach((change => {
let data;
if (isCellVisible(column, change.key)) {
return
}
if ("insert" === change.type) {
data = change.data
} else if ("update" === change.type) {
const oldData = that._getOldData(change.key);
if (!(0, _type.isDefined)(oldData)) {
return
}
data = (0, _array_utils.createObjectWithChanges)(oldData, change.data)
}
if (data) {
const validator = this._validatingController.createValidator({
column: column,
key: change.key,
value: column.calculateCellValue(data)
});
if (validator) {
invisibleColumnValidators.push(validator)
}
}
}))
}))
}
return function() {
invisibleColumnValidators.forEach((validator => {
validator.dispose()
}))
}
}
_beforeSaveEditData(change, editIndex) {
let result = super._beforeSaveEditData.apply(this, arguments);
const validationData = this._validatingController._getValidationData(null === change || void 0 === change ? void 0 : change.key, true);
if (change) {
const isValid = "remove" === change.type || validationData.isValid;
result = result || !isValid
} else {
const disposeValidators = this._createInvisibleColumnValidators(this.getChanges());
result = new _deferred.Deferred;
this.executeOperation(result, (() => {
this._validatingController.validate(true).done((isFullValid => {
disposeValidators();
this._updateRowAndPageIndices();
switch (this.getEditMode()) {
case EDIT_MODE_CELL:
if (!isFullValid) {
this._focusEditingCell()
}
break;
case EDIT_MODE_BATCH:
if (!isFullValid) {
this._resetEditRowKey();
this._resetEditColumnName();
this._dataController.updateItems()
}
}
result.resolve(!isFullValid)
}))
}))
}
return result.promise ? result.promise() : result
}
_beforeEditCell(rowIndex, columnIndex, item) {
const result = super._beforeEditCell(rowIndex, columnIndex, item);
if (this.getEditMode() === EDIT_MODE_CELL) {
const $cell = this._rowsView._getCellElement(rowIndex, columnIndex);
const validator = $cell && $cell.data("dxValidator");
const rowOptions = $cell && $cell.closest(".dx-row").data("options");
const value = validator && validator.option("adapter").getValue();
if (validator && cellValueShouldBeValidated(value, rowOptions)) {
const deferred = new _deferred.Deferred;
(0, _deferred.when)(this._validatingController.validateCell(validator), result).done(((validationResult, result) => {
deferred.resolve(validationResult.status === VALIDATION_STATUS.valid && result)
}));
return deferred.promise()
}
if (!validator) {
return result
}
}
return false
}
_afterSaveEditData(cancel) {
let $firstErrorRow;
const isCellEditMode = this.getEditMode() === EDIT_MODE_CELL;
(0, _iterator.each)(this.getChanges(), ((_, change) => {
const $errorRow = this._showErrorRow(change);
$firstErrorRow = $firstErrorRow || $errorRow
}));
if ($firstErrorRow) {
const scrollable = this._rowsView.getScrollable();
if (scrollable) {
scrollable.update();
scrollable.scrollToElement($firstErrorRow)
}
}
if (cancel && isCellEditMode && this._needUpdateRow()) {
const editRowIndex = this.getEditRowIndex();
this._dataController.updateItems({
changeType: "update",
rowIndices: [editRowIndex]
});
this._focusEditingCell()
} else if (!cancel) {
let shouldResetValidationState = true;
if (isCellEditMode) {
const columns = this._columnsController.getColumns();
const columnsWithValidatingEditors = columns.filter((col => {
var _col$validationRules;
return col.showEditorAlways && (null === (_col$validationRules = col.validationRules) || void 0 === _col$validationRules ? void 0 : _col$validationRules.length) > 0
})).length > 0;
shouldResetValidationState = !columnsWithValidatingEditors
}
if (shouldResetValidationState) {
this._validatingController.initValidationState()
}
}
}
_handleDataChanged(args) {
const validationState = this._validatingController._validationState;
if ("standard" === this.option("scrolling.mode")) {
this.resetRowAndPageIndices()
}
if ("prepend" === args.changeType) {
(0, _iterator.each)(validationState, ((_, validationData) => {
validationData.rowIndex += args.items.length
}))
}
super._handleDataChanged(args)
}
resetRowAndPageIndices() {
const validationState = this._validatingController._validationState;
(0, _iterator.each)(validationState, ((_, validationData) => {
if (validationData.pageIndex !== this._pageIndex) {
delete validationData.pageIndex;
delete validationData.rowIndex
}
}))
}
_beforeCancelEditData() {
this._validatingController.initValidationState();
super._beforeCancelEditData()
}
_showErrorRow(change) {
let $popupContent;
const items = this._dataController.items();
const rowIndex = this.getIndexByKey(change.key, items);
const validationData = this._validatingController._getValidationData(change.key);
if (!(null !== validationData && void 0 !== validationData && validationData.isValid) && null !== validationData && void 0 !== validationData && validationData.errorText && rowIndex >= 0) {
$popupContent = this.getPopupContent();
return this._errorHandlingController && this._errorHandlingController.renderErrorRow(null === validationData || void 0 === validationData ? void 0 : validationData.errorText, rowIndex, $popupContent)
}
}
updateFieldValue(e) {
const deferred = new _deferred.Deferred;
this._validatingController.removeCellValidationResult({
change: this.getChangeByKey(e.key),
columnIndex: e.column.index
});
super.updateFieldValue.apply(this, arguments).done((() => {
const currentValidator = this._validatingController.getCellValidator({
rowKey: e.key,
columnIndex: e.column.index
});
(0, _deferred.when)(currentValidator && this._validatingController.validateCell(currentValidator)).done((validationResult => {
this._editorFactoryController.refocus();
deferred.resolve(validationResult)
}))
}));
return deferred.promise()
}
highlightDataCell($cell, parameters) {
super.highlightDataCell.apply(this, arguments);
this._validatingController.setCellValidationStatus(parameters);
const isEditableCell = !!parameters.setValue;
const cellModified = this.isCellModified(parameters);
const isValidated = (0, _type.isDefined)(parameters.validationStatus);
const needValidation = cellModified && parameters.column.setCellValue || isEditableCell && !cellModified && !(parameters.row.isNewRow || !isValidated);
if (needValidation) {
const validator = $cell.data("dxValidator");
if (validator) {
(0, _deferred.when)(this._validatingController.validateCell(validator)).done((() => {
this._validatingController.setCellValidationStatus(parameters)
}))
}
}
}
getChangeByKey(key) {
const changes = this.getChanges();
return changes[_m_utils.default.getIndexByKey(key, changes)]
}
isCellModified(parameters) {
const cellModified = super.isCellModified(parameters);
const change = this.getChangeByKey(parameters.key);
const isCellInvalid = !!parameters.row && this._validatingController.isInvalidCell({
rowKey: parameters.key,
columnIndex: parameters.column.index
});
return cellModified || this._validatingController._rowIsValidated(change) && isCellInvalid
}
};
exports.validatingEditingExtender = validatingEditingExtender;
const getWidthOfVisibleCells = function(that, element) {
const rowIndex = (0, _renderer.default)(element).closest("tr").index();
const $cellElements = (0, _renderer.default)(that._rowsView.getRowElement(rowIndex)).first().children().filter(":not(.dx-hidden-cell)");
return that._rowsView._getWidths($cellElements).reduce(((w1, w2) => w1 + w2), 0)
};
const getBoundaryNonFixedColumnsInfo = function(fixedColumns) {
let firstNonFixedColumnIndex;
let lastNonFixedColumnIndex;
fixedColumns.some(((column, index) => {
if ("transparent" === column.command) {
firstNonFixedColumnIndex = 0 === index ? -1 : index;
lastNonFixedColumnIndex = index === fixedColumns.length - 1 ? -1 : index + column.colspan - 1;
return true
}
return
}));
return {
startColumnIndex: firstNonFixedColumnIndex,
endColumnIndex: lastNonFixedColumnIndex
}
};
const validatingEditorFactoryExtender = Base => class extends Base {
_showRevertButton($container) {
var _this$_revertTooltip, _$tooltipElement2;
let $tooltipElement = null === (_this$_revertTooltip = this._revertTooltip) || void 0 === _this$_revertTooltip ? void 0 : _this$_revertTooltip.$element();
if (!$container || !$container.length) {
var _$tooltipElement;
null === (_$tooltipElement = $tooltipElement) || void 0 === _$tooltipElement || _$tooltipElement.remove();
this._revertTooltip = void 0;
return
}
if ($container.find($tooltipElement).length) {
var _this$_revertTooltip2;
null === (_this$_revertTooltip2 = this._revertTooltip) || void 0 === _this$_revertTooltip2 || _this$_revertTooltip2.repaint();
return
}
const $overlayContainer = this.getRevertButtonContainer($container);
const revertTooltipClass = this.addWidgetPrefix("revert-tooltip");
null === (_$tooltipElement2 = $tooltipElement) || void 0 === _$tooltipElement2 || _$tooltipElement2.remove();
$tooltipElement = (0, _renderer.default)("<div>").addClass(revertTooltipClass).appendTo($container);
const tooltipOptions = {
animation: null,
visible: true,
width: "auto",
height: "auto",
shading: false,
container: $overlayContainer,
propagateOutsideClick: true,
hideOnOutsideClick: false,
wrapperAttr: {
class: revertTooltipClass
},
contentTemplate: () => {
const $buttonElement = (0, _renderer.default)("<div>").addClass("dx-revert-button");
const buttonOptions = {
icon: "revert",
hint: this.option("editing.texts.validationCancelChanges"),
elementAttr: {
id: "dxRevertButton",
"aria-label": _message.default.format("dxDataGrid-ariaRevertButton")
},
onClick: () => {
this._editingController.cancelEditData()
}
};
return new _button.default($buttonElement, buttonOptions).$element()
},
position: {
my: "left top",
at: "right top",
offset: "1 0",
collision: "flip",
boundaryOffset: "0 0",
boundary: this._rowsView.element(),
of: $container
},
onPositioned: this.overlayPositionedHandler.bind(this)
};
this._revertTooltip = new _ui.default($tooltipElement, tooltipOptions)
}
_hideFixedGroupCell($cell, overlayOptions) {
var _this$_rowsView, _this$_rowsView$isFix;
let $nextFixedRowElement;
let $groupCellElement;
const isFixedColumns = null === (_this$_rowsView = this._rowsView) || void 0 === _this$_rowsView || null === (_this$_rowsView$isFix = _this$_rowsView.isFixedColumns) || void 0 === _this$_rowsView$isFix ? void 0 : _this$_rowsView$isFix.call(_this$_rowsView);
const isFormOrPopupEditMode = this._editingController.isFormOrPopupEditMode();
if (isFixedColumns && !isFormOrPopupEditMode) {
const nextRowOptions = $cell.closest(".dx-row").next().data("options");
if (nextRowOptions && "group" === nextRowOptions.rowType) {
$nextFixedRowElement = (0, _renderer.default)(this._rowsView.getRowElement(nextRowOptions.rowIndex)).last();
$groupCellElement = $nextFixedRowElement.find(".dx-group-cell");
if ($groupCellElement.length && "hidden" !== $groupCellElement.get(0).style.visibility) {
$groupCellElement.css("visibility", "hidden");
overlayOptions.onDisposing = function() {
$groupCellElement.css("visibility", "")
}
}
}
}
}
_showValidationMessage($cell, messages, alignment) {
const editorPopup = $cell.find(".dx-dropdowneditor-overlay").data("dxPopup");
const isOverlayVisible = editorPopup && editorPopup.option("visible");
const myPosition = isOverlayVisible ? "top right" : `top ${alignment}`;
const atPosition = isOverlayVisible ? "top left" : `bottom ${alignment}`;
const $overlayContainer = this.getValidationMessageContainer($cell);
let errorMessageText = "";
messages && messages.forEach((message => {
errorMessageText += (error