From f491e40e05b6be518219d43cfe3faa03c32f83c3 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Fri, 24 Oct 2025 15:53:21 +0400 Subject: [PATCH 01/10] DataGrid: fix interaction blocking while hovering over header if there are grouped columns and fixed columns are enabled (T1291988) --- .../__internal/grids/grid_core/adaptivity/m_adaptivity.ts | 4 ++-- .../grids/grid_core/column_fixing/m_column_fixing.ts | 3 +-- .../m_columns_resizing_reordering.ts | 5 +++-- .../js/__internal/grids/grid_core/sticky_columns/dom.ts | 4 +++- .../grids/grid_core/sticky_columns/m_sticky_columns.ts | 7 ++++--- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts index a70583e5aa2d..2724a0a85479 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts @@ -996,8 +996,8 @@ const exportExtender = ( const columnsResizer = ( Base: ModuleType, ) => class AdaptivityColumnsResizerExtender extends Base { - protected _pointCreated(point, cellsLength, columns) { - const result = super._pointCreated(point, cellsLength, columns); + protected _pointCreated(point, cells: dxElementWrapper | undefined, columns) { + const result = super._pointCreated(point, cells, columns); const currentColumn = columns[point.columnIndex] || {}; const nextColumnIndex = this._getNextColumnIndex(point.columnIndex); const nextColumn = columns[nextColumnIndex] || {}; diff --git a/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts b/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts index d217d7f9803f..9a387a1ae3df 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts @@ -408,7 +408,6 @@ const baseFixedColumns = >(Base: T) => class B return cellElements; } - // eslint-disable-next-line @typescript-eslint/no-unused-vars public getColumnWidths(fixedTableElement?: any, rowIndex?: number) { const result = super.getColumnWidths(fixedTableElement, rowIndex); const fixedColumns = this.getFixedColumns(); @@ -1122,7 +1121,7 @@ const columnsResizer = (Base: ModuleType) => class point.index += correctIndex; } - return that._pointCreated(point, columns.length, columns); + return that._pointCreated(point, { length: columns.length } as dxElementWrapper, columns); }); } } diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index 93cfe15e1c0e..bb306e36504a 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -748,11 +748,12 @@ export class ColumnsResizerViewController extends modules.ViewController { /** * @extended: adaptivity */ - protected _pointCreated(point, cellsLength, columns) { + protected _pointCreated(point, cells: dxElementWrapper | undefined, columns) { const isNextColumnMode = isNextColumnResizingMode(this); const rtlEnabled = this.option('rtlEnabled'); const isRtlParentStyle = this._isRtlParentStyle(); const firstPointColumnIndex = !isNextColumnMode && rtlEnabled && !isRtlParentStyle ? 0 : 1; + const cellsLength = cells?.length ?? 0; if (point.index >= firstPointColumnIndex && point.index < cellsLength + (!isNextColumnMode && (!rtlEnabled || isRtlParentStyle) ? 1 : 0)) { this._correctColumnIndexForPoint(point, firstPointColumnIndex, columns); @@ -989,7 +990,7 @@ export class ColumnsResizerViewController extends modules.ViewController { if (cells && cells.length > 0) { that._pointsByColumns = gridCoreUtils.getPointsByColumns( cells, - (point) => that._pointCreated(correctColumnY(point), cells.length, columns), + (point) => that._pointCreated(correctColumnY(point), cells, columns), false, 0, needToCheckPrevPoint, diff --git a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/dom.ts b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/dom.ts index 6b510d2c662e..0cb8682a0f38 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/dom.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/dom.ts @@ -194,6 +194,7 @@ const noNeedToCreateResizingPoint = ( point, column, nextColumn, + cells, }: { point: { x: number; @@ -204,6 +205,7 @@ const noNeedToCreateResizingPoint = ( }; column; nextColumn; + cells: dxElementWrapper | undefined; }, addWidgetPrefix, ): boolean => { @@ -212,7 +214,7 @@ const noNeedToCreateResizingPoint = ( const offsetX = Math.round(point.x); const rtlEnabled = that.option('rtlEnabled') as boolean; const isSplitPoint = isDefined(isLeftBoundary) || isDefined(isRightBoundary); - const $cells = $(that.getColumnElements() ?? ''); + const $cells = $(cells ?? ''); const $container = $(that.getContent()); const isFixedPoint = column?.fixed && nextColumn?.fixed; const nonFixedAreaBoundingRect = getNonFixedAreaBoundingRect($cells, $container, addWidgetPrefix); diff --git a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts index 3f1fbcc53c6c..cccb58f2b2a5 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts @@ -601,11 +601,11 @@ const columnsResizer = (Base: ModuleType) => class super._generatePointsByColumns(hasStickyColumns); } - protected _pointCreated(point, cellsLength, columns) { + protected _pointCreated(point, cells: dxElementWrapper | undefined, columns) { // @ts-expect-error const hasStickyColumns = this._columnHeadersView?.hasStickyColumns(); - const result = super._pointCreated(point, cellsLength, columns); - const needToCheckPoint = hasStickyColumns && cellsLength > 0; + const result = super._pointCreated(point, cells, columns); + const needToCheckPoint = hasStickyColumns && cells && cells.length > 0; if (needToCheckPoint && !result) { const column = columns[point.index - 1]; @@ -618,6 +618,7 @@ const columnsResizer = (Base: ModuleType) => class point, column, nextColumn, + cells, }, this.addWidgetPrefix.bind(this), ); From d71f149fa32b9562dd6f2c647922955a6053e54e Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Mon, 27 Oct 2025 21:48:40 +0400 Subject: [PATCH 02/10] DataGrid: fix interaction blocking while dragging a column if there are grouped and fixed columns enabled (T1291988) --- .../grid_core/adaptivity/m_adaptivity.ts | 8 +++++-- .../column_fixing/m_column_fixing.ts | 8 +++++-- .../m_columns_resizing_reordering.ts | 22 +++++++++++++++++-- .../sticky_columns/m_sticky_columns.ts | 13 ++++++----- .../columnsResizingReorderingModule.tests.js | 6 ++--- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts index 2724a0a85479..7ab06afce235 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts @@ -1022,8 +1022,12 @@ const columnsResizer = ( const draggingHeader = ( Base: ModuleType, ) => class AdaptivityDraggingHeaderExtender extends Base { - protected _pointCreated(point, columns, location, sourceColumn) { - const result = super._pointCreated(point, columns, location, sourceColumn); + protected _pointCreated({ + point, columns, location, sourceColumn, cells, + }) { + const result = super._pointCreated({ + point, columns, location, sourceColumn, cells, + }); const column = columns[point.columnIndex - 1] || {}; const hasAdaptiveHiddenWidth = column.visibleWidth === HIDDEN_COLUMNS_WIDTH; diff --git a/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts b/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts index 9a387a1ae3df..a4b9db8a7949 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts @@ -1076,8 +1076,12 @@ const draggingHeader = (Base: ModuleType) => class return super._generatePointsByColumns(options, needToCheckPrevPoint); } - protected _pointCreated(point, columns, location, sourceColumn) { - const result = super._pointCreated.apply(this, arguments as any); + protected _pointCreated({ + point, columns, location, sourceColumn, cells, + }) { + const result = super._pointCreated({ + point, columns, location, sourceColumn, cells, + }); const targetColumn = columns[point.columnIndex]; // @ts-expect-error const $transparentColumn = this._columnHeadersView.getTransparentColumnElement(); diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index bb306e36504a..31adc951f87e 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -1386,10 +1386,18 @@ export class DraggingHeaderViewController extends modules.ViewController { * @extended: column_fixing */ public _generatePointsByColumns(options, needToCheckPrevPoint = false) { + const cells = this._columnHeadersView.getColumnElements(); this.isCustomGroupColumnPosition = this.checkIsCustomGroupColumnPosition(options); + const points = gridCoreUtils.getPointsByColumns( options.columnElements, - (point) => this._pointCreated(point, options.columns, options.targetDraggingPanel.getName(), options.sourceColumn), + (point) => this._pointCreated({ + point, + columns: options.columns, + location: options.targetDraggingPanel.getName(), + sourceColumn: options.sourceColumn, + cells, + }), options.isVerticalOrientation, options.startColumnIndex, needToCheckPrevPoint, @@ -1422,9 +1430,19 @@ export class DraggingHeaderViewController extends modules.ViewController { * @param columns All columns in the given location * @param location Location where we move column (headers, group, column chooser etc) * @param sourceColumn Column that is dragging + * @param cells collection of draggable cells wrapped into jQuery object * @returns whether to filter current point (true - remove point, false - keep it) */ - protected _pointCreated(point, columns, location, sourceColumn): boolean { + + protected _pointCreated({ + point, columns, location, sourceColumn, + }: { + point: ColumnPoint; + columns; + location?; + sourceColumn?; + cells?: dxElementWrapper; + }): boolean { const targetColumn = columns[point.columnIndex]; const prevColumn = columns[point.columnIndex - 1]; diff --git a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts index cccb58f2b2a5..7ecf8a0af43d 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts @@ -665,18 +665,21 @@ const draggingHeader = (Base: ModuleType) => class return super._generatePointsByColumns(options, hasStickyColumns); } - protected _pointCreated(point, columns, location, sourceColumn) { + protected _pointCreated({ + point, columns, location, sourceColumn, cells, + }) { // @ts-expect-error const hasStickyColumns = this._columnHeadersView.hasStickyColumns(); - const $cells = this._columnHeadersView.getColumnElements(); - const needToCheckPoint = hasStickyColumns && location === 'headers' && $cells?.length + const needToCheckPoint = hasStickyColumns && location === 'headers' && cells?.length && (!sourceColumn.fixed || sourceColumn.fixedPosition === StickyPosition.Sticky); - const result = super._pointCreated(point, columns, location, sourceColumn); + const result = super._pointCreated({ + point, columns, location, sourceColumn, + }); if (needToCheckPoint && !result) { return GridCoreStickyColumnsDom.noNeedToCreateReorderingPoint( point, - $cells, + cells, $(this._columnHeadersView.getContent()), this.addWidgetPrefix.bind(this), ); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js index a79626098f86..1980e995a740 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js @@ -3525,7 +3525,7 @@ QUnit.module('Headers reordering', { // assert const $cells = controller._columnHeadersView._tableElement.find('td'); const points = gridCore.getPointsByColumns($cells, function(point) { - return controller._pointCreated(point, testColumns, 'headers', testColumns[1]); + return controller._pointCreated({ point, columns: testColumns, location: 'headers', sourceColumn: testColumns[1] }); }); assert.deepEqual(points, [ { x: -9930, y: -10000, columnIndex: 1, index: 1 }, @@ -3549,7 +3549,7 @@ QUnit.module('Headers reordering', { // assert const points = gridCore.getPointsByColumns($cells, function(point) { - return controller._pointCreated(point, testColumns); + return controller._pointCreated({ point, columns: testColumns }); }); assert.deepEqual(points, [ { x: -10000, y: -10000, columnIndex: 0, index: 0 }, @@ -3573,7 +3573,7 @@ QUnit.module('Headers reordering', { // assert assert.ok(!gridCore.getPointsByColumns($cells, function(point) { - return controller._pointCreated(point, testColumns, 'headers', testColumns[0]); + return controller._pointCreated({ point, columns: testColumns, location: 'headers', sourceColumn: testColumns[0] }); }).length, 'points by columns'); }); From 375204e7d892ea270ad52ed6ac7cb64f8eb1e120 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Tue, 28 Oct 2025 01:08:41 +0400 Subject: [PATCH 03/10] DataGrid: fix interaction blocking while dragging a column (T1291988) --- .../m_columns_resizing_reordering.ts | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index 31adc951f87e..90b0e10e2a4a 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -29,6 +29,7 @@ import type { ColumnChooserView } from '../column_chooser/m_column_chooser'; import type { ColumnHeadersView } from '../column_headers/m_column_headers'; import type { ColumnsController } from '../columns_controller/m_columns_controller'; import type { HeaderPanel } from '../header_panel/m_header_panel'; +import type { View } from '../m_modules'; import modules from '../m_modules'; import gridCoreUtils from '../m_utils'; import type { PagerView } from '../pager/m_pager'; @@ -66,6 +67,16 @@ type ColumnIndex = number | { columnIndex: number; }; +interface DraggingPanelBoundingRect { + draggingPanel: View; + boundingRect: { + top?: number; + left?: number; + right?: number; + bottom?: number; + }; +} + export class TrackerView extends modules.View { private _positionChanged: any; @@ -404,6 +415,8 @@ export class DraggingHeaderView extends modules.View { private _onSelectStart: any; + private _draggingPanelBoundingRects!: DraggingPanelBoundingRect[] | null; + /// #DEBUG private _testPointsByColumns: any; /// #ENDDEBUG @@ -449,6 +462,7 @@ export class DraggingHeaderView extends modules.View { this._columnsResizerViewController = this.getController('columnsResizer'); this._columnsController = this.getController('columns'); this._isDragging = false; + this._draggingPanelBoundingRects = null; dataController.loadingChanged.add((isLoading) => { const element = this.element(); @@ -465,16 +479,18 @@ export class DraggingHeaderView extends modules.View { private _getDraggingPanelByPos(pos) { const that = this; + const draggingPanelBoundingRects = that._getDraggingPanelBoundingRects(); let result; - each(that._dragOptions.draggingPanels, (index, draggingPanel) => { - if (draggingPanel) { - const boundingRect = draggingPanel.getBoundingRect(); - if (boundingRect && (boundingRect.bottom === undefined || pos.y < boundingRect.bottom) && (boundingRect.top === undefined || pos.y > boundingRect.top) - && (boundingRect.left === undefined || pos.x > boundingRect.left) && (boundingRect.right === undefined || pos.x < boundingRect.right)) { - result = draggingPanel; - return false; - } + each(draggingPanelBoundingRects, (_, { draggingPanel, boundingRect }) => { + if (boundingRect + && (boundingRect.bottom === undefined || pos.y < boundingRect.bottom) + && (boundingRect.top === undefined || pos.y > boundingRect.top) + && (boundingRect.left === undefined || pos.x > boundingRect.left) + && (boundingRect.right === undefined || pos.x < boundingRect.right) + ) { + result = draggingPanel; + return false; } return undefined; @@ -483,6 +499,29 @@ export class DraggingHeaderView extends modules.View { return result; } + public setDraggingPanelBoundingRects(): void { + const that = this; + const boundingRects: DraggingPanelBoundingRect[] = []; + + each(that._dragOptions.draggingPanels, (_, draggingPanel) => { + const boundingRect = draggingPanel?.getBoundingRect(); + + if (boundingRect) { + boundingRects.push({ draggingPanel, boundingRect }); + } + }); + + that._draggingPanelBoundingRects = boundingRects.length ? boundingRects : null; + } + + private _getDraggingPanelBoundingRects(): DraggingPanelBoundingRect[] | null { + return this._draggingPanelBoundingRects; + } + + private _resetDraggingPanelBoundingRects(): void { + this._draggingPanelBoundingRects = null; + } + protected _renderCore() { this.element() .addClass(`${this.addWidgetPrefix(DRAGGING_HEADER_CLASS)} ${this.addWidgetPrefix(CELL_CONTENT_CLASS)} ${WIDGET_CLASS}`) @@ -649,6 +688,7 @@ export class DraggingHeaderView extends modules.View { that._isDragging = false; // eslint-disable-next-line spellcheck/spell-checker domAdapter.getDocument().onselectstart = that._onSelectStart || null; + that._resetDraggingPanelBoundingRects(); } } @@ -1513,6 +1553,7 @@ export class DraggingHeaderViewController extends modules.ViewController { draggingPanels, rowIndex: that._columnsController.getRowIndex(column.index, true), }); + draggingHeader.setDraggingPanelBoundingRects(); })); eventsEngine.on($columnElement, addNamespace(dragEventMove, MODULE_NAMESPACE), { that: draggingHeader }, that.createAction(draggingHeader.moveHeader)); eventsEngine.on($columnElement, addNamespace(dragEventEnd, MODULE_NAMESPACE), { that: draggingHeader }, that.createAction(draggingHeader.dropHeader)); From f34a7bdb0e894d8ed2275fe6633c452494b99603 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Tue, 28 Oct 2025 15:20:16 +0400 Subject: [PATCH 04/10] fix(DataGrid): improve types description --- .../m_columns_resizing_reordering.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index 90b0e10e2a4a..be40a834a433 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -1464,11 +1464,11 @@ export class DraggingHeaderViewController extends modules.ViewController { } /** - * @extended: adaptivity, column_fixing - * Function that is used to filter column points, it's called for each point + * @extended adaptivity, column_fixing + * @description Function used to filter column points, it's called for each point * @param point Point that we are checking * @param columns All columns in the given location - * @param location Location where we move column (headers, group, column chooser etc) + * @param location Location where we move column (headers, group, column chooser, etc.) * @param sourceColumn Column that is dragging * @param cells collection of draggable cells wrapped into jQuery object * @returns whether to filter current point (true - remove point, false - keep it) @@ -1478,9 +1478,9 @@ export class DraggingHeaderViewController extends modules.ViewController { point, columns, location, sourceColumn, }: { point: ColumnPoint; - columns; - location?; - sourceColumn?; + columns: any[]; + location?: string; + sourceColumn?: any; cells?: dxElementWrapper; }): boolean { const targetColumn = columns[point.columnIndex]; From d4831eaa9688a1c6031d1958dc969456d0313289 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Tue, 28 Oct 2025 16:54:46 +0400 Subject: [PATCH 05/10] fix(DataGrid): move draggingPanelBoundingRects to _dragOptions property --- .../m_columns_resizing_reordering.ts | 44 ++----------------- .../columns_resizing_reordering/utils.ts | 28 ++++++++++++ 2 files changed, 31 insertions(+), 41 deletions(-) create mode 100644 packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.ts diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index be40a834a433..9650d25f980f 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -21,6 +21,7 @@ import { } from '@js/core/utils/size'; import { isDefined, isObject, isString } from '@js/core/utils/type'; import swatchContainer from '@ts/core/utils/swatch_container'; +import { getDraggingPanelBoundingRects } from '@ts/grids/grid_core/columns_resizing_reordering/utils'; import type { EditorFactory } from '@ts/grids/grid_core/editor_factory/m_editor_factory'; import type { ColumnPoint, ModuleType } from '@ts/grids/grid_core/m_types'; import type { RowsView } from '@ts/grids/grid_core/views/m_rows_view'; @@ -29,7 +30,6 @@ import type { ColumnChooserView } from '../column_chooser/m_column_chooser'; import type { ColumnHeadersView } from '../column_headers/m_column_headers'; import type { ColumnsController } from '../columns_controller/m_columns_controller'; import type { HeaderPanel } from '../header_panel/m_header_panel'; -import type { View } from '../m_modules'; import modules from '../m_modules'; import gridCoreUtils from '../m_utils'; import type { PagerView } from '../pager/m_pager'; @@ -67,16 +67,6 @@ type ColumnIndex = number | { columnIndex: number; }; -interface DraggingPanelBoundingRect { - draggingPanel: View; - boundingRect: { - top?: number; - left?: number; - right?: number; - bottom?: number; - }; -} - export class TrackerView extends modules.View { private _positionChanged: any; @@ -415,8 +405,6 @@ export class DraggingHeaderView extends modules.View { private _onSelectStart: any; - private _draggingPanelBoundingRects!: DraggingPanelBoundingRect[] | null; - /// #DEBUG private _testPointsByColumns: any; /// #ENDDEBUG @@ -462,7 +450,6 @@ export class DraggingHeaderView extends modules.View { this._columnsResizerViewController = this.getController('columnsResizer'); this._columnsController = this.getController('columns'); this._isDragging = false; - this._draggingPanelBoundingRects = null; dataController.loadingChanged.add((isLoading) => { const element = this.element(); @@ -479,10 +466,9 @@ export class DraggingHeaderView extends modules.View { private _getDraggingPanelByPos(pos) { const that = this; - const draggingPanelBoundingRects = that._getDraggingPanelBoundingRects(); let result; - each(draggingPanelBoundingRects, (_, { draggingPanel, boundingRect }) => { + each(that._dragOptions.draggingPanelBoundingRects, (_, { draggingPanel, boundingRect }) => { if (boundingRect && (boundingRect.bottom === undefined || pos.y < boundingRect.bottom) && (boundingRect.top === undefined || pos.y > boundingRect.top) @@ -499,29 +485,6 @@ export class DraggingHeaderView extends modules.View { return result; } - public setDraggingPanelBoundingRects(): void { - const that = this; - const boundingRects: DraggingPanelBoundingRect[] = []; - - each(that._dragOptions.draggingPanels, (_, draggingPanel) => { - const boundingRect = draggingPanel?.getBoundingRect(); - - if (boundingRect) { - boundingRects.push({ draggingPanel, boundingRect }); - } - }); - - that._draggingPanelBoundingRects = boundingRects.length ? boundingRects : null; - } - - private _getDraggingPanelBoundingRects(): DraggingPanelBoundingRect[] | null { - return this._draggingPanelBoundingRects; - } - - private _resetDraggingPanelBoundingRects(): void { - this._draggingPanelBoundingRects = null; - } - protected _renderCore() { this.element() .addClass(`${this.addWidgetPrefix(DRAGGING_HEADER_CLASS)} ${this.addWidgetPrefix(CELL_CONTENT_CLASS)} ${WIDGET_CLASS}`) @@ -688,7 +651,6 @@ export class DraggingHeaderView extends modules.View { that._isDragging = false; // eslint-disable-next-line spellcheck/spell-checker domAdapter.getDocument().onselectstart = that._onSelectStart || null; - that._resetDraggingPanelBoundingRects(); } } @@ -1551,9 +1513,9 @@ export class DraggingHeaderViewController extends modules.ViewController { columnElement: $columnElement, sourceLocation: nameDraggingPanel, draggingPanels, + draggingPanelBoundingRects: getDraggingPanelBoundingRects(draggingPanels), rowIndex: that._columnsController.getRowIndex(column.index, true), }); - draggingHeader.setDraggingPanelBoundingRects(); })); eventsEngine.on($columnElement, addNamespace(dragEventMove, MODULE_NAMESPACE), { that: draggingHeader }, that.createAction(draggingHeader.moveHeader)); eventsEngine.on($columnElement, addNamespace(dragEventEnd, MODULE_NAMESPACE), { that: draggingHeader }, that.createAction(draggingHeader.dropHeader)); diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.ts new file mode 100644 index 000000000000..88e798ce4023 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.ts @@ -0,0 +1,28 @@ +import { each } from '@ts/core/utils/m_iterator'; +import type { View } from '@ts/grids/grid_core/m_modules'; + +interface DraggingPanelBoundingRect { + draggingPanel: View; + boundingRect: { + top?: number; + left?: number; + right?: number; + bottom?: number; + }; +} + +export const getDraggingPanelBoundingRects = ( + draggingPanels: View[], +): DraggingPanelBoundingRect[] | null => { + const boundingRects: DraggingPanelBoundingRect[] = []; + + each(draggingPanels, (_, draggingPanel) => { + const boundingRect = draggingPanel?.getBoundingRect(); + + if (boundingRect) { + boundingRects.push({ draggingPanel, boundingRect }); + } + }); + + return boundingRects.length ? boundingRects : null; +}; From 6599c7f8cb03ec6aa58ea26d46d8c44945f9d5f3 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Tue, 28 Oct 2025 17:29:14 +0400 Subject: [PATCH 06/10] fix(DataGrid): fix jsdoc --- .../m_columns_resizing_reordering.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index 9650d25f980f..b3865195ec0b 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -1426,7 +1426,7 @@ export class DraggingHeaderViewController extends modules.ViewController { } /** - * @extended adaptivity, column_fixing + * @extended: adaptivity, column_fixing * @description Function used to filter column points, it's called for each point * @param point Point that we are checking * @param columns All columns in the given location From cfb456c6a57001bf3026d424e1fd5665808108d2 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Wed, 29 Oct 2025 00:04:17 +0400 Subject: [PATCH 07/10] fix(DataGrid): fix QUnit tests --- .../m_columns_resizing_reordering.ts | 7 +++++-- .../columnsResizingReorderingModule.tests.js | 14 +++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index b3865195ec0b..4a7ba4276a2b 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -527,9 +527,13 @@ export class DraggingHeaderView extends modules.View { public dragHeader(options) { const { columnElement } = options; + const dragOptions = { + ...options, + draggingPanelBoundingRects: getDraggingPanelBoundingRects(options.draggingPanels), + }; this._isDragging = true; - this._dragOptions = options; + this._dragOptions = dragOptions; this._dropOptions = { sourceIndex: options.index, sourceColumnIndex: this._getVisibleIndexObject(options.rowIndex, options.columnIndex), @@ -1513,7 +1517,6 @@ export class DraggingHeaderViewController extends modules.ViewController { columnElement: $columnElement, sourceLocation: nameDraggingPanel, draggingPanels, - draggingPanelBoundingRects: getDraggingPanelBoundingRects(draggingPanels), rowIndex: that._columnsController.getRowIndex(column.index, true), }); })); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js index 1980e995a740..52b5c5f5c512 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js @@ -4657,11 +4657,11 @@ QUnit.module('Headers reordering', { const controller = this.createDraggingHeaderViewController(); controller._rowsView = {}; - controller._columnHeadersView = { toggleDraggableColumnClass: noop }; controller._rowsView.toggleDraggableColumnClass = function(columnIndex, value) { columnIndexOpacity = columnIndex; toggleClass = value; }; + controller._columnHeadersView = { toggleDraggableColumnClass: noop, getColumnElements: noop }; controller._columnHeadersView.element = function() { return $('
'); }; @@ -5440,7 +5440,7 @@ QUnit.module('Group panel reordering', { let opacityValue; this.controller._rowsView = {}; - this.controller._columnHeadersView = { toggleDraggableColumnClass: noop }; + this.controller._columnHeadersView = { toggleDraggableColumnClass: noop, getColumnElements: noop }; this.controller._rowsView.toggleDraggableColumnClass = function(columnIndex, value) { columnIndexOpacity = columnIndex; opacityValue = value; @@ -5509,8 +5509,8 @@ QUnit.module('Group panel reordering', { const testElement = $('#container'); that.controller._rowsView = {}; - that.controller._columnHeadersView = {}; that.controller._rowsView.toggleDraggableColumnClass = function() {}; + that.controller._columnHeadersView = { getColumnElements: noop }; that.controller._columnHeadersView.element = function() { return that.draggingPanels[0].element().append($('
').addClass('dx-header-row')); }; @@ -5576,8 +5576,8 @@ QUnit.module('Group panel reordering', { const testElement = $('#container'); that.controller._rowsView = {}; - that.controller._columnHeadersView = {}; that.controller._rowsView.toggleDraggableColumnClass = function() {}; + that.controller._columnHeadersView = { getColumnElements: noop }; that.controller._columnHeadersView.element = function() { return that.draggingPanels[0].element().append($('
').addClass('dx-header-row')); }; @@ -5625,8 +5625,8 @@ QUnit.module('Group panel reordering', { const testElement = $('#container'); that.controller._rowsView = {}; - that.controller._columnHeadersView = { toggleDraggableColumnClass: noop }; that.controller._rowsView.toggleDraggableColumnClass = function() {}; + that.controller._columnHeadersView = { toggleDraggableColumnClass: noop, getColumnElements: noop }; that.controller._columnHeadersView.element = function() { return that.draggingPanels[0].element().append($('
').addClass('dx-header-row')); }; @@ -5689,7 +5689,7 @@ QUnit.module('Group panel reordering', { const testElement = $('#container'); that.controller._rowsView = {}; - that.controller._columnHeadersView = { toggleDraggableColumnClass: noop }; + that.controller._columnHeadersView = { toggleDraggableColumnClass: noop, getColumnElements: noop }; that.controller._rowsView.toggleDraggableColumnClass = function() {}; that.controller._columnHeadersView.element = function() { return that.draggingPanels[0].element().append($('
').addClass('dx-header-row')); @@ -5738,8 +5738,8 @@ QUnit.module('Group panel reordering', { const testElement = $('#container'); that.controller._rowsView = {}; - that.controller._columnHeadersView = {}; that.controller._rowsView.toggleDraggableColumnClass = function() {}; + that.controller._columnHeadersView = { getColumnElements: noop }; that.controller._columnHeadersView.element = function() { return that.draggingPanels[0].element().append($('
').addClass('dx-header-row')); }; From e5bbbeb41c8a6dfbcc34e1b23f719861be33ca07 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Wed, 29 Oct 2025 11:41:00 +0400 Subject: [PATCH 08/10] test(DataGrid): add unit tests for utils --- .../m_columns_resizing_reordering.ts | 2 +- .../columns_resizing_reordering/utils.test.ts | 74 +++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index 4a7ba4276a2b..e0001ec0caa9 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -1436,7 +1436,7 @@ export class DraggingHeaderViewController extends modules.ViewController { * @param columns All columns in the given location * @param location Location where we move column (headers, group, column chooser, etc.) * @param sourceColumn Column that is dragging - * @param cells collection of draggable cells wrapped into jQuery object + * @param cells JQuery-wrapped collection of header cell elements * @returns whether to filter current point (true - remove point, false - keep it) */ diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts new file mode 100644 index 000000000000..3c4f4de9a034 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts @@ -0,0 +1,74 @@ +import { describe, expect, it } from '@jest/globals'; + +import { getDraggingPanelBoundingRects } from './utils'; + +const getRandomPoint = (max: number) => Math.floor(Math.random() * max); + +const getDraggingPanelMock = () => ({ + getBoundingRect: () => ({ + top: getRandomPoint(1080), + bottom: getRandomPoint(1080), + left: getRandomPoint(1920), + right: getRandomPoint(1920), + }), +} as any); + +describe('m_columns_resizing_reordering/utils.test.ts', () => { + describe('getDraggingPanelBoundingRects', () => { + it('returns equal amount of elements in tuple', () => { + const draggingPanels = [ + getDraggingPanelMock(), + getDraggingPanelMock(), + getDraggingPanelMock(), + ]; + const result = getDraggingPanelBoundingRects(draggingPanels); + + expect(result?.length).toBe(draggingPanels.length); + }); + + it('returns the same dragging panel objects', () => { + const draggingPanels = [ + getDraggingPanelMock(), + getDraggingPanelMock(), + getDraggingPanelMock(), + ]; + const result = getDraggingPanelBoundingRects(draggingPanels); + + expect(result).not.toBeNull(); + result?.forEach((draggingPanelBoundingRect, index) => { + expect(draggingPanelBoundingRect.draggingPanel).toBe(draggingPanels[index]); + }); + }); + + it('returns filtered tuple without empty objects', () => { + const draggingPanels = [ + getDraggingPanelMock(), + undefined, + getDraggingPanelMock(), + null, + ]; + const result = getDraggingPanelBoundingRects(draggingPanels); + + expect(result?.length).toBe(draggingPanels.filter(Boolean).length); + }); + + it('returns null if the result is empty array', () => { + const draggingPanels = [undefined, null] as any[]; + const result = getDraggingPanelBoundingRects(draggingPanels); + + expect(result).toBeNull(); + }); + + it('returns null if draggingPanels array is empty', () => { + const draggingPanels = [] as any[]; + const result = getDraggingPanelBoundingRects(draggingPanels); + + expect(result).toBeNull(); + }); + + it('returns null if draggingPanels is null or undefined', () => { + expect(getDraggingPanelBoundingRects(undefined as any)).toBeNull(); + expect(getDraggingPanelBoundingRects(null as any)).toBeNull(); + }); + }); +}); From ffe2b7f46ead9f92934e9f82f80f0f5ada850d4f Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Wed, 29 Oct 2025 18:00:23 +0400 Subject: [PATCH 09/10] test(DataGrid): add integration tests --- ...ns_resizing_reordering.integration.test.ts | 183 ++++++++++++++++++ .../columns_resizing_reordering/utils.test.ts | 90 +++++---- 2 files changed, 227 insertions(+), 46 deletions(-) create mode 100644 packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.integration.test.ts diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.integration.test.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.integration.test.ts new file mode 100644 index 000000000000..2748d0d6a56a --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.integration.test.ts @@ -0,0 +1,183 @@ +import { + afterEach, beforeEach, describe, expect, it, jest, +} from '@jest/globals'; +import { + end as dragEventEnd, + move as dragEventMove, + start as dragEventStart, +} from '@js/common/core/events/drag'; +import type { dxElementWrapper } from '@js/core/renderer'; +import $ from '@js/core/renderer'; +import type { Properties as DataGridProperties } from '@js/ui/data_grid'; +import DataGrid from '@js/ui/data_grid'; +import errors from '@js/ui/widget/ui.errors'; +import { DataGridModel } from '@ts/grids/data_grid/__tests__/__mock__/model/data_grid'; + +const SELECTORS = { + gridContainer: '#gridContainer', +}; + +const GRID_CONTAINER_ID = 'gridContainer'; + +const createDataGrid = async ( + options: DataGridProperties = {}, +): Promise<{ + $container: dxElementWrapper; + component: DataGridModel; + instance: DataGrid; +}> => new Promise((resolve) => { + const $container = $('
') + .attr('id', GRID_CONTAINER_ID) + .appendTo(document.body); + + const instance = new DataGrid($container.get(0) as HTMLDivElement, options); + const component = new DataGridModel($container.get(0) as HTMLElement); + + jest.runAllTimers(); + + resolve({ + $container, + component, + instance, + }); +}); + +const beforeTest = (): void => { + jest.useFakeTimers(); + jest.spyOn(errors, 'log').mockImplementation(jest.fn()); +}; + +const afterTest = (): void => { + const $container = $(SELECTORS.gridContainer); + const dataGrid = ($container as any).dxDataGrid('instance') as DataGrid; + + dataGrid.dispose(); + $container.remove(); + jest.clearAllMocks(); + jest.useRealTimers(); +}; + +describe('Performance optimization', () => { + beforeEach(beforeTest); + afterEach(afterTest); + + const createGridWith200Columns = async (): Promise<{ + $container: dxElementWrapper; + component: DataGridModel; + instance: DataGrid; + }> => { + const columns = [ + { + dataField: 'id', caption: 'ID', width: '100px', fixed: true, + }, + { + caption: 'Name', + columns: [ + { dataField: 'name.first', caption: 'First name', width: '150px' }, + { dataField: 'name.last', caption: 'Last name', width: '150px' }, + ], + }, + ...Array.from({ length: 198 }, (_, index) => ({ + dataField: `values.${index}`, + caption: `Value ${index + 1}`, + width: '100px', + })), + ]; + + const dataSource = [ + { + id: 1, + name: { first: 'John', last: 'Doe' }, + values: Array.from({ length: 198 }, (_, index) => index + 1), + }, + ]; + + return createDataGrid({ + dataSource, + columns, + width: '100%', + showBorders: true, + showColumnLines: true, + allowColumnResizing: true, + allowColumnReordering: true, + }); + }; + + describe('ColumnsResizerViewController', () => { + it('should call "_pointCreated" 202 times when generating points by columns (1 fixed + 1 group + 2 group children + 198 regular)', async () => { + const { instance } = await createGridWith200Columns(); + const columnsResizerController = (instance as any).getController('columnsResizer'); + + const pointCreatedSpy = jest.spyOn(columnsResizerController, '_pointCreated'); + + columnsResizerController.pointsByColumns(); + + expect(pointCreatedSpy).toHaveBeenCalledTimes(202); + }); + + it('should call "getColumnElements" as many times as there are head rows', async () => { + const { instance } = await createGridWith200Columns(); + const columnsResizerController = (instance as any).getController('columnsResizer'); + const columnHeadersView = (instance as any).getView('columnHeadersView'); + + const columnHeadersViewSpy = jest.spyOn(columnHeadersView, 'getColumnElements'); + + columnsResizerController.pointsByColumns(); + + expect(columnHeadersViewSpy).toHaveBeenCalledTimes(2); + }); + }); + + describe('DraggingHeaderViewController', () => { + const getDragEvent = ( + eventName: string, + headerOffset: { left: number; top: number }, + dragOffset: { left: number; top: number }, + ) => { + const dragEndEvent = document.createEvent('CustomEvent') as any; + + dragEndEvent.initCustomEvent(eventName, true, true); + dragEndEvent.pageX = headerOffset.left + dragOffset.left; + dragEndEvent.pageY = headerOffset.top + dragOffset.top; + dragEndEvent.pointerType = 'mouse'; + + return dragEndEvent; + }; + + it('should call "getBoundingRect" once for each dragging panel view', async () => { + const { instance } = await createGridWith200Columns(); + const columnHeadersView = (instance as any).getView('columnHeadersView'); + const columnChooserView = (instance as any).getView('columnChooserView'); + const headerPanelView = (instance as any).getView('headerPanel'); + + const getBoundingViewMocks = [ + jest.spyOn(columnHeadersView, 'getBoundingRect'), + jest.spyOn(columnChooserView, 'getBoundingRect'), + jest.spyOn(headerPanelView, 'getBoundingRect'), + ]; + + const $headerCell = $(columnHeadersView.element()).find('.dx-header-row td').eq(5); + const headerOffset = $headerCell.offset(); + + if (!headerOffset) { + throw new Error('Header cell not found'); + } + + const dragStartOffset = { left: 10, top: 10 }; + const dragStartEvent = getDragEvent(dragEventStart, headerOffset, dragStartOffset); + $headerCell.get(0)?.dispatchEvent(dragStartEvent); + + const dragMoveOffset = { left: 500, top: 10 }; + const dragMoveEvent = getDragEvent(dragEventMove, headerOffset, dragMoveOffset); + $headerCell.get(0)?.dispatchEvent(dragMoveEvent); + + const dragEndOffset = { left: 500, top: 10 }; + const dragEndEvent = getDragEvent(dragEventEnd, headerOffset, dragEndOffset); + $headerCell.get(0)?.dispatchEvent(dragEndEvent); + + getBoundingViewMocks.forEach((getBoundingViewMock) => { + expect(getBoundingViewMock).toHaveBeenCalledTimes(1); + }); + }); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts index 3c4f4de9a034..91f6fb558590 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/utils.test.ts @@ -13,62 +13,60 @@ const getDraggingPanelMock = () => ({ }), } as any); -describe('m_columns_resizing_reordering/utils.test.ts', () => { - describe('getDraggingPanelBoundingRects', () => { - it('returns equal amount of elements in tuple', () => { - const draggingPanels = [ - getDraggingPanelMock(), - getDraggingPanelMock(), - getDraggingPanelMock(), - ]; - const result = getDraggingPanelBoundingRects(draggingPanels); +describe('getDraggingPanelBoundingRects', () => { + it('returns equal amount of elements in tuple', () => { + const draggingPanels = [ + getDraggingPanelMock(), + getDraggingPanelMock(), + getDraggingPanelMock(), + ]; + const result = getDraggingPanelBoundingRects(draggingPanels); - expect(result?.length).toBe(draggingPanels.length); - }); + expect(result?.length).toBe(draggingPanels.length); + }); - it('returns the same dragging panel objects', () => { - const draggingPanels = [ - getDraggingPanelMock(), - getDraggingPanelMock(), - getDraggingPanelMock(), - ]; - const result = getDraggingPanelBoundingRects(draggingPanels); + it('returns the same dragging panel objects', () => { + const draggingPanels = [ + getDraggingPanelMock(), + getDraggingPanelMock(), + getDraggingPanelMock(), + ]; + const result = getDraggingPanelBoundingRects(draggingPanels); - expect(result).not.toBeNull(); - result?.forEach((draggingPanelBoundingRect, index) => { - expect(draggingPanelBoundingRect.draggingPanel).toBe(draggingPanels[index]); - }); + expect(result).not.toBeNull(); + result?.forEach((draggingPanelBoundingRect, index) => { + expect(draggingPanelBoundingRect.draggingPanel).toBe(draggingPanels[index]); }); + }); - it('returns filtered tuple without empty objects', () => { - const draggingPanels = [ - getDraggingPanelMock(), - undefined, - getDraggingPanelMock(), - null, - ]; - const result = getDraggingPanelBoundingRects(draggingPanels); + it('returns filtered tuple without empty objects', () => { + const draggingPanels = [ + getDraggingPanelMock(), + undefined, + getDraggingPanelMock(), + null, + ]; + const result = getDraggingPanelBoundingRects(draggingPanels); - expect(result?.length).toBe(draggingPanels.filter(Boolean).length); - }); + expect(result?.length).toBe(draggingPanels.filter(Boolean).length); + }); - it('returns null if the result is empty array', () => { - const draggingPanels = [undefined, null] as any[]; - const result = getDraggingPanelBoundingRects(draggingPanels); + it('returns null if the result is empty array', () => { + const draggingPanels = [undefined, null] as any[]; + const result = getDraggingPanelBoundingRects(draggingPanels); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('returns null if draggingPanels array is empty', () => { - const draggingPanels = [] as any[]; - const result = getDraggingPanelBoundingRects(draggingPanels); + it('returns null if draggingPanels array is empty', () => { + const draggingPanels = [] as any[]; + const result = getDraggingPanelBoundingRects(draggingPanels); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('returns null if draggingPanels is null or undefined', () => { - expect(getDraggingPanelBoundingRects(undefined as any)).toBeNull(); - expect(getDraggingPanelBoundingRects(null as any)).toBeNull(); - }); + it('returns null if draggingPanels is null or undefined', () => { + expect(getDraggingPanelBoundingRects(undefined as any)).toBeNull(); + expect(getDraggingPanelBoundingRects(null as any)).toBeNull(); }); }); From c31cb81a498646675b94528fe3cc112ccd5c5f78 Mon Sep 17 00:00:00 2001 From: Danil Mirgaev Date: Fri, 31 Oct 2025 17:00:51 +0400 Subject: [PATCH 10/10] fix(DataGrid): simplify the "_ pointCreated" method --- .../__internal/grids/grid_core/adaptivity/m_adaptivity.ts | 4 ++-- .../grids/grid_core/column_fixing/m_column_fixing.ts | 2 +- .../m_columns_resizing_reordering.ts | 6 +++--- .../grids/grid_core/sticky_columns/m_sticky_columns.ts | 7 ++++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts index 7ab06afce235..2280bd6263f5 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/adaptivity/m_adaptivity.ts @@ -996,8 +996,8 @@ const exportExtender = ( const columnsResizer = ( Base: ModuleType, ) => class AdaptivityColumnsResizerExtender extends Base { - protected _pointCreated(point, cells: dxElementWrapper | undefined, columns) { - const result = super._pointCreated(point, cells, columns); + protected _pointCreated(point, columns, cells?: dxElementWrapper) { + const result = super._pointCreated(point, columns, cells); const currentColumn = columns[point.columnIndex] || {}; const nextColumnIndex = this._getNextColumnIndex(point.columnIndex); const nextColumn = columns[nextColumnIndex] || {}; diff --git a/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts b/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts index a4b9db8a7949..96fa1c78e427 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/column_fixing/m_column_fixing.ts @@ -1125,7 +1125,7 @@ const columnsResizer = (Base: ModuleType) => class point.index += correctIndex; } - return that._pointCreated(point, { length: columns.length } as dxElementWrapper, columns); + return that._pointCreated(point, columns); }); } } diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts index e0001ec0caa9..8514b917c3c6 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_resizing_reordering/m_columns_resizing_reordering.ts @@ -754,12 +754,12 @@ export class ColumnsResizerViewController extends modules.ViewController { /** * @extended: adaptivity */ - protected _pointCreated(point, cells: dxElementWrapper | undefined, columns) { + protected _pointCreated(point, columns, cells?: dxElementWrapper) { const isNextColumnMode = isNextColumnResizingMode(this); const rtlEnabled = this.option('rtlEnabled'); const isRtlParentStyle = this._isRtlParentStyle(); const firstPointColumnIndex = !isNextColumnMode && rtlEnabled && !isRtlParentStyle ? 0 : 1; - const cellsLength = cells?.length ?? 0; + const cellsLength = cells?.length ?? columns.length; if (point.index >= firstPointColumnIndex && point.index < cellsLength + (!isNextColumnMode && (!rtlEnabled || isRtlParentStyle) ? 1 : 0)) { this._correctColumnIndexForPoint(point, firstPointColumnIndex, columns); @@ -996,7 +996,7 @@ export class ColumnsResizerViewController extends modules.ViewController { if (cells && cells.length > 0) { that._pointsByColumns = gridCoreUtils.getPointsByColumns( cells, - (point) => that._pointCreated(correctColumnY(point), cells, columns), + (point) => that._pointCreated(correctColumnY(point), columns, cells), false, 0, needToCheckPrevPoint, diff --git a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts index 7ecf8a0af43d..e3bed6985f33 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/sticky_columns/m_sticky_columns.ts @@ -601,11 +601,12 @@ const columnsResizer = (Base: ModuleType) => class super._generatePointsByColumns(hasStickyColumns); } - protected _pointCreated(point, cells: dxElementWrapper | undefined, columns) { + protected _pointCreated(point, columns, cells?: dxElementWrapper) { // @ts-expect-error const hasStickyColumns = this._columnHeadersView?.hasStickyColumns(); - const result = super._pointCreated(point, cells, columns); - const needToCheckPoint = hasStickyColumns && cells && cells.length > 0; + const result = super._pointCreated(point, columns, cells); + const cellsLength = cells?.length ?? columns.length; + const needToCheckPoint = hasStickyColumns && cellsLength > 0; if (needToCheckPoint && !result) { const column = columns[point.index - 1];