UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,072 lines (1,066 loc) • 50.1 kB
/** * DevExtreme (cjs/__internal/grids/grid_core/adaptivity/m_adaptivity.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.adaptivityModule = exports.AdaptiveColumnsController = void 0; var _click = require("../../../../common/core/events/click"); var _events_engine = _interopRequireDefault(require("../../../../common/core/events/core/events_engine")); var _remove = require("../../../../common/core/events/remove"); var _index = require("../../../../common/core/events/utils/index"); var _message = _interopRequireDefault(require("../../../../common/core/localization/message")); var _guid = _interopRequireDefault(require("../../../../core/guid")); var _renderer = _interopRequireDefault(require("../../../../core/renderer")); var _common = require("../../../../core/utils/common"); var _deferred = require("../../../../core/utils/deferred"); var _dom = require("../../../../core/utils/dom"); var _extend = require("../../../../core/utils/extend"); var _iterator = require("../../../../core/utils/iterator"); var _size = require("../../../../core/utils/size"); var _type = require("../../../../core/utils/type"); var _form = _interopRequireDefault(require("../../../../ui/form")); var _themes = require("../../../../ui/themes"); 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 COLUMN_HEADERS_VIEW = "columnHeadersView"; const ROWS_VIEW = "rowsView"; const FOOTER_VIEW = "footerView"; const COLUMN_VIEWS = ["columnHeadersView", ROWS_VIEW, FOOTER_VIEW]; const ADAPTIVE_NAMESPACE = "dxDataGridAdaptivity"; const HIDDEN_COLUMNS_WIDTH = "adaptiveHidden"; const ADAPTIVE_ROW_TYPE = "detailAdaptive"; const FORM_ITEM_CONTENT_CLASS = "dx-field-item-content"; const FORM_ITEM_MODIFIED = "dx-item-modified"; const HIDDEN_COLUMN_CLASS = "hidden-column"; const ADAPTIVE_COLUMN_BUTTON_CLASS = "adaptive-more"; const ADAPTIVE_COLUMN_NAME_CLASS = "dx-command-adaptive"; const COMMAND_ADAPTIVE_HIDDEN_CLASS = "dx-command-adaptive-hidden"; const ADAPTIVE_DETAIL_ROW_CLASS = "dx-adaptive-detail-row"; const ADAPTIVE_ITEM_TEXT_CLASS = "dx-adaptive-item-text"; const MASTER_DETAIL_CELL_CLASS = "dx-master-detail-cell"; const LAST_DATA_CELL_CLASS = "dx-last-data-cell"; const ADAPTIVE_COLUMN_NAME = "adaptive"; const EDIT_MODE_BATCH = "batch"; const EDIT_MODE_ROW = "row"; const EDIT_MODE_FORM = "form"; const EDIT_MODE_POPUP = "popup"; const REVERT_TOOLTIP_CLASS = "revert-tooltip"; const GROUP_CELL_CLASS = "dx-group-cell"; const GROUP_ROW_CLASS = "dx-group-row"; const EXPAND_ARIA_NAME = "dxDataGrid-ariaAdaptiveExpand"; const COLLAPSE_ARIA_NAME = "dxDataGrid-ariaAdaptiveCollapse"; const LEGACY_SCROLLING_MODE = "scrolling.legacyMode"; function getColumnId(that, column) { return that._columnsController.getColumnId(column) } function getDataCellElements($row) { return $row.find("td:not(.dx-datagrid-hidden-column):not([class*='dx-command-'])") } function adaptiveCellTemplate(container, options) { let $adaptiveColumnButton; const $container = (0, _renderer.default)(container); const adaptiveColumnsController = options.component.getController("adaptiveColumns"); if ("data" === options.rowType) { $adaptiveColumnButton = (0, _renderer.default)("<span>").addClass(adaptiveColumnsController.addWidgetPrefix("adaptive-more")); _events_engine.default.on($adaptiveColumnButton, (0, _index.addNamespace)(_click.name, ADAPTIVE_NAMESPACE), adaptiveColumnsController.createAction((() => { adaptiveColumnsController.toggleExpandAdaptiveDetailRow(options.key) }))); $adaptiveColumnButton.appendTo($container) } else { _m_utils.default.setEmptyText($container) } } function focusCellHandler(e) { var _e$data; const $nextCell = null === (_e$data = e.data) || void 0 === _e$data ? void 0 : _e$data.$nextCell; _events_engine.default.off($nextCell, "focus", focusCellHandler); _events_engine.default.trigger($nextCell, "dxclick") } class AdaptiveColumnsController extends _m_modules.default.ViewController { init() { this._columnsController = this.getController("columns"); this._dataController = this.getController("data"); this._editingController = this.getController("editing"); this._keyboardNavigationController = this.getController("keyboardNavigation"); this._rowsView = this.getView("rowsView"); this._columnsController.addCommandColumn({ type: "adaptive", command: "adaptive", visible: true, adaptiveHidden: true, cssClass: "dx-command-adaptive", alignment: "center", width: "auto", cellTemplate: adaptiveCellTemplate, fixedPosition: "right" }); this._columnsController.columnsChanged.add((() => { const isAdaptiveVisible = !!this.updateHidingQueue(this._columnsController.getColumns()).length; this._columnsController.columnOption("command:adaptive", "adaptiveHidden", !isAdaptiveVisible, true) })); this._hidingColumnsQueue = []; this._hiddenColumns = []; this.createAction("onAdaptiveDetailRowPreparing"); super.init() } optionChanged(args) { if ("columnHidingEnabled" === args.name) { this._columnsController.columnOption("command:adaptive", "adaptiveHidden", !args.value) } super.optionChanged(args) } publicMethods() { return ["isAdaptiveDetailRowExpanded", "expandAdaptiveDetailRow", "collapseAdaptiveDetailRow"] } _isRowEditMode() { const editMode = this._getEditMode(); return "row" === editMode } _isItemModified(item, cellOptions) { const columnIndex = this._columnsController.getVisibleIndex(item.column.index); const rowIndex = this._dataController.getRowIndexByKey(cellOptions.key); const row = this._dataController.items()[rowIndex + 1]; return row && row.modifiedValues && (0, _type.isDefined)(row.modifiedValues[columnIndex]) } _renderFormViewTemplate(item, cellOptions, $container) { const that = this; const { column: column } = item; const focusAction = that.createAction((() => { if (that._editingController.isEditing()) { _events_engine.default.trigger($container, _click.name) } })); const rowData = cellOptions.row.data; const value = column.calculateCellValue(rowData); const displayValue = _m_utils.default.getDisplayValue(column, value, rowData, cellOptions.rowType); const text = _m_utils.default.formatValue(displayValue, column); const isCellOrBatchEditMode = this._editingController.isCellOrBatchEditMode(); const rowsView = that._rowsView; if (column.allowEditing && this._keyboardNavigationController.isKeyboardEnabled()) { $container.attr("tabIndex", that.option("tabIndex")); if (isCellOrBatchEditMode) { _events_engine.default.off($container, "focus", focusAction); _events_engine.default.on($container, "focus", focusAction) } } if (column.cellTemplate) { const templateOptions = (0, _extend.extend)({}, cellOptions, { value: value, displayValue: displayValue, text: text, column: column }); rowsView.renderTemplate($container, column.cellTemplate, templateOptions, (0, _dom.isElementInDom)($container)).done((() => { rowsView._cellPrepared($container, cellOptions) })) } else { const container = $container.get(0); if (column.encodeHtml) { container.textContent = text } else { container.innerHTML = text } $container.addClass("dx-adaptive-item-text"); if (!(0, _type.isDefined)(text) || "" === text) { $container.html("&nbsp;") } if (!that._isRowEditMode()) { if (that._isItemModified(item, cellOptions)) { $container.addClass("dx-item-modified") } } rowsView._cellPrepared($container, cellOptions) } } _getTemplate(item, cellOptions, updateForm) { const that = this; const { column: column } = item; const editingController = this._editingController; return function(options, container) { const $container = (0, _renderer.default)(container); const columnIndex = that._columnsController.getVisibleIndex(column.index); const templateOptions = (0, _extend.extend)({}, cellOptions); const renderFormTemplate = function() { const isItemEdited = that._isItemEdited(item); templateOptions.value = cellOptions.row.values[columnIndex]; if (isItemEdited || column.showEditorAlways) { editingController.renderFormEditorTemplate(templateOptions, item, options, $container, !isItemEdited) } else { templateOptions.column = column; templateOptions.columnIndex = columnIndex; that._renderFormViewTemplate(item, templateOptions, $container) } }; renderFormTemplate(); if (templateOptions.watch) { const dispose = templateOptions.watch((() => ({ isItemEdited: that._isItemEdited(item), value: cellOptions.row.values[columnIndex] })), (() => { $container.contents().remove(); $container.removeClass("dx-adaptive-item-text"); renderFormTemplate() })); _events_engine.default.on($container, _remove.removeEvent, dispose) } } } _isVisibleColumnsValid(visibleColumns) { if (visibleColumns < 2) { return false } if (visibleColumns.length - function() { let result = 0; for (let j = 0; j < visibleColumns.length; j++) { const visibleColumn = visibleColumns[j]; if (visibleColumn.command) { result++ } } return result }() <= 1) { return false } return true } _calculatePercentWidths(widths, visibleColumns) { const that = this; let percentWidths = 0; visibleColumns.forEach(((item, index) => { if ("adaptiveHidden" !== widths[index]) { percentWidths += that._getItemPercentWidth(item) } })); return percentWidths } _isPercentWidth(width) { return (0, _type.isString)(width) && width.endsWith("%") } _isColumnHidden(column) { return this._hiddenColumns.filter((hiddenColumn => hiddenColumn.index === column.index)).length > 0 } _getAverageColumnsWidth(containerWidth, columns, columnsCanFit) { const that = this; let fixedColumnsWidth = 0; let columnsWithoutFixedWidthCount = 0; columns.forEach((column => { if (!that._isColumnHidden(column)) { const { width: width } = column; if ((0, _type.isDefined)(width) && !isNaN(parseFloat(width))) { fixedColumnsWidth += that._isPercentWidth(width) ? that._calculatePercentWidth({ visibleIndex: column.visibleIndex, columnsCount: columns.length, columnsCanFit: columnsCanFit, bestFitWidth: column.bestFitWidth, columnWidth: width, containerWidth: containerWidth }) : parseFloat(width) } else { columnsWithoutFixedWidthCount++ } } })); return (containerWidth - fixedColumnsWidth) / columnsWithoutFixedWidthCount } _calculateColumnWidth(column, containerWidth, contentColumns, columnsCanFit) { const columnId = getColumnId(this, column); const widthOption = this._columnsController.columnOption(columnId, "width"); const bestFitWidth = this._columnsController.columnOption(columnId, "bestFitWidth"); const columnsCount = contentColumns.length; let colWidth; if (widthOption && "auto" !== widthOption) { if (this._isPercentWidth(widthOption)) { colWidth = this._calculatePercentWidth({ visibleIndex: column.visibleIndex, columnsCount: columnsCount, columnsCanFit: columnsCanFit, bestFitWidth: bestFitWidth, columnWidth: widthOption, containerWidth: containerWidth }) } else { return parseFloat(widthOption) } } else { const columnAutoWidth = this.option("columnAutoWidth"); colWidth = columnAutoWidth || !!column.command ? bestFitWidth : this._getAverageColumnsWidth(containerWidth, contentColumns, columnsCanFit) } return colWidth } _calculatePercentWidth(options) { const columnFitted = options.visibleIndex < options.columnsCount - 1 && options.columnsCanFit; const partialWidth = options.containerWidth * parseFloat(options.columnWidth) / 100; const resultWidth = options.columnsCanFit && partialWidth < options.bestFitWidth ? options.bestFitWidth : partialWidth; return columnFitted ? options.containerWidth * parseFloat(options.columnWidth) / 100 : resultWidth } _getNotTruncatedColumnWidth(column, containerWidth, contentColumns, columnsCanFit) { const columnId = getColumnId(this, column); const widthOption = this._columnsController.columnOption(columnId, "width"); const bestFitWidth = this._columnsController.columnOption(columnId, "bestFitWidth"); if (widthOption && "auto" !== widthOption && !this._isPercentWidth(widthOption)) { return parseFloat(widthOption) } const colWidth = this._calculateColumnWidth(column, containerWidth, contentColumns, columnsCanFit); return colWidth < bestFitWidth ? null : colWidth } _getItemPercentWidth(item) { let result = 0; if (item.width && this._isPercentWidth(item.width)) { result = parseFloat(item.width) } return result } _getCommandColumnsWidth() { const that = this; const columns = that._columnsController.getVisibleColumns(); let colWidth = 0; (0, _iterator.each)(columns, ((index, column) => { if (column.index < 0 || column.command) { colWidth += that._columnsController.columnOption(getColumnId(that, column), "bestFitWidth") || 0 } })); return colWidth } _isItemEdited(item) { if (this.isFormOrPopupEditMode()) { return false } if (this._isRowEditMode()) { const editRowKey = this.option("editing.editRowKey"); if ((0, _common.equalByValue)(editRowKey, this._dataController.adaptiveExpandedKey())) { return true } } else { const rowIndex = this._dataController.getRowIndexByKey(this._dataController.adaptiveExpandedKey()) + 1; const columnIndex = this._columnsController.getVisibleIndex(item.column.index); return this._editingController.isEditCell(rowIndex, columnIndex) } return } _getFormItemsByHiddenColumns(hiddenColumns) { const items = []; (0, _iterator.each)(hiddenColumns, ((_, column) => { items.push({ column: column, name: column.name, dataField: column.dataField, visibleIndex: column.visibleIndex }) })); return items } _getAdaptiveColumnVisibleIndex(visibleColumns) { for (let i = 0; i < visibleColumns.length; i++) { const column = visibleColumns[i]; if ("adaptive" === column.command) { return i } } return } _hideAdaptiveColumn(resultWidths, visibleColumns) { const visibleIndex = this._getAdaptiveColumnVisibleIndex(visibleColumns); if ((0, _type.isDefined)(visibleIndex)) { resultWidths[visibleIndex] = "adaptiveHidden"; this._hideVisibleColumn({ isCommandColumn: true, visibleIndex: visibleIndex }) } } _showHiddenCellsInView(_ref) { let { $cells: $cells, isCommandColumn: isCommandColumn } = _ref; let cssClassNameToRemove = this.addWidgetPrefix("hidden-column"); if (isCommandColumn) { cssClassNameToRemove = "dx-command-adaptive-hidden"; $cells.attr({ tabIndex: 0, "aria-hidden": null }).removeClass(cssClassNameToRemove) } else { $cells.removeClass(cssClassNameToRemove) } } _showHiddenColumns() { for (let i = 0; i < COLUMN_VIEWS.length; i++) { const view = this.getView(COLUMN_VIEWS[i]); if (view && view.isVisible() && view.element()) { const viewName = view.name; const $hiddenCommandCells = view.element().find(".dx-command-adaptive-hidden"); this._showHiddenCellsInView({ viewName: viewName, $cells: $hiddenCommandCells, isCommandColumn: true }); const $hiddenCells = view.element().find(`.${this.addWidgetPrefix("hidden-column")}`); this._showHiddenCellsInView({ viewName: viewName, $cells: $hiddenCells }) } } } _isCellValid($cell) { return $cell && $cell.length && !$cell.hasClass("dx-master-detail-cell") && !$cell.hasClass("dx-group-cell") } _hideVisibleColumn(_ref2) { let { isCommandColumn: isCommandColumn, visibleIndex: visibleIndex } = _ref2; const that = this; COLUMN_VIEWS.forEach((viewName => { const view = that.getView(viewName); view && that._hideVisibleColumnInView({ view: view, isCommandColumn: isCommandColumn, visibleIndex: visibleIndex }) })) } _hideVisibleColumnInView(_ref3) { let { view: view, isCommandColumn: isCommandColumn, visibleIndex: visibleIndex } = _ref3; const viewName = view.name; let $cellElement; const column = this._columnsController.getVisibleColumns()[visibleIndex]; const editFormRowIndex = this._editingController && this._editingController.getEditFormRowIndex(); if (view && view.isVisible() && column) { const rowsCount = view.getRowsCount(); const $rowElements = view._getRowElements(); for (let rowIndex = 0; rowIndex < rowsCount; rowIndex++) { const cancelClassAdding = rowIndex === editFormRowIndex && viewName === ROWS_VIEW && "popup" !== this.option("editing.mode"); if (!cancelClassAdding) { const currentVisibleIndex = "columnHeadersView" === viewName ? this._columnsController.getVisibleIndex(column.index, rowIndex) : visibleIndex; if (currentVisibleIndex >= 0) { const $rowElement = $rowElements.eq(rowIndex); $cellElement = this._findCellElementInRow($rowElement, currentVisibleIndex); this._isCellValid($cellElement) && this._hideVisibleCellInView({ viewName: viewName, isCommandColumn: isCommandColumn, $cell: $cellElement }) } } } } } _findCellElementInRow($rowElement, visibleColumnIndex) { const $rowCells = $rowElement.children(); let visibleIndex = visibleColumnIndex; let cellIsInsideGroup = false; if ($rowElement.hasClass("dx-group-row")) { const $groupCell = $rowElement.find(".dx-group-cell"); const colSpan = $groupCell.attr("colspan"); if ($groupCell.length && (0, _type.isDefined)(colSpan)) { const groupCellLength = parseInt(colSpan); const endGroupIndex = $groupCell.index() + groupCellLength - 1; if (visibleColumnIndex > endGroupIndex) { visibleIndex = visibleColumnIndex - groupCellLength + 1 } else { cellIsInsideGroup = true } } } const $cellElement = !cellIsInsideGroup ? $rowCells.eq(visibleIndex) : void 0; return $cellElement } _hideVisibleCellInView(_ref4) { let { $cell: $cell, isCommandColumn: isCommandColumn } = _ref4; const cssClassNameToAdd = isCommandColumn ? "dx-command-adaptive-hidden" : this.addWidgetPrefix("hidden-column"); $cell.attr({ tabIndex: -1, "aria-hidden": true }).addClass(cssClassNameToAdd) } _getEditMode() { return this._editingController.getEditMode() } isFormOrPopupEditMode() { const editMode = this._getEditMode(); return "form" === editMode || "popup" === editMode } hideRedundantColumns(resultWidths, visibleColumns, hiddenQueue) { const that = this; this._hiddenColumns = []; if (that._isVisibleColumnsValid(visibleColumns) && hiddenQueue.length) { let totalWidth = 0; const $rootElement = that.component.$element(); let rootElementWidth = (0, _size.getWidth)($rootElement) - that._getCommandColumnsWidth(); const getVisibleContentColumns = function() { return visibleColumns.filter((item => !item.command && 0 === this._hiddenColumns.filter((i => i.index === item.index)).length)) }.bind(this); let visibleContentColumns = getVisibleContentColumns(); const contentColumnsCount = visibleContentColumns.length; let i; let hasHiddenColumns; let needHideColumn; do { needHideColumn = false; totalWidth = 0; const percentWidths = that._calculatePercentWidths(resultWidths, visibleColumns); const columnsCanFit = percentWidths < 100 && 0 !== percentWidths; for (i = 0; i < visibleColumns.length; i++) { const visibleColumn = visibleColumns[i]; let columnWidth = that._getNotTruncatedColumnWidth(visibleColumn, rootElementWidth, visibleContentColumns, columnsCanFit); const columnId = getColumnId(that, visibleColumn); const widthOption = that._columnsController.columnOption(columnId, "width"); const minWidth = that._columnsController.columnOption(columnId, "minWidth"); const columnBestFitWidth = that._columnsController.columnOption(columnId, "bestFitWidth"); if ("adaptiveHidden" === resultWidths[i]) { hasHiddenColumns = true; continue } if (!columnWidth && !visibleColumn.command && !visibleColumn.fixed) { needHideColumn = true; break } if (!widthOption || "auto" === widthOption) { columnWidth = Math.max(columnBestFitWidth || 0, minWidth || 0) } if ("adaptive" !== visibleColumn.command || hasHiddenColumns) { totalWidth += columnWidth } } needHideColumn = needHideColumn || totalWidth > (0, _size.getWidth)($rootElement); if (needHideColumn) { const column = hiddenQueue.pop(); const visibleIndex = that._columnsController.getVisibleIndex(column.index); rootElementWidth += that._calculateColumnWidth(column, rootElementWidth, visibleContentColumns, columnsCanFit); that._hideVisibleColumn({ visibleIndex: visibleIndex }); resultWidths[visibleIndex] = "adaptiveHidden"; this._hiddenColumns.push(column); visibleContentColumns = getVisibleContentColumns() } } while (needHideColumn && visibleContentColumns.length > 1 && hiddenQueue.length); if (contentColumnsCount === visibleContentColumns.length) { that._hideAdaptiveColumn(resultWidths, visibleColumns) } } else { that._hideAdaptiveColumn(resultWidths, visibleColumns) } } getAdaptiveDetailItems() { return this._$itemContents } getItemContentByColumnIndex(visibleColumnIndex) { let $itemContent; for (let i = 0; i < this._$itemContents.length; i++) { $itemContent = this._$itemContents.eq(i); const item = $itemContent.data("dx-form-item"); if (item && item.column && this._columnsController.getVisibleIndex(item.column.index) === visibleColumnIndex) { return $itemContent } } } toggleExpandAdaptiveDetailRow(key, alwaysExpanded) { if (!(this.isFormOrPopupEditMode() && this._editingController.isEditing())) { this._dataController.toggleExpandAdaptiveDetailRow(key, alwaysExpanded) } } createFormByHiddenColumns(container, options) { const that = this; const $container = (0, _renderer.default)(container); const userFormOptions = { items: that._getFormItemsByHiddenColumns(that._hiddenColumns), formID: `dx-${new _guid.default}` }; const defaultFormOptions = (0, _themes.isMaterial)() ? { colCount: 2 } : {}; this.executeAction("onAdaptiveDetailRowPreparing", { formOptions: userFormOptions }); that._$itemContents = null; that._form = that._createComponent((0, _renderer.default)("<div>").appendTo($container), _form.default, (0, _extend.extend)(defaultFormOptions, userFormOptions, { customizeItem(item) { const column = item.column || that._columnsController.columnOption(item.name || item.dataField); if (column) { item.label = item.label || {}; item.label.text = item.label.text || column.caption; item.column = column; item.template = that._getTemplate(item, options, that.updateForm.bind(that)) } userFormOptions.customizeItem && userFormOptions.customizeItem.call(this, item) }, onContentReady(e) { userFormOptions.onContentReady && userFormOptions.onContentReady.call(this, e); that._$itemContents = $container.find(".dx-field-item-content") } })) } hasAdaptiveDetailRowExpanded() { return (0, _type.isDefined)(this._dataController.adaptiveExpandedKey()) } updateForm(hiddenColumns) { if (this.hasAdaptiveDetailRowExpanded()) { if (this._form && (0, _type.isDefined)(this._form._contentReadyAction)) { if (hiddenColumns && hiddenColumns.length) { this._form.option("items", this._getFormItemsByHiddenColumns(hiddenColumns)) } else { this._form.repaint() } } } } updateHidingQueue(columns) { const that = this; const hideableColumns = columns.filter((column => column.visible && !column.type && !column.fixed && !((0, _type.isDefined)(column.groupIndex) && column.groupIndex >= 0))); let columnsHasHidingPriority; let i; that._hidingColumnsQueue = []; if (that.option("allowColumnResizing") && "widget" === that.option("columnResizingMode")) { return that._hidingColumnsQueue } for (i = 0; i < hideableColumns.length; i++) { if ((0, _type.isDefined)(hideableColumns[i].hidingPriority) && hideableColumns[i].hidingPriority >= 0) { columnsHasHidingPriority = true; that._hidingColumnsQueue[hideableColumns[i].hidingPriority] = hideableColumns[i] } } if (columnsHasHidingPriority) { that._hidingColumnsQueue.reverse() } else if (that.option("columnHidingEnabled")) { for (i = 0; i < hideableColumns.length; i++) { const visibleIndex = that._columnsController.getVisibleIndex(hideableColumns[i].index); that._hidingColumnsQueue[visibleIndex] = hideableColumns[i] } } that._hidingColumnsQueue = that._hidingColumnsQueue.filter(Object); return that._hidingColumnsQueue } getHiddenColumns() { return this._hiddenColumns } hasHiddenColumns() { return this._hiddenColumns.length > 0 } getHidingColumnsQueue() { return this._hidingColumnsQueue } isAdaptiveDetailRowExpanded(key) { const dataController = this._dataController; return dataController.adaptiveExpandedKey() && (0, _common.equalByValue)(dataController.adaptiveExpandedKey(), key) } expandAdaptiveDetailRow(key) { if (!this.hasAdaptiveDetailRowExpanded()) { this.toggleExpandAdaptiveDetailRow(key) } } collapseAdaptiveDetailRow() { if (this.hasAdaptiveDetailRowExpanded()) { this.toggleExpandAdaptiveDetailRow() } } updateCommandAdaptiveAriaLabel(key, label) { const rowIndex = this._dataController.getRowIndexByKey(key); if (-1 === rowIndex) { return } const $row = (0, _renderer.default)(this.component.getRowElement(rowIndex)); this.setCommandAdaptiveAriaLabel($row, label) } setCommandAdaptiveAriaLabel($row, labelName) { const $adaptiveCommand = $row.find(".dx-command-adaptive"); $adaptiveCommand.attr("aria-label", _message.default.format(labelName)) } } exports.AdaptiveColumnsController = AdaptiveColumnsController; const keyboardNavigation = Base => class extends Base { _isCellValid($cell, isClick) { return super._isCellValid($cell, isClick) && !$cell.hasClass(this.addWidgetPrefix("hidden-column")) && !$cell.hasClass("dx-command-adaptive-hidden") } _processNextCellInMasterDetail($nextCell, $cell) { super._processNextCellInMasterDetail($nextCell, $cell); const isCellOrBatchMode = this._editingController.isCellOrBatchEditMode(); const isEditing = this._editingController.isEditing(); if (isEditing && $nextCell && isCellOrBatchMode && !this._isInsideEditForm($nextCell)) { _events_engine.default.off($nextCell, "focus", focusCellHandler); _events_engine.default.on($nextCell, "focus", { $nextCell: $nextCell }, focusCellHandler); _events_engine.default.trigger($cell, "focus") } } _isCellElement($cell) { return super._isCellElement($cell) || $cell.hasClass("dx-adaptive-item-text") } }; const rowsView = Base => class extends Base { _getCellTemplate(options) { const that = this; const { column: column } = options; if ("detailAdaptive" === options.rowType && "detail" === column.command) { return function(container, options) { that._adaptiveColumnsController.createFormByHiddenColumns((0, _renderer.default)(container), options) } } return super._getCellTemplate(options) } _createRow(row) { const $row = super._createRow.apply(this, arguments); if (row && "detailAdaptive" === row.rowType && row.key === this._dataController.adaptiveExpandedKey()) { $row.addClass("dx-adaptive-detail-row") } return $row } _renderCells($row, options) { super._renderCells($row, options); const adaptiveColumnsController = this._adaptiveColumnsController; const hidingColumnsQueueLength = adaptiveColumnsController.getHidingColumnsQueue().length; const hiddenColumnsLength = adaptiveColumnsController.getHiddenColumns().length; if (hidingColumnsQueueLength && !hiddenColumnsLength) { getDataCellElements($row).last().addClass("dx-last-data-cell") } if ("data" === options.row.rowType) { adaptiveColumnsController.setCommandAdaptiveAriaLabel($row, EXPAND_ARIA_NAME) } } _getColumnIndexByElementCore($element) { const $itemContent = $element.closest(".dx-field-item-content"); if ($itemContent.length && $itemContent.closest(this.component.$element()).length) { const formItem = $itemContent.length ? $itemContent.first().data("dx-form-item") : null; return formItem && formItem.column && this._columnsController.getVisibleIndex(formItem.column.index) } return super._getColumnIndexByElementCore($element) } _cellPrepared($cell, options) { super._cellPrepared.apply(this, arguments); if ("detailAdaptive" !== options.row.rowType && "adaptiveHidden" === options.column.visibleWidth) { $cell.addClass(this.addWidgetPrefix("hidden-column")) } } getCell(cellPosition, rows) { const item = this._dataController.items()[null === cellPosition || void 0 === cellPosition ? void 0 : cellPosition.rowIndex]; if ("detailAdaptive" === (null === item || void 0 === item ? void 0 : item.rowType)) { const $adaptiveDetailItems = this._adaptiveColumnsController.getAdaptiveDetailItems(); return super.getCell(cellPosition, rows, $adaptiveDetailItems) } return super.getCell.apply(this, arguments) } _getCellElement(rowIndex, columnIdentifier) { const item = this._dataController.items()[rowIndex]; if (item && "detailAdaptive" === item.rowType) { return this._adaptiveColumnsController.getItemContentByColumnIndex(columnIdentifier) } return super._getCellElement.apply(this, arguments) } getContextMenuItems(options) { var _super$getContextMenu; if (options.row && "detailAdaptive" === options.row.rowType) { const view = this._columnHeadersView; const formItem = (0, _renderer.default)(options.targetElement).closest(".dx-field-item-label").next().data("dx-form-item"); options.column = formItem ? formItem.column : options.column; return view.getContextMenuItems && view.getContextMenuItems(options) } return null === (_super$getContextMenu = super.getContextMenuItems) || void 0 === _super$getContextMenu ? void 0 : _super$getContextMenu.call(this, options) } isClickableElement($target) { var _super$isClickableEle; const isClickable = (null === (_super$isClickableEle = super.isClickableElement) || void 0 === _super$isClickableEle ? void 0 : _super$isClickableEle.call(this, $target)) ?? false; return isClickable || !!$target.closest(".dx-command-adaptive").length } }; const exportExtender = Base => class extends Base { _updateColumnWidth(column, width) { super._updateColumnWidth(column, "adaptiveHidden" === column.visibleWidth ? column.bestFitWidth : width) } }; const columnsResizer = Base => class extends Base { _pointCreated(point, cellsLength, columns) { const result = super._pointCreated(point, cellsLength, columns); const currentColumn = columns[point.columnIndex] || {}; const nextColumnIndex = this._getNextColumnIndex(point.columnIndex); const nextColumn = columns[nextColumnIndex] || {}; const hasHiddenColumnsOnly = nextColumnIndex !== point.columnIndex + 1 && nextColumn.command; const hasAdaptiveHiddenWidth = "adaptiveHidden" === currentColumn.visibleWidth || hasHiddenColumnsOnly; return result || hasAdaptiveHiddenWidth } _getNextColumnIndex(currentColumnIndex) { const visibleColumns = this._columnsController.getVisibleColumns(); let index = super._getNextColumnIndex(currentColumnIndex); while (visibleColumns[index] && "adaptiveHidden" === visibleColumns[index].visibleWidth) { index++ } return index } }; const draggingHeader = Base => class extends Base { _pointCreated(point, columns, location, sourceColumn) { const result = super._pointCreated(point, columns, location, sourceColumn); const column = columns[point.columnIndex - 1] || {}; const hasAdaptiveHiddenWidth = "adaptiveHidden" === column.visibleWidth; return result || hasAdaptiveHiddenWidth } }; const editing = Base => class extends Base { _isRowEditMode() { return "row" === this.getEditMode() } _getFormEditItemTemplate(cellOptions, column) { if ("row" !== this.getEditMode() && "detailAdaptive" === cellOptions.rowType) { cellOptions.columnIndex = this._columnsController.getVisibleIndex(column.index); return this.getColumnTemplate(cellOptions) } return super._getFormEditItemTemplate(cellOptions, column) } _closeEditItem($targetElement) { const $itemContents = $targetElement.closest(".dx-field-item-content"); const rowIndex = this._dataController.getRowIndexByKey(this._dataController.adaptiveExpandedKey()) + 1; const formItem = $itemContents.length ? $itemContents.first().data("dx-form-item") : null; const columnIndex = formItem && formItem.column && this._columnsController.getVisibleIndex(formItem.column.index); if (!this.isEditCell(rowIndex, columnIndex)) { super._closeEditItem($targetElement) } } _beforeUpdateItems(rowIndices, rowIndex) { if (!this._adaptiveColumnsController.isFormOrPopupEditMode() && this._adaptiveColumnsController.hasHiddenColumns()) { const items = this._dataController.items(); const item = items[rowIndex]; const oldExpandRowIndex = _m_utils.default.getIndexByKey(this._dataController.adaptiveExpandedKey(), items); this._isForceRowAdaptiveExpand = !this._adaptiveColumnsController.hasAdaptiveDetailRowExpanded(); if (oldExpandRowIndex >= 0) { rowIndices.push(oldExpandRowIndex + 1) } rowIndices.push(rowIndex + 1); this._dataController.adaptiveExpandedKey(item.key) } } _afterInsertRow(key) { super._afterInsertRow.apply(this, arguments); if (this._adaptiveColumnsController.hasHiddenColumns()) { this._adaptiveColumnsController.toggleExpandAdaptiveDetailRow(key, this.isRowEditMode()); this._isForceRowAdaptiveExpand = true } } _collapseAdaptiveDetailRow() { if (this._isRowEditMode() && this._isForceRowAdaptiveExpand) { this._adaptiveColumnsController.collapseAdaptiveDetailRow(); this._isForceRowAdaptiveExpand = false } } _cancelEditAdaptiveDetailRow() { if (this._adaptiveColumnsController.hasHiddenColumns()) { this._collapseAdaptiveDetailRow() } } _afterSaveEditData() { super._afterSaveEditData.apply(this, arguments); const deferred = new _deferred.Deferred; if (this._isRowEditMode() && this._adaptiveColumnsController.hasHiddenColumns()) { (0, _deferred.when)(this._validatingController.validate(true)).done((isValid => { if (isValid) { this._cancelEditAdaptiveDetailRow() } deferred.resolve() })) } else { deferred.resolve() } return deferred.promise() } _beforeCancelEditData() { super._beforeCancelEditData(); this._cancelEditAdaptiveDetailRow() } _getRowIndicesForCascadeUpdating(row) { const rowIndices = super._getRowIndicesForCascadeUpdating.apply(this, arguments); if (this._adaptiveColumnsController.isAdaptiveDetailRowExpanded(row.key)) { rowIndices.push("detailAdaptive" === row.rowType ? row.rowIndex - 1 : row.rowIndex + 1) } return rowIndices } _beforeCloseEditCellInBatchMode(rowIndices) { const expandedKey = this._dataController._adaptiveExpandedKey; if (expandedKey) { const rowIndex = _m_utils.default.getIndexByKey(expandedKey, this._dataController.items()); if (rowIndex > -1) { rowIndices.unshift(rowIndex) } } } editRow(rowIndex) { if (this._adaptiveColumnsController.isFormOrPopupEditMode()) { this._adaptiveColumnsController.collapseAdaptiveDetailRow() } return super.editRow(rowIndex) } deleteRow(rowIndex) { const rowKey = this._dataController.getKeyByRowIndex(rowIndex); if ("batch" === this.getEditMode() && this._adaptiveColumnsController.isAdaptiveDetailRowExpanded(rowKey)) { this._adaptiveColumnsController.collapseAdaptiveDetailRow() } super.deleteRow(rowIndex) } }; const data = Base => class extends Base { init() { super.init(); this._adaptiveExpandedKey = void 0 } _processItems(items, change) { const { changeType: changeType } = change; items = super._processItems.apply(this, arguments); if ("loadingAll" === changeType || !(0, _type.isDefined)(this._adaptiveExpandedKey)) { return items } const expandRowIndex = _m_utils.default.getIndexByKey(this._adaptiveExpandedKey, items); const newMode = false === this.option(LEGACY_SCROLLING_MODE); if (expandRowIndex >= 0) { const item = items[expandRowIndex]; items.splice(expandRowIndex + 1, 0, { visible: true, rowType: "detailAdaptive", key: item.key, data: item.data, node: item.node, modifiedValues: item.modifiedValues, isNewRow: item.isNewRow, values: item.values }) } else if ("refresh" === changeType && !(newMode && change.repaintChangesOnly)) { this._adaptiveExpandedKey = void 0 } return items } _getRowIndicesForExpand(key) { const rowIndices = super._getRowIndicesForExpand.apply(this, arguments); if (this._adaptiveColumnsController.isAdaptiveDetailRowExpanded(key)) { const lastRowIndex = rowIndices[rowIndices.length - 1]; rowIndices.push(lastRowIndex + 1) } return rowIndices } adaptiveExpandedKey(value) { if ((0, _type.isDefined)(value)) { this._adaptiveExpandedKey = value } else { return this._adaptiveExpandedKey } } toggleExpandAdaptiveDetailRow(key, alwaysExpanded) { let oldExpandLoadedRowIndex = _m_utils.default.getIndexByKey(this._adaptiveExpandedKey, this._items); let newExpandLoadedRowIndex = _m_utils.default.getIndexByKey(key, this._items); if (oldExpandLoadedRowIndex >= 0 && oldExpandLoadedRowIndex === newExpandLoadedRowIndex && !alwaysExpanded) { key = void 0; newExpandLoadedRowIndex = -1 } const oldKey = this._adaptiveExpandedKey; this._adaptiveExpandedKey = key; if (oldExpandLoadedRowIndex >= 0) { oldExpandLoadedRowIndex++ } if (newExpandLoadedRowIndex >= 0) { newExpandLoadedRowIndex++ } const rowIndexDelta = this.getRowIndexDelta(); this.updateItems({ allowInvisibleRowIndices: true, changeType: "update", rowIndices: [oldExpandLoadedRowIndex - rowIndexDelta, newExpandLoadedRowIndex - rowIndexDelta] }); this._adaptiveColumnsController.updateCommandAdaptiveAriaLabel(key, COLLAPSE_ARIA_NAME); this._adaptiveColumnsController.updateCommandAdaptiveAriaLabel(oldKey, EXPAND_ARIA_NAME) } }; const editorFactory = Base => class extends Base { _needHideBorder($element) { return super._needHideBorder($element) || (null === $element || void 0 === $element ? void 0 : $element.hasClass("dx-field-item-content")) && (null === $element || void 0 === $element ? void 0 : $element.find(".dx-checkbox").length) } _getFocusCellSelector() { return `${super._getFocusCellSelector()}, .dx-adaptive-detail-row .dx-field-item > .dx-field-item-content` } _getRevertTooltipsSelector() { return `${super._getRevertTooltipsSelector()}, .dx-field-item-content .${this.addWidgetPrefix("revert-tooltip")}` } }; const columns = Base => class extends Base { _isColumnVisible(column) { return super._isColumnVisible(column) && !column.adaptiveHidden } getVisibleDataColumnsByBandColumn(bandColumnIndex) { return super.getVisibleDataColumnsByBandColumn(bandColumnIndex).filter((column => "adaptiveHidden" !== column.visibleWidth)) } }; const resizing = Base => class extends Base { dispose() { super.dispose.apply(this, arguments); clearTimeout(this._updateScrollableTimeoutID) } _needBestFit() { return super._needBestFit() || !!this._adaptiveColumnsController.getHidingColumnsQueue().length } _correctColumnWidths(resultWidths, visibleColumns) { const adaptiveController = this._adaptiveColumnsController; const oldHiddenColumns = adaptiveController.getHiddenColumns(); const hidingColumnsQueue = adaptiveController.updateHidingQueue(this._columnsController.getColumns()); adaptiveController.hideRedundantColumns(resultWidths, visibleColumns, hidingColumnsQueue); const hiddenColumns = adaptiveController.getHiddenColumns(); if (adaptiveController.hasAdaptiveDetailRowExpanded()) { if (oldHiddenColumns.length !== hiddenColumns.length) { adaptiveController.updateForm(hiddenColumns) } }!hiddenColumns.length && adaptiveController.collapseAdaptiveDetailRow(); return super._correctColumnWidths.apply(this, arguments) } _toggleBestFitMode(isBestFit) { isBestFit && this._adaptiveColumnsController._showHiddenColumns(); super._toggleBestFitMode(isBestFit) } _needStretch() { const adaptiveColumnsController = this._adaptiveColumnsController; return super._needStretch.apply(this, arguments) || adaptiveColumnsController.getHidingColumnsQueue().length || adaptiveColumnsController.hasHiddenColumns() } }; const adaptivityModule = exports.adaptivityModule = { defaultOptions: () => ({ columnHidingEnabled: false, onAdaptiveDetailRowPreparing: null }), controllers: { adaptiveColumns: AdaptiveColumnsController }, extenders: { views: { rowsView: rowsView }, controllers: { export: exportExtender, columnsResizer: columnsResizer, draggingHeader: draggingHeader, editing: editing, resizing: resizing, data: data,