UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,298 lines (1,097 loc) • 94.8 kB
"use strict"; var $ = require("../../core/renderer"), domAdapter = require("../../core/dom_adapter"), window = require("../../core/utils/window").getWindow(), eventsEngine = require("../../events/core/events_engine"), Guid = require("../../core/guid"), typeUtils = require("../../core/utils/type"), each = require("../../core/utils/iterator").each, deepExtendArraySafe = require("../../core/utils/object").deepExtendArraySafe, extend = require("../../core/utils/extend").extend, modules = require("./ui.grid_core.modules"), clickEvent = require("../../events/click"), gridCoreUtils = require("./ui.grid_core.utils"), _getIndexByKey = gridCoreUtils.getIndexByKey, eventUtils = require("../../events/utils"), addNamespace = eventUtils.addNamespace, dialog = require("../dialog"), messageLocalization = require("../../localization/message"), Button = require("../button"), Popup = require("../popup"), errors = require("../widget/ui.errors"), devices = require("../../core/devices"), Form = require("../form"), holdEvent = require("../../events/hold"), deferredUtils = require("../../core/utils/deferred"), when = deferredUtils.when, Deferred = deferredUtils.Deferred; var EDIT_FORM_CLASS = "edit-form", EDIT_FORM_ITEM_CLASS = "edit-form-item", FOCUS_OVERLAY_CLASS = "focus-overlay", READONLY_CLASS = "readonly", EDIT_POPUP_CLASS = "edit-popup", FORM_BUTTONS_CONTAINER_CLASS = "form-buttons-container", ADD_ROW_BUTTON_CLASS = "addrow-button", LINK_CLASS = "dx-link", EDITOR_CELL_CLASS = "dx-editor-cell", ROW_SELECTED = "dx-selection", EDIT_ROW = "dx-edit-row", EDIT_BUTTON_CLASS = "dx-edit-button", COMMAND_EDIT_CLASS = "dx-command-edit", COMMAND_EDIT_WITH_ICONS_CLASS = COMMAND_EDIT_CLASS + "-with-icons", BUTTON_CLASS = "dx-button", INSERT_INDEX = "__DX_INSERT_INDEX__", ROW_CLASS = "dx-row", ROW_REMOVED = "dx-row-removed", ROW_INSERTED = "dx-row-inserted", ROW_MODIFIED = "dx-row-modified", CELL_MODIFIED = "dx-cell-modified", CELL_HIGHLIGHT_OUTLINE = "dx-highlight-outline", EDITING_NAMESPACE = "dxDataGridEditing", DATA_ROW_CLASS = "dx-data-row", CELL_FOCUS_DISABLED_CLASS = "dx-cell-focus-disabled", EDITORS_INPUT_SELECTOR = "input:not([type='hidden'])", FOCUSABLE_ELEMENT_SELECTOR = "[tabindex], " + EDITORS_INPUT_SELECTOR, EDIT_MODE_BATCH = "batch", EDIT_MODE_ROW = "row", EDIT_MODE_CELL = "cell", EDIT_MODE_FORM = "form", EDIT_MODE_POPUP = "popup", DATA_EDIT_DATA_INSERT_TYPE = "insert", DATA_EDIT_DATA_UPDATE_TYPE = "update", DATA_EDIT_DATA_REMOVE_TYPE = "remove", POINTER_EVENTS_NONE_CLASS = "dx-pointer-events-none", POINTER_EVENTS_TARGET_CLASS = "dx-pointer-events-target", EDIT_MODES = [EDIT_MODE_BATCH, EDIT_MODE_ROW, EDIT_MODE_CELL, EDIT_MODE_FORM, EDIT_MODE_POPUP], ROW_BASED_MODES = [EDIT_MODE_ROW, EDIT_MODE_FORM, EDIT_MODE_POPUP], CELL_BASED_MODES = [EDIT_MODE_BATCH, EDIT_MODE_CELL], MODES_WITH_DELAYED_FOCUS = [EDIT_MODE_ROW, EDIT_MODE_FORM]; var EDIT_LINK_CLASS = { saveEditData: "dx-link-save", cancelEditData: "dx-link-cancel", editRow: "dx-link-edit", undeleteRow: "dx-link-undelete", deleteRow: "dx-link-delete", addRowByRowIndex: "dx-link-add" }, EDIT_ICON_CLASS = { saveEditData: "dx-icon-save", cancelEditData: "dx-icon-revert", editRow: "dx-icon-edit", undeleteRow: "dx-icon-revert", deleteRow: "dx-icon-trash", addRowByRowIndex: "dx-icon-add" }; var _getEditMode = function _getEditMode(that) { var editMode = that.option("editing.mode"); if (EDIT_MODES.indexOf(editMode) !== -1) { return editMode; } return EDIT_MODE_ROW; }; var _isRowEditMode = function _isRowEditMode(that) { var editMode = _getEditMode(that); return ROW_BASED_MODES.indexOf(editMode) !== -1; }; var EditingController = modules.ViewController.inherit(function () { var getDefaultEditorTemplate = function getDefaultEditorTemplate(that) { return function (container, options) { var $editor = $("<div>").appendTo(container); that.getController("editorFactory").createEditor($editor, extend({}, options.column, { value: options.value, setValue: options.setValue, row: options.row, parentType: "dataRow", width: null, readOnly: !options.setValue, isOnForm: options.isOnForm, id: options.id, updateValueImmediately: _isRowEditMode(that) })); }; }; var editCellTemplate = function editCellTemplate(container, options) { var editingTexts, editingOptions, $container = $(container), editingController = options.component.getController("editing"), isRowMode = _isRowEditMode(editingController); if (options.rowType === "data") { $container.css("textAlign", "center"); options.rtlEnabled = editingController.option("rtlEnabled"); editingOptions = editingController.option("editing") || {}; editingTexts = editingOptions.texts || {}; if (options.row && options.row.rowIndex === editingController._getVisibleEditRowIndex() && isRowMode) { editingController._createLink($container, editingTexts.saveRowChanges, "saveEditData", options, editingOptions.useIcons); editingController._createLink($container, editingTexts.cancelRowChanges, "cancelEditData", options, editingOptions.useIcons); } else { editingController._createEditingLinks($container, options, editingOptions, isRowMode); } } else { $container.get(0).innerHTML = "&nbsp;"; } }; return { init: function init() { var that = this; that._editRowIndex = -1; that._editData = []; that._editColumnIndex = -1; that._columnsController = that.getController("columns"); that._dataController = that.getController("data"); that._rowsView = that.getView("rowsView"); if (!that._dataChangedHandler) { that._dataChangedHandler = that._handleDataChanged.bind(that); that._dataController.changed.add(that._dataChangedHandler); } if (!that._saveEditorHandler) { that.createAction("onInitNewRow", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onRowInserting", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onRowInserted", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onEditingStart", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onRowUpdating", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onRowUpdated", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onRowRemoving", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onRowRemoved", { excludeValidators: ["disabled", "readOnly"] }); that._saveEditorHandler = that.createAction(function (e) { var event = e.event, isEditorPopup, isDomElement, isFocusOverlay, isAddRowButton, isCellEditMode, $target; if (!_isRowEditMode(that) && !that._editCellInProgress) { $target = $(event.target); isEditorPopup = $target.closest(".dx-dropdowneditor-overlay").length; isDomElement = $target.closest(window.document).length; isAddRowButton = $target.closest("." + that.addWidgetPrefix(ADD_ROW_BUTTON_CLASS)).length; isFocusOverlay = $target.hasClass(that.addWidgetPrefix(FOCUS_OVERLAY_CLASS)); isCellEditMode = _getEditMode(that) === EDIT_MODE_CELL; if (!isEditorPopup && !isFocusOverlay && !(isAddRowButton && isCellEditMode && that.isEditing()) && isDomElement) { that._closeEditItem.bind(that)($target); } } }); eventsEngine.on(domAdapter.getDocument(), clickEvent.name, that._saveEditorHandler); } that._updateEditColumn(); that._updateEditButtons(); }, _closeEditItem: function _closeEditItem($targetElement) { var isDataRow = $targetElement.closest("." + DATA_ROW_CLASS).length, $targetCell = $targetElement.closest("." + ROW_CLASS + "> td"), columnIndex = $targetCell[0] && $targetCell[0].cellIndex, rowIndex = this.getView("rowsView").getRowIndex($targetCell.parent()), visibleColumns = this._columnsController.getVisibleColumns(), // TODO jsdmitry: Move this code to _rowClick method of rowsView allowEditing = visibleColumns[columnIndex] && visibleColumns[columnIndex].allowEditing; if (this.isEditing() && (!isDataRow || isDataRow && !allowEditing && !this.isEditCell(rowIndex, columnIndex))) { this.closeEditCell(); } }, _handleDataChanged: function _handleDataChanged(args) { var that = this, editForm = that._editForm; if (that.option("scrolling.mode") === "standard") { that.resetRowAndPageIndices(); } if (args.changeType === "prepend") { each(that._editData, function (_, editData) { editData.rowIndex += args.items.length; if (editData.type === DATA_EDIT_DATA_INSERT_TYPE) { editData.key.rowIndex += args.items.length; editData.key.dataRowIndex += args.items.filter(function (item) { return item.rowType === "data"; }).length; } }); } if (args.changeType === "refresh" && _getEditMode(that) === EDIT_MODE_POPUP && editForm && editForm.option("visible")) { editForm.repaint(); } }, isRowEditMode: function isRowEditMode() { return _isRowEditMode(this); }, getEditMode: function getEditMode() { return _getEditMode(this); }, getFirstEditableColumnIndex: function getFirstEditableColumnIndex() { var columnsController = this.getController("columns"), columnIndex; if (_getEditMode(this) === EDIT_MODE_FORM && this._firstFormItem) { columnIndex = this._firstFormItem.column.index; } else { var visibleColumns = columnsController.getVisibleColumns(); each(visibleColumns, function (index, column) { if (column.allowEditing) { columnIndex = index; return false; } }); } return columnIndex; }, getFirstEditableCellInRow: function getFirstEditableCellInRow(rowIndex) { return this.getView("rowsView")._getCellElement(rowIndex ? rowIndex : 0, this.getFirstEditableColumnIndex()); }, getFocusedCellInRow: function getFocusedCellInRow(rowIndex) { return this.getFirstEditableCellInRow(rowIndex); }, getIndexByKey: function getIndexByKey(key, items) { return _getIndexByKey(key, items); }, hasChanges: function hasChanges() { var that = this, result = false; for (var i = 0; i < that._editData.length; i++) { if (that._editData[i].type) { result = true; break; } } return result; }, dispose: function dispose() { this.callBase(); clearTimeout(this._inputFocusTimeoutID); eventsEngine.off(domAdapter.getDocument(), clickEvent.name, this._saveEditorHandler); }, optionChanged: function optionChanged(args) { if (args.name === "editing") { this.init(); args.handled = true; } else { this.callBase(args); } }, publicMethods: function publicMethods() { return ["insertRow", "addRow", "removeRow", "deleteRow", "undeleteRow", "editRow", "editCell", "closeEditCell", "saveEditData", "cancelEditData", "hasEditData"]; }, refresh: function refresh() { if (_getEditMode(this) === EDIT_MODE_CELL) return; if (_getEditMode(this) !== EDIT_MODE_BATCH) { this.init(); } else { this._editRowIndex = -1; this._editColumnIndex = -1; } }, isEditing: function isEditing() { return this._editRowIndex > -1; }, isEditRow: function isEditRow(rowIndex) { var editMode = _getEditMode(this); return this._getVisibleEditRowIndex() === rowIndex && ROW_BASED_MODES.indexOf(editMode) !== -1; }, getEditRowKey: function getEditRowKey() { var items = this._dataController.items(), item = items[this._getVisibleEditRowIndex()]; return item && item.key; }, getEditFormRowIndex: function getEditFormRowIndex() { var editMode = _getEditMode(this); return editMode === EDIT_MODE_FORM || editMode === EDIT_MODE_POPUP ? this._getVisibleEditRowIndex() : -1; }, isEditCell: function isEditCell(rowIndex, columnIndex) { return this._getVisibleEditRowIndex() === rowIndex && this._editColumnIndex === columnIndex; }, getPopupContent: function getPopupContent() { var editMode = _getEditMode(this), popupVisible = this._editPopup && this._editPopup.option("visible"); if (editMode === EDIT_MODE_POPUP && popupVisible) { return this._editPopup.$content(); } }, getEditForm: function getEditForm() { return this._editForm; }, _needInsertItem: function _needInsertItem(editData, changeType) { var that = this, dataSource = that._dataController.dataSource(), scrollingMode = that.option("scrolling.mode"), pageIndex = dataSource.pageIndex(), beginPageIndex = dataSource.beginPageIndex ? dataSource.beginPageIndex() : pageIndex, endPageIndex = dataSource.endPageIndex ? dataSource.endPageIndex() : pageIndex; if (scrollingMode !== "standard") { switch (changeType) { case "append": return editData.key.pageIndex === endPageIndex; case "prepend": return editData.key.pageIndex === beginPageIndex; case "refresh": editData.key.rowIndex = 0; editData.key.dataRowIndex = 0; editData.key.pageIndex = 0; break; default: return editData.key.pageIndex >= beginPageIndex && editData.key.pageIndex <= endPageIndex; } } return editData.key.pageIndex === pageIndex; }, _generateNewItem: function _generateNewItem(key) { var item = { key: key }; if (key && key[INSERT_INDEX]) { item[INSERT_INDEX] = key[INSERT_INDEX]; } return item; }, processItems: function processItems(items, changeType) { var that = this, i, key, item, editData = that._editData; that.update(changeType); for (i = 0; i < editData.length; i++) { key = editData[i].key; item = that._generateNewItem(key); if (editData[i].type === DATA_EDIT_DATA_INSERT_TYPE && that._needInsertItem(editData[i], changeType, items, item)) { items.splice(key.dataRowIndex, 0, item); } } return items; }, processDataItem: function processDataItem(item, options, generateDataValues) { var that = this, data, editMode, editData, editIndex, columns = options.visibleColumns, key = item.data[INSERT_INDEX] ? item.data.key : item.key; editIndex = _getIndexByKey(key, that._editData); if (editIndex >= 0) { editMode = _getEditMode(that); editData = that._editData[editIndex]; data = editData.data; item.isEditing = options.rowIndex === that._getVisibleEditRowIndex(); switch (editData.type) { case DATA_EDIT_DATA_INSERT_TYPE: if (editMode === EDIT_MODE_POPUP) { item.visible = false; } item.inserted = true; item.key = key; item.data = data; break; case DATA_EDIT_DATA_UPDATE_TYPE: item.modified = true; item.oldData = item.data; item.data = gridCoreUtils.createObjectWithChanges(item.data, data); item.modifiedValues = generateDataValues(data, columns); break; case DATA_EDIT_DATA_REMOVE_TYPE: if (editMode === EDIT_MODE_BATCH) { item.data = gridCoreUtils.createObjectWithChanges(item.data, data); } item.removed = true; break; } } }, /** * @name dxDataGridMethods.insertRow * @publicName insertRow() * @deprecated dxDataGridMethods.addRow */ insertRow: function insertRow() { errors.log("W0002", "dxDataGrid", "insertRow", "15.2", "Use the 'addRow' method instead"); return this.addRow(); }, _initNewRow: function _initNewRow(options, insertKey) { this.executeAction("onInitNewRow", options); var rows = this._dataController.items(), row = rows[insertKey.rowIndex]; if (row && (!row.isEditing && row.rowType === "detail" || row.rowType === "detailAdaptive")) { insertKey.rowIndex++; } insertKey.dataRowIndex = rows.filter(function (row, index) { return index < insertKey.rowIndex && (row.rowType === "data" || row.rowType === "group"); }).length; }, _getInsertIndex: function _getInsertIndex() { var maxInsertIndex = 0; this._editData.forEach(function (editItem) { if (editItem.type === DATA_EDIT_DATA_INSERT_TYPE && editItem.key[INSERT_INDEX] > maxInsertIndex) { maxInsertIndex = editItem.key[INSERT_INDEX]; } }); return maxInsertIndex + 1; }, /** * @name dxDataGridMethods.addRow * @publicName addRow() */ /** * @name dxTreeListMethods.addRow * @publicName addRow() */ /** * @name dxTreeListMethods.addRow * @publicName addRow(parentId) * @param1 parentId:any */ addRow: function addRow(parentKey) { var that = this, dataController = that._dataController, store = dataController.store(), key = store && store.key(), rowsView = that.getView("rowsView"), param = { data: {} }, parentRowIndex = dataController.getRowIndexByKey(parentKey), insertKey = { pageIndex: dataController.pageIndex(), rowIndex: parentRowIndex >= 0 ? parentRowIndex + 1 : rowsView ? rowsView.getTopVisibleItemIndex() : 0, parentKey: parentKey }, oldEditRowIndex = that._getVisibleEditRowIndex(), editMode = _getEditMode(that), $firstCell; if (editMode === EDIT_MODE_CELL && that.hasChanges()) { that.saveEditData(); } that.refresh(); var insertIndex = that._getInsertIndex(); if (editMode !== EDIT_MODE_BATCH && insertIndex > 1) { return; } if (!key) { param.data.__KEY__ = String(new Guid()); } that._initNewRow(param, insertKey); if (editMode !== EDIT_MODE_BATCH) { that._editRowIndex = insertKey.rowIndex + that._dataController.getRowIndexOffset(); } insertKey[INSERT_INDEX] = insertIndex; that._addEditData({ key: insertKey, data: param.data, type: DATA_EDIT_DATA_INSERT_TYPE }); dataController.updateItems({ changeType: "update", rowIndices: [oldEditRowIndex, insertKey.rowIndex] }); if (editMode === EDIT_MODE_POPUP) { that._showEditPopup(insertKey.rowIndex); } else { $firstCell = that.getFirstEditableCellInRow(insertKey.rowIndex); that._editCellInProgress = true; that._delayedInputFocus($firstCell, function () { that._editCellInProgress = false; var $cell = that.getFirstEditableCellInRow(insertKey.rowIndex); $cell && eventsEngine.trigger($cell, clickEvent.name); }); } that._afterInsertRow({ key: insertKey, data: param.data }); }, _isEditingStart: function _isEditingStart(options) { this.executeAction("onEditingStart", options); return options.cancel; }, _beforeEditCell: function _beforeEditCell(rowIndex, columnIndex, item) { var that = this; if (_getEditMode(that) === EDIT_MODE_CELL && !item.inserted && that.hasChanges()) { var d = new Deferred(); that.saveEditData().always(function () { d.resolve(that.hasChanges()); }); return d; } }, _beforeUpdateItems: function _beforeUpdateItems() {}, _getVisibleEditRowIndex: function _getVisibleEditRowIndex() { return this._editRowIndex >= 0 ? this._editRowIndex - this._dataController.getRowIndexOffset() : -1; }, /** * @name GridBaseMethods.editRow * @publicName editRow(rowIndex) * @param1 rowIndex:number */ editRow: function editRow(rowIndex) { var that = this, dataController = that._dataController, items = dataController.items(), item = items[rowIndex], params = { data: item && item.data, cancel: false }, oldEditRowIndex = that._getVisibleEditRowIndex(), $editingCell; if (!item) { return; } if (rowIndex === oldEditRowIndex) { return true; } if (!item.inserted) { params.key = item.key; } if (that._isEditingStart(params)) { return; } that.init(); that._pageIndex = dataController.pageIndex(); that._editRowIndex = (items[0].inserted ? rowIndex - 1 : rowIndex) + that._dataController.getRowIndexOffset(); that._addEditData({ data: {}, key: item.key, oldData: item.data }); var rowIndices = [oldEditRowIndex, rowIndex], editMode = _getEditMode(that); that._beforeUpdateItems(rowIndices, rowIndex, oldEditRowIndex); if (editMode === EDIT_MODE_POPUP) { that._showEditPopup(rowIndex); } else { dataController.updateItems({ changeType: "update", rowIndices: rowIndices }); } if (MODES_WITH_DELAYED_FOCUS.indexOf(editMode) !== -1) { $editingCell = that.getFocusedCellInRow(that._getVisibleEditRowIndex()); that._delayedInputFocus($editingCell, function () { $editingCell && that.component.focus($editingCell); }); } }, _showEditPopup: function _showEditPopup(rowIndex) { var that = this, isMobileDevice = devices.current().deviceType !== "desktop", popupOptions = extend({ showTitle: false, fullScreen: isMobileDevice, toolbarItems: [{ toolbar: 'bottom', location: 'after', widget: 'dxButton', options: that._getSaveButtonConfig() }, { toolbar: 'bottom', location: 'after', widget: 'dxButton', options: that._getCancelButtonConfig() }], contentTemplate: that._getPopupEditFormTemplate(rowIndex) }, that.option("editing.popup")); if (!that._editPopup) { var $popupContainer = $("<div>").appendTo(that.component.$element()).addClass(that.addWidgetPrefix(EDIT_POPUP_CLASS)); that._editPopup = that._createComponent($popupContainer, Popup, {}); that._editPopup.on("hidden", that._getEditPopupHiddenHandler()); that._editPopup.on("shown", function (e) { eventsEngine.trigger(e.component.$content().find(FOCUSABLE_ELEMENT_SELECTOR).first(), "focus"); }); } that._editPopup.option(popupOptions); that._editPopup.show(); }, _getEditPopupHiddenHandler: function _getEditPopupHiddenHandler() { var that = this; return function (e) { if (that.isEditing()) { that.cancelEditData(); } }; }, _getPopupEditFormTemplate: function _getPopupEditFormTemplate(rowIndex) { var that = this, row = that.component.getVisibleRows()[rowIndex], templateOptions = { row: row, rowType: row.rowType, key: row.key }; return function ($container) { var formTemplate = that.getEditFormTemplate(); formTemplate($container, templateOptions, true); }; }, _getSaveButtonConfig: function _getSaveButtonConfig() { return { text: this.option("editing.texts.saveRowChanges"), onClick: this.saveEditData.bind(this) }; }, _getCancelButtonConfig: function _getCancelButtonConfig() { return { text: this.option("editing.texts.cancelRowChanges"), onClick: this.cancelEditData.bind(this) }; }, /** * @name GridBaseMethods.editCell * @publicName editCell(rowIndex, visibleColumnIndex) * @param1 rowIndex:number * @param2 visibleColumnIndex:number */ /** * @name GridBaseMethods.editCell * @publicName editCell(rowIndex, dataField) * @param1 rowIndex:number * @param2 dataField:string */ editCell: function editCell(rowIndex, columnIndex) { var that = this, columnsController = that._columnsController, dataController = that._dataController, items = dataController.items(), item = items[rowIndex], params = { data: item && item.data, cancel: false }, oldEditRowIndex = that._getVisibleEditRowIndex(), visibleColumns = columnsController.getVisibleColumns(), oldColumn = visibleColumns[that._editColumnIndex]; if (typeUtils.isString(columnIndex)) { columnIndex = columnsController.columnOption(columnIndex, "index"); columnIndex = columnsController.getVisibleIndex(columnIndex); } var column = params.column = visibleColumns[columnIndex]; if (column && item && (item.rowType === "data" || item.rowType === "detailAdaptive") && !item.removed && !_isRowEditMode(that)) { if (that.isEditCell(rowIndex, columnIndex)) { return true; } var editRowIndex = rowIndex + dataController.getRowIndexOffset(); return when(that._beforeEditCell(rowIndex, columnIndex, item)).done(function (cancel) { if (cancel) { return; } if (that._prepareEditCell(params, item, columnIndex, editRowIndex)) { that._repaintEditCell(column, oldColumn, oldEditRowIndex); } }); } return false; }, _prepareEditCell: function _prepareEditCell(params, item, editColumnIndex, editRowIndex) { var that = this; if (!item.inserted) { params.key = item.key; } if (that._isEditingStart(params)) { return false; } that._editRowIndex = editRowIndex; that._editColumnIndex = editColumnIndex; that._pageIndex = that._dataController.pageIndex(); that._addEditData({ data: {}, key: item.key, oldData: item.data }); return true; }, _repaintEditCell: function _repaintEditCell(column, oldColumn, oldEditRowIndex) { var that = this, rowsView = that._rowsView; if (!column || !column.showEditorAlways || oldColumn && !oldColumn.showEditorAlways) { that._editCellInProgress = true; // T316439 that.getController("editorFactory").loseFocus(); that._dataController.updateItems({ changeType: "update", rowIndices: [oldEditRowIndex, that._getVisibleEditRowIndex()] }); } // TODO no focus border when call editCell via API var $cell = rowsView && rowsView._getCellElement(that._getVisibleEditRowIndex(), that._editColumnIndex); // T319885 if ($cell && !$cell.find(":focus").length) { that._focusEditingCell(function () { that._editCellInProgress = false; }, $cell, true); } else { that._editCellInProgress = false; } }, _delayedInputFocus: function _delayedInputFocus($cell, beforeFocusCallback, callBeforeFocusCallbackAlways) { var that = this; function inputFocus() { if (beforeFocusCallback) { beforeFocusCallback(); } $cell && eventsEngine.trigger($cell.find(FOCUSABLE_ELEMENT_SELECTOR).first(), "focus"); that._beforeFocusCallback = null; } if (devices.real().ios || devices.real().android) { inputFocus(); } else { if (that._beforeFocusCallback) that._beforeFocusCallback(); clearTimeout(that._inputFocusTimeoutID); if (callBeforeFocusCallbackAlways) { that._beforeFocusCallback = beforeFocusCallback; } that._inputFocusTimeoutID = setTimeout(inputFocus); } }, _focusEditingCell: function _focusEditingCell(beforeFocusCallback, $editCell, callBeforeFocusCallbackAlways) { var that = this, rowsView = that.getView("rowsView"); $editCell = $editCell || rowsView && rowsView._getCellElement(that._getVisibleEditRowIndex(), that._editColumnIndex); that._delayedInputFocus($editCell, beforeFocusCallback, callBeforeFocusCallbackAlways); }, /** * @name dxDataGridMethods.removeRow * @publicName removeRow(rowIndex) * @param1 rowIndex:number * @deprecated GridBaseMethods.deleteRow */ removeRow: function removeRow(rowIndex) { errors.log("W0002", "dxDataGrid", "removeRow", "15.2", "Use the 'deleteRow' method instead"); return this.deleteRow(rowIndex); }, /** * @name GridBaseMethods.deleteRow * @publicName deleteRow(rowIndex) * @param1 rowIndex:number */ deleteRow: function deleteRow(rowIndex) { var that = this, editingOptions = that.option("editing"), editingTexts = editingOptions && editingOptions.texts, confirmDeleteTitle = editingTexts && editingTexts.confirmDeleteTitle, isBatchMode = editingOptions && editingOptions.mode === EDIT_MODE_BATCH, confirmDeleteMessage = editingTexts && editingTexts.confirmDeleteMessage, dataController = that._dataController, removeByKey, showDialogTitle, oldEditRowIndex = that._getVisibleEditRowIndex(), item = dataController.items()[rowIndex], key = item && item.key; if (item) { removeByKey = function removeByKey(key) { that.refresh(); var editIndex = _getIndexByKey(key, that._editData); if (editIndex >= 0) { if (that._editData[editIndex].type === DATA_EDIT_DATA_INSERT_TYPE) { that._editData.splice(editIndex, 1); } else { that._editData[editIndex].type = DATA_EDIT_DATA_REMOVE_TYPE; } } else { that._addEditData({ key: key, oldData: item.data, type: DATA_EDIT_DATA_REMOVE_TYPE }); } if (isBatchMode) { dataController.updateItems({ changeType: "update", rowIndices: [oldEditRowIndex, rowIndex] }); } else { that.saveEditData(); } }; if (isBatchMode || !confirmDeleteMessage) { removeByKey(key); } else { showDialogTitle = typeUtils.isDefined(confirmDeleteTitle) && confirmDeleteTitle.length > 0; dialog.confirm(confirmDeleteMessage, confirmDeleteTitle, showDialogTitle).done(function (confirmResult) { if (confirmResult) { removeByKey(key); } }); } } }, /** * @name GridBaseMethods.undeleteRow * @publicName undeleteRow(rowIndex) * @param1 rowIndex:number */ undeleteRow: function undeleteRow(rowIndex) { var that = this, dataController = that._dataController, item = dataController.items()[rowIndex], oldEditRowIndex = that._getVisibleEditRowIndex(), key = item && item.key; if (item) { var editIndex = _getIndexByKey(key, that._editData), editData; if (editIndex >= 0) { editData = that._editData[editIndex]; if (typeUtils.isEmptyObject(editData.data)) { that._editData.splice(editIndex, 1); } else { editData.type = DATA_EDIT_DATA_UPDATE_TYPE; } dataController.updateItems({ changeType: "update", rowIndices: [oldEditRowIndex, rowIndex] }); } } }, _saveEditDataCore: function _saveEditDataCore(deferreds, results) { var that = this, store = that._dataController.store(), isDataSaved = true; function executeEditingAction(actionName, params, func) { var deferred = new Deferred(); that.executeAction(actionName, params); function createFailureHandler(deferred) { return function (arg) { var error = arg instanceof Error ? arg : new Error(arg && String(arg) || "Unknown error"); deferred.reject(error); }; } when(deferredUtils.fromPromise(params.cancel)).done(function (cancel) { if (cancel) { deferred.resolve("cancel"); } else { func(params).done(deferred.resolve).fail(createFailureHandler(deferred)); } }).fail(createFailureHandler(deferred)); return deferred; } each(that._editData, function (index, editData) { var data = editData.data, oldData = editData.oldData, type = editData.type, deferred, doneDeferred, params; if (that._beforeSaveEditData(editData, index)) { return; } switch (type) { case DATA_EDIT_DATA_REMOVE_TYPE: params = { data: oldData, key: editData.key, cancel: false }; deferred = executeEditingAction("onRowRemoving", params, function () { return store.remove(editData.key); }); break; case DATA_EDIT_DATA_INSERT_TYPE: params = { data: data, cancel: false }; deferred = executeEditingAction("onRowInserting", params, function () { return store.insert(params.data).done(function (data, key) { editData.key = key; }); }); break; case DATA_EDIT_DATA_UPDATE_TYPE: params = { newData: data, oldData: oldData, key: editData.key, cancel: false }; deferred = executeEditingAction("onRowUpdating", params, function () { return store.update(editData.key, params.newData); }); break; } if (deferred) { doneDeferred = new Deferred(); deferred.always(function (data) { isDataSaved = data !== "cancel"; results.push({ key: editData.key, result: data }); }).always(doneDeferred.resolve); deferreds.push(doneDeferred.promise()); } }); return isDataSaved; }, _processSaveEditDataResult: function _processSaveEditDataResult(results) { var that = this, dataController = that._dataController, i, arg, cancel, editData, editIndex, isError, $popupContent, hasSavedData = false, editMode = _getEditMode(that); for (i = 0; i < results.length; i++) { arg = results[i].result; cancel = arg === "cancel"; editIndex = _getIndexByKey(results[i].key, that._editData); editData = that._editData[editIndex]; if (editData) { isError = arg && arg instanceof Error; if (isError) { editData.error = arg; $popupContent = that.getPopupContent(); dataController.dataErrorOccurred.fire(arg, $popupContent); if (editMode !== EDIT_MODE_BATCH) { break; } } else if (!cancel || editMode !== EDIT_MODE_BATCH && editData.type === DATA_EDIT_DATA_REMOVE_TYPE) { that._editData.splice(editIndex, 1); hasSavedData = !cancel; } } } return hasSavedData; }, _fireSaveEditDataEvents: function _fireSaveEditDataEvents(editData) { var that = this; each(editData, function (_, itemData) { var data = itemData.data, key = itemData.key, type = itemData.type, params = { key: key, data: data }; if (itemData.error) { params.error = itemData.error; } switch (type) { case DATA_EDIT_DATA_REMOVE_TYPE: that.executeAction("onRowRemoved", extend({}, params, { data: itemData.oldData })); break; case DATA_EDIT_DATA_INSERT_TYPE: that.executeAction("onRowInserted", params); break; case DATA_EDIT_DATA_UPDATE_TYPE: that.executeAction("onRowUpdated", params); break; } }); }, /** * @name GridBaseMethods.saveEditData * @publicName saveEditData() * @return Promise<void> */ saveEditData: function saveEditData() { var that = this, editData, results = [], deferreds = [], dataController = that._dataController, dataSource = dataController.dataSource(), editMode = _getEditMode(that), result = new Deferred(); var resetEditIndices = function resetEditIndices(that) { if (editMode !== EDIT_MODE_CELL) { that._editColumnIndex = -1; that._editRowIndex = -1; } }; if (that._beforeSaveEditData() || that._saving) { that._afterSaveEditData(); return result.resolve().promise(); } if (!that._saveEditDataCore(deferreds, results) && editMode === EDIT_MODE_CELL) { that._focusEditingCell(); } if (deferreds.length) { that._saving = true; dataSource && dataSource.beginLoading(); when.apply($, deferreds).done(function () { editData = that._editData.slice(0); if (that._processSaveEditDataResult(results)) { resetEditIndices(that); if (editMode === EDIT_MODE_POPUP && that._editPopup) { that._editPopup.hide(); } dataSource && dataSource.endLoading(); when(dataController.refresh()).always(function () { that._fireSaveEditDataEvents(editData); that._afterSaveEditData(); result.resolve(); }); } else { dataSource && dataSource.endLoading(); result.resolve(); } }).fail(function () { dataSource && dataSource.endLoading(); result.resolve(); }); return result.always(function () { that._focusEditingCell(); that._saving = false; }).promise(); } if (_isRowEditMode(that)) { if (!that.hasChanges()) { that.cancelEditData(); } } else if (CELL_BASED_MODES.indexOf(editMode) !== -1) { resetEditIndices(that); dataController.updateItems(); } else { that._focusEditingCell(); } that._afterSaveEditData(); return result.resolve().promise(); }, isSaving: function isSaving() { return this._saving; }, _updateEditColumn: function _updateEditColumn() { var that = this, useIcons = that.option("editing.useIcons"), isEditColumnVisible = that._isEditColumnVisible(), cssClass = COMMAND_EDIT_CLASS + (useIcons ? " " + COMMAND_EDIT_WITH_ICONS_CLASS : ""); that._columnsController.addCommandColumn({ command: "edit", visible: isEditColumnVisible, cssClass: cssClass, width: "auto", cellTemplate: editCellTemplate }); that._columnsController.columnOption("command:edit", { visible: isEditColumnVisible, cssClass: cssClass }); }, _isEditColumnVisible: function _isEditColumnVisible() { var that = this, editingOptions = that.option("editing"); if (editingOptions) { var editMode = _getEditMode(that), isVisibleWithCurrentEditMode = false; switch (editMode) { case EDIT_MODE_ROW: isVisibleWithCurrentEditMode = editingOptions.allowUpdating || editingOptions.allowAdding; break; case EDIT_MODE_FORM: case EDIT_MODE_POPUP: isVisibleWithCurrentEditMode = editingOptions.allowUpdating; break; } return editingOptions.allowDeleting || isVisibleWithCurrentEditMode; } }, _updateEditButtons: function _updateEditButtons() { var that = this, headerPanel = that.getView("headerPanel"), hasChanges = that.hasChanges(); if (headerPanel) { headerPanel.setToolbarItemDisabled("saveButton", !hasChanges); headerPanel.setToolbarItemDisabled("revertButton", !hasChanges); } }, _applyModified: function _applyModified($element) { $element && $element.addClass(CELL_MODIFIED); }, _beforeCloseEditCellInBatchMode: function _beforeCloseEditCellInBatchMode() {}, /** * @name GridBaseMethods.cancelEditData * @publicName cancelEditData() */ cancelEditData: function cancelEditData() { var that = this, editMode = _getEditMode(that), rowIndex = this._editRowIndex, dataController = that._dataController; that._beforeCancelEditData(); that.init(); if (ROW_BASED_MODES.indexOf(editMode) !== -1 && rowIndex >= 0) { dataController.updateItems({ changeType: "update", rowIndices: [rowIndex, rowIndex + 1] }); } else { dataController.updateItems(); } if (editMode === EDIT_MODE_POPUP) { that._hideEditPopup(); } }, _hideEditPopup: function _hideEditPopup() { this._editPopup && this._editPopup.option("visible", false); }, /** * @name GridBaseMethods.hasEditData * @publicName hasEditData() * @return boolean */ hasEditData: function hasEditData() { return this.hasChanges(); }, /** * @name GridBaseMethods.closeEditCell * @publicName closeEditCell() */ closeEditCell: function closeEditCell() { var that = this, editMode = _getEditMode(that), oldEditRowIndex = that._getVisibleEditRowIndex(), dataController = that._dataController;