diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering.ts deleted file mode 100644 index 70c9de3bdcf3..000000000000 --- a/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { ClientFunction } from 'testcafe'; -import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; -import DataGrid from 'devextreme-testcafe-models/dataGrid'; -import { ClassNames } from 'devextreme-testcafe-models/dataGrid/classNames'; -import url from '../../../helpers/getPageUrl'; -import { createWidget } from '../../../helpers/createWidget'; -import { MouseAction, MouseUpEvents } from '../../../helpers/mouseUpEvents'; -import { testScreenshot } from '../../../helpers/themeUtils'; - -const CLASS = ClassNames; - -const getVisibleColumns = (dataGrid: DataGrid): Promise => { - const { getInstance } = dataGrid; - - return ClientFunction( - () => (getInstance() as any) - .getVisibleColumns() - .map((column: any) => column.dataField || column.name), - { dependencies: { getInstance } }, - )(); -}; -const getColumnsSeparatorOffset = ClientFunction(() => $(`.${CLASS.columnsSeparator}`).offset(), { dependencies: { CLASS } }); - -fixture.disablePageReloads`Column reordering` - .page(url(__dirname, '../../container.html')); - -// T975549 -test('The column reordering should work correctly when there is a fixed column with zero width', async (t) => { - const dataGrid = new DataGrid('#container'); - const headers = dataGrid.getHeaders(); - const headerRow = headers.getHeaderRow(0); - - await t - .expect(headerRow.getHeaderCell(2).element.textContent) - .eql('Field 2') - .drag(headerRow.getHeaderCell(3).element, -400, 0) - .expect(headerRow.getHeaderCell(2).element.textContent) - .eql('Field 3') - .expect(getVisibleColumns(dataGrid)) - .eql(['field1', 'fake', 'field3', 'field2', 'field4']); -}).before(async () => createWidget('dxDataGrid', { - width: 800, - dataSource: [ - { - field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', - }, - ], - columnFixing: { - // @ts-expect-error private option - legacyMode: true, - }, - columns: [ - { - dataField: 'field1', - fixed: true, - width: 200, - }, { - name: 'fake', - fixed: true, - width: 0.01, - }, { - dataField: 'field2', - width: 200, - }, { - dataField: 'field3', - width: 200, - }, { - dataField: 'field4', - width: 200, - }, - ], - allowColumnReordering: true, -})); - -// T1038094 -test('The separator should display correctly when dragging column', async (t) => { - const dataGrid = new DataGrid('#container'); - - await dataGrid.moveHeader(0, 200, 5, true); - - await t - .expect(getColumnsSeparatorOffset()) - .eql({ - left: 8, - top: 8, - }); - - await dataGrid.moveHeader(0, 400, 5); - - const offset2 = await getColumnsSeparatorOffset(); - await t - .expect(offset2!.left).within(405, 406.5) - .expect(offset2!.top).eql(8); - - await dataGrid.moveHeader(0, 600, 5); - - const offset3 = await getColumnsSeparatorOffset(); - - await t - .expect(offset3!.left).within(605, 606.5) - .expect(offset3!.top).eql(8); - - await dataGrid.moveHeader(0, 800, 5); - - await t - .expect(getColumnsSeparatorOffset()) - .eql({ - left: 805, - top: 8, - }); -}).before(async () => createWidget('dxDataGrid', { - width: 800, - dataSource: [ - { - field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', - }, - ], - columns: [ - { - dataField: 'field1', - width: 200, - }, { - dataField: 'field2', - width: 200, - }, { - dataField: 'field3', - width: 200, - }, { - dataField: 'field4', - width: 200, - }, - ], - allowColumnReordering: true, - allowColumnResizing: true, -})); - -test.meta({ unstable: true })('column separator should work properly with expand columns', async (t) => { - const { takeScreenshot, compareResults } = createScreenshotsComparer(t); - const dataGrid = new DataGrid('#container'); - await MouseUpEvents.disable(MouseAction.dragToOffset); - - await t.drag(dataGrid.getGroupPanel().getHeader(0).element, 0, 30); - await testScreenshot(t, takeScreenshot, 'column-separator-with-expand-columns.png'); - await t - .expect(compareResults.isValid()) - .ok(compareResults.errorMessages()); - - await MouseUpEvents.enable(MouseAction.dragToOffset); -}).before(async () => createWidget('dxDataGrid', { - width: 800, - dataSource: [ - { - field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', - }, - ], - groupPanel: { - visible: true, - }, - columns: [ - { - dataField: 'field1', - width: 200, - groupIndex: 0, - }, { - dataField: 'field2', - width: 200, - groupIndex: 1, - }, { - dataField: 'field3', - width: 200, - }, { - dataField: 'field4', - width: 200, - }, - ], - allowColumnReordering: true, -})); - -test('HeaderRow should be highlighted when dragging column with allowColumnReordering=false', async (t) => { - const { takeScreenshot, compareResults } = createScreenshotsComparer(t); - const dataGrid = new DataGrid('#container'); - await MouseUpEvents.disable(MouseAction.dragToOffset); - - await t.drag(dataGrid.getGroupPanel().getHeader(0).element, 0, 30); - await testScreenshot(t, takeScreenshot, 'headerRow-highlight-on-drag.png'); - await t - .expect(compareResults.isValid()) - .ok(compareResults.errorMessages()); - - await MouseUpEvents.enable(MouseAction.dragToOffset); -}).before(async () => createWidget('dxDataGrid', { - width: 800, - dataSource: [ - { - field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', - }, - ], - groupPanel: { - visible: true, - }, - columns: [ - { - dataField: 'field1', - width: 200, - groupIndex: 0, - }, { - dataField: 'field2', - width: 200, - groupIndex: 1, - }, { - dataField: 'field3', - width: 200, - }, { - dataField: 'field4', - width: 200, - }, - ], - allowColumnReordering: false, -})); - -test('Column without allowReordering should have same position after dragging to groupPanel and back', async (t) => { - const dataGrid = new DataGrid('#container'); - - await t.expect(dataGrid.isReady()).ok(); - - await t.drag(dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(2).element, -100, -50); - - await t.expect(dataGrid.getGroupPanel().getHeadersCount()).eql(1); - - await t.drag(dataGrid.getGroupPanel().getHeader(0).element, 0, 50); - - const headers = await Promise.all([0, 1, 2, 3].map( - (i) => dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(i).element.textContent, - )); - - await t.expect(headers).eql(['Field 1', 'Field 2', 'Field 3', 'Field 4']); -}).before(async () => createWidget('dxDataGrid', { - width: 800, - dataSource: [ - { - field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', - }, - ], - groupPanel: { - visible: true, - }, - columns: [ - { - dataField: 'field1', - width: 200, - }, { - dataField: 'field2', - width: 200, - }, { - dataField: 'field3', - width: 200, - }, { - dataField: 'field4', - width: 200, - }, - ], - allowColumnReordering: false, -})); - -test('The group separator should not appear when dragging a grouped column to the same position', async (t) => { - const dataGrid = new DataGrid('#container'); - const { takeScreenshot, compareResults } = createScreenshotsComparer(t); - - await t.drag(dataGrid.getGroupPanel().getHeader(0).element, -25, 20); - - await testScreenshot(t, takeScreenshot, 'dragging_grouped_column_to_same_position.png', { element: dataGrid.element }); - await t - .expect(compareResults.isValid()) - .ok(compareResults.errorMessages()); -}).before(async () => { - await MouseUpEvents.disable(MouseAction.dragToOffset); - - return createWidget('dxDataGrid', { - width: 800, - dataSource: [ - { - field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', - }, - ], - groupPanel: { - visible: true, - }, - columns: [ - { - dataField: 'field1', - width: 200, - groupIndex: 0, - }, { - dataField: 'field2', - width: 200, - }, { - dataField: 'field3', - width: 200, - }, { - dataField: 'field4', - width: 200, - }, - ], - allowColumnReordering: false, - }); -}).after(async () => { - await MouseUpEvents.enable(MouseAction.dragToOffset); -}); diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/column-separator-with-expand-columns (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/etalons/column-separator-with-expand-columns (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/column-separator-with-expand-columns (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/etalons/column-separator-with-expand-columns (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/dragging_grouped_column_to_same_position (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/etalons/dragging_grouped_column_to_same_position (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/dragging_grouped_column_to_same_position (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/etalons/dragging_grouped_column_to_same_position (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/etalons/headerRow-highlight-on-drag (fluent.blue.light).png b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/etalons/headerRow-highlight-on-drag (fluent.blue.light).png similarity index 100% rename from e2e/testcafe-devextreme/tests/dataGrid/common/etalons/headerRow-highlight-on-drag (fluent.blue.light).png rename to e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/etalons/headerRow-highlight-on-drag (fluent.blue.light).png diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/functional.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/functional.ts new file mode 100644 index 000000000000..4f40b2a65202 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/functional.ts @@ -0,0 +1,412 @@ +import { ClientFunction } from 'testcafe'; +import DataGrid from 'devextreme-testcafe-models/dataGrid'; +import { ClassNames } from 'devextreme-testcafe-models/dataGrid/classNames'; +import url from '../../../../helpers/getPageUrl'; +import { createWidget } from '../../../../helpers/createWidget'; + +const CLASS = ClassNames; + +const getVisibleColumns = (dataGrid: DataGrid): Promise => { + const { getInstance } = dataGrid; + + return ClientFunction( + () => (getInstance() as any) + .getVisibleColumns() + .map((column: any) => column.dataField || column.name), + { dependencies: { getInstance } }, + )(); +}; +const getColumnsSeparatorOffset = ClientFunction(() => $(`.${CLASS.columnsSeparator}`).offset(), { dependencies: { CLASS } }); + +fixture.disablePageReloads`Column reordering` + .page(url(__dirname, '../../../container.html')); + +// T975549 +test('The column reordering should work correctly when there is a fixed column with zero width', async (t) => { + const dataGrid = new DataGrid('#container'); + const headers = dataGrid.getHeaders(); + const headerRow = headers.getHeaderRow(0); + + await t + .expect(headerRow.getHeaderCell(2).element.textContent) + .eql('Field 2') + .drag(headerRow.getHeaderCell(3).element, -400, 0) + .expect(headerRow.getHeaderCell(2).element.textContent) + .eql('Field 3') + .expect(getVisibleColumns(dataGrid)) + .eql(['field1', 'fake', 'field3', 'field2', 'field4']); +}).before(async () => createWidget('dxDataGrid', { + width: 800, + dataSource: [ + { + field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', + }, + ], + columnFixing: { + // @ts-expect-error private option + legacyMode: true, + }, + columns: [ + { + dataField: 'field1', + fixed: true, + width: 200, + }, { + name: 'fake', + fixed: true, + width: 0.01, + }, { + dataField: 'field2', + width: 200, + }, { + dataField: 'field3', + width: 200, + }, { + dataField: 'field4', + width: 200, + }, + ], + allowColumnReordering: true, +})); + +// T1038094 +test('The separator should display correctly when dragging column', async (t) => { + const dataGrid = new DataGrid('#container'); + + await dataGrid.moveHeader(0, 200, 5, true); + + await t + .expect(getColumnsSeparatorOffset()) + .eql({ + left: 8, + top: 8, + }); + + await dataGrid.moveHeader(0, 400, 5); + + const offset2 = await getColumnsSeparatorOffset(); + await t + .expect(offset2!.left).within(405, 406.5) + .expect(offset2!.top).eql(8); + + await dataGrid.moveHeader(0, 600, 5); + + const offset3 = await getColumnsSeparatorOffset(); + + await t + .expect(offset3!.left).within(605, 606.5) + .expect(offset3!.top).eql(8); + + await dataGrid.moveHeader(0, 800, 5); + + await t + .expect(getColumnsSeparatorOffset()) + .eql({ + left: 805, + top: 8, + }); +}).before(async () => createWidget('dxDataGrid', { + width: 800, + dataSource: [ + { + field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', + }, + ], + columns: [ + { + dataField: 'field1', + width: 200, + }, { + dataField: 'field2', + width: 200, + }, { + dataField: 'field3', + width: 200, + }, { + dataField: 'field4', + width: 200, + }, + ], + allowColumnReordering: true, + allowColumnResizing: true, +})); + +test('Column without allowReordering should have same position after dragging to groupPanel and back', async (t) => { + const dataGrid = new DataGrid('#container'); + + await t.expect(dataGrid.isReady()).ok(); + + await t.drag(dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(2).element, -100, -50); + + await t.expect(dataGrid.getGroupPanel().getHeadersCount()).eql(1); + + await t.drag(dataGrid.getGroupPanel().getHeader(0).element, 0, 50); + + const headers = await Promise.all([0, 1, 2, 3].map( + (i) => dataGrid.getHeaders().getHeaderRow(0).getHeaderCell(i).element.textContent, + )); + + await t.expect(headers).eql(['Field 1', 'Field 2', 'Field 3', 'Field 4']); +}).before(async () => createWidget('dxDataGrid', { + width: 800, + dataSource: [ + { + field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', + }, + ], + groupPanel: { + visible: true, + }, + columns: [ + { + dataField: 'field1', + width: 200, + }, { + dataField: 'field2', + width: 200, + }, { + dataField: 'field3', + width: 200, + }, { + dataField: 'field4', + width: 200, + }, + ], + allowColumnReordering: false, +})); + +// T1316881 +test('Column reordering should work correctly with fixed columns on the right and columnRenderingMode is virtual', async (t) => { + // arrange + const dataGrid = new DataGrid('#container'); + const headers = dataGrid.getHeaders(); + const headerRow = headers.getHeaderRow(0); + + await t.expect(dataGrid.isReady()).ok(); + + const lastHeader = headerRow.getDataHeaderCells().nth(11); + + // assert + await t + .expect(lastHeader.textContent) + .eql('19'); + + // act + await t.drag(lastHeader, -200, 0); + + // assert + await t + .expect(headerRow.getDataHeaderCells().nth(11).textContent) + .eql('18'); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [{}], + width: 800, + allowColumnReordering: true, + columnWidth: 100, + scrolling: { + columnRenderingMode: 'virtual', + }, + columns: [ + { dataField: '1' }, + { dataField: '2' }, + { dataField: '3' }, + { dataField: '4' }, + { dataField: '5' }, + { dataField: '6' }, + { dataField: '7' }, + { dataField: '8' }, + { dataField: '9' }, + { dataField: '10' }, + { dataField: '11' }, + { dataField: '12' }, + { dataField: '13' }, + { dataField: '14' }, + { dataField: '15' }, + { dataField: '16' }, + { dataField: '17' }, + { dataField: '18', fixed: true, fixedPosition: 'right' }, + { dataField: '19', fixed: true, fixedPosition: 'right' }, + ], +})); + +// T1316881 +test('Column reordering should work correctly after scrolling right with fixed columns on the left and columnRenderingMode is virtual', async (t) => { + // arrange + const dataGrid = new DataGrid('#container'); + const headers = dataGrid.getHeaders(); + const headerRow = headers.getHeaderRow(0); + + await t.expect(dataGrid.isReady()).ok(); + + // act + await dataGrid.scrollTo(t, { x: 10000 }); + + // assert + await t + .expect(dataGrid.getScrollLeft()) + .eql(1100) + .expect(headerRow.getHeaderCell(16).element.exists) // last non-fixed column + .ok() + .expect(headerRow.getDataHeaderCells().nth(0).textContent) + .eql('1'); + + // act + await t.drag(headerRow.getDataHeaderCells().nth(1), -200, 0); + + // assert + await t + .expect(headerRow.getDataHeaderCells().nth(0).textContent) + .eql('2'); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [{}], + width: 800, + allowColumnReordering: true, + columnWidth: 100, + scrolling: { + columnRenderingMode: 'virtual', + }, + columns: [ + { dataField: '1', fixed: true, fixedPosition: 'left' }, + { dataField: '2', fixed: true, fixedPosition: 'left' }, + { dataField: '3' }, + { dataField: '4' }, + { dataField: '5' }, + { dataField: '6' }, + { dataField: '7' }, + { dataField: '8' }, + { dataField: '9' }, + { dataField: '10' }, + { dataField: '11' }, + { dataField: '12' }, + { dataField: '13' }, + { dataField: '14' }, + { dataField: '15' }, + { dataField: '16' }, + { dataField: '17' }, + { dataField: '18' }, + { dataField: '19' }, + ], +})); + +// T1316881 +test('Dragging a fixed column to a group panel should work correctly when columnRenderingMode is virtual', async (t) => { + // arrange + const dataGrid = new DataGrid('#container'); + const headers = dataGrid.getHeaders(); + const headerRow = headers.getHeaderRow(0); + + await t.expect(dataGrid.isReady()).ok(); + + const fixedHeader = headerRow.getDataHeaderCells().nth(10); + + // assert + await t + .expect(fixedHeader.textContent) + .eql('18'); + + // act + await t.drag(fixedHeader, -600, -50); + + // assert + await t + .expect(dataGrid.getGroupPanel().getHeader(0).element.textContent) + .eql('18'); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [{}], + width: 800, + allowColumnReordering: true, + columnWidth: 100, + scrolling: { + columnRenderingMode: 'virtual', + }, + groupPanel: { + visible: true, + }, + columns: [ + { dataField: '1' }, + { dataField: '2' }, + { dataField: '3' }, + { dataField: '4' }, + { dataField: '5' }, + { dataField: '6' }, + { dataField: '7' }, + { dataField: '8' }, + { dataField: '9' }, + { dataField: '10' }, + { dataField: '11' }, + { dataField: '12' }, + { dataField: '13' }, + { dataField: '14' }, + { dataField: '15' }, + { dataField: '16' }, + { dataField: '17' }, + { dataField: '18', fixed: true, fixedPosition: 'right' }, + { dataField: '19', fixed: true, fixedPosition: 'right' }, + ], +})); + +// T1316881 +test('Dragging a fixed column to a column chooser should work correctly when columnRenderingMode is virtual', async (t) => { + // arrange + const dataGrid = new DataGrid('#container'); + const headers = dataGrid.getHeaders(); + const headerRow = headers.getHeaderRow(0); + + await t.expect(dataGrid.isReady()).ok(); + + // act - open column chooser + await t.click(dataGrid.getColumnChooserButton()); + + // assert + await t + .expect(dataGrid.getColumnChooser().isOpened) + .ok(); + + const fixedHeader = headerRow.getDataHeaderCells().nth(10); + + // assert + await t + .expect(fixedHeader.textContent) + .eql('18'); + + // act + await t.drag(fixedHeader, 20, 300); + + // assert + await t + .expect(await dataGrid.getColumnChooser().getColumnTexts()) + .eql(['18']); +}).before(async () => createWidget('dxDataGrid', { + dataSource: [{}], + width: 800, + height: 500, + allowColumnReordering: true, + columnWidth: 100, + scrolling: { + columnRenderingMode: 'virtual', + }, + columnChooser: { + enabled: true, + }, + columns: [ + { dataField: '1' }, + { dataField: '2' }, + { dataField: '3' }, + { dataField: '4' }, + { dataField: '5' }, + { dataField: '6' }, + { dataField: '7' }, + { dataField: '8' }, + { dataField: '9' }, + { dataField: '10' }, + { dataField: '11' }, + { dataField: '12' }, + { dataField: '13' }, + { dataField: '14' }, + { dataField: '15' }, + { dataField: '16' }, + { dataField: '17' }, + { dataField: '18', fixed: true, fixedPosition: 'right' }, + { dataField: '19', fixed: true, fixedPosition: 'right' }, + ], +})); diff --git a/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/visual.ts b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/visual.ts new file mode 100644 index 000000000000..301b6c4ce312 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/dataGrid/common/columnReordering/visual.ts @@ -0,0 +1,138 @@ +import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; +import DataGrid from 'devextreme-testcafe-models/dataGrid'; +import url from '../../../../helpers/getPageUrl'; +import { createWidget } from '../../../../helpers/createWidget'; +import { MouseAction, MouseUpEvents } from '../../../../helpers/mouseUpEvents'; +import { testScreenshot } from '../../../../helpers/themeUtils'; + +fixture.disablePageReloads`Column reordering.Visual` + .page(url(__dirname, '../../../container.html')); + +test.meta({ unstable: true })('column separator should work properly with expand columns', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid('#container'); + await MouseUpEvents.disable(MouseAction.dragToOffset); + + await t.drag(dataGrid.getGroupPanel().getHeader(0).element, 0, 30); + await testScreenshot(t, takeScreenshot, 'column-separator-with-expand-columns.png'); + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); + + await MouseUpEvents.enable(MouseAction.dragToOffset); +}).before(async () => createWidget('dxDataGrid', { + width: 800, + dataSource: [ + { + field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', + }, + ], + groupPanel: { + visible: true, + }, + columns: [ + { + dataField: 'field1', + width: 200, + groupIndex: 0, + }, { + dataField: 'field2', + width: 200, + groupIndex: 1, + }, { + dataField: 'field3', + width: 200, + }, { + dataField: 'field4', + width: 200, + }, + ], + allowColumnReordering: true, +})); + +test('HeaderRow should be highlighted when dragging column with allowColumnReordering=false', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const dataGrid = new DataGrid('#container'); + await MouseUpEvents.disable(MouseAction.dragToOffset); + + await t.drag(dataGrid.getGroupPanel().getHeader(0).element, 0, 30); + await testScreenshot(t, takeScreenshot, 'headerRow-highlight-on-drag.png'); + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); + + await MouseUpEvents.enable(MouseAction.dragToOffset); +}).before(async () => createWidget('dxDataGrid', { + width: 800, + dataSource: [ + { + field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', + }, + ], + groupPanel: { + visible: true, + }, + columns: [ + { + dataField: 'field1', + width: 200, + groupIndex: 0, + }, { + dataField: 'field2', + width: 200, + groupIndex: 1, + }, { + dataField: 'field3', + width: 200, + }, { + dataField: 'field4', + width: 200, + }, + ], + allowColumnReordering: false, +})); + +test('The group separator should not appear when dragging a grouped column to the same position', async (t) => { + const dataGrid = new DataGrid('#container'); + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + + await t.drag(dataGrid.getGroupPanel().getHeader(0).element, -25, 20); + + await testScreenshot(t, takeScreenshot, 'dragging_grouped_column_to_same_position.png', { element: dataGrid.element }); + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + await MouseUpEvents.disable(MouseAction.dragToOffset); + + return createWidget('dxDataGrid', { + width: 800, + dataSource: [ + { + field1: 'test1', field2: 'test2', field3: 'test3', field4: 'test4', + }, + ], + groupPanel: { + visible: true, + }, + columns: [ + { + dataField: 'field1', + width: 200, + groupIndex: 0, + }, { + dataField: 'field2', + width: 200, + }, { + dataField: 'field3', + width: 200, + }, { + dataField: 'field4', + width: 200, + }, + ], + allowColumnReordering: false, + }); +}).after(async () => { + await MouseUpEvents.enable(MouseAction.dragToOffset); +}); diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_controller/const.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/const.ts index df4795ff788f..f7c24e8b9aa2 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_controller/const.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/const.ts @@ -5,6 +5,7 @@ export const IGNORE_COLUMN_OPTION_NAMES = { visibleWidth: true, bestFitWidth: tr export const COMMAND_EXPAND_CLASS = 'dx-command-expand'; export const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991/* IE11 */; export const GROUP_COMMAND_COLUMN_NAME = 'groupExpand'; +export const VIRTUAL_COMMAND_COLUMN_NAME = 'virtual'; export const DETAIL_COMMAND_COLUMN_NAME = 'detailExpand'; export const COLUMN_OPTION_REGEXP = /columns\[(\d+)\]\.?/gi; @@ -27,6 +28,7 @@ export const COLUMN_INDEX_OPTIONS = { }; export const GROUP_LOCATION = 'group'; export const COLUMN_CHOOSER_LOCATION = 'columnChooser'; +export const HEADERS_LOCATION = 'headers'; export const UNSUPPORTED_PROPERTIES_FOR_CHILD_COLUMNS = [ 'fixed', diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller_utils.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller_utils.ts index 4d9c097a4f63..1f0267472113 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller_utils.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/m_columns_controller_utils.ts @@ -30,8 +30,10 @@ import { UNSUPPORTED_PROPERTIES_FOR_CHILD_COLUMNS, USER_STATE_FIELD_NAMES, USER_STATE_FIELD_NAMES_15_1, + VIRTUAL_COMMAND_COLUMN_NAME, } from './const'; import type { Column, ColumnsController } from './m_columns_controller'; +import type { ColumnIndex, DropLocationNames } from './types'; const warnFixedInChildColumnsOnce = (controller: ColumnsController, childColumns: any[]): void => { if (controller?._isWarnedAboutUnsupportedProperties) return; @@ -414,22 +416,60 @@ export const updateColumnVisibleIndexes = function (that: ColumnsController, cur normalizeIndexes(result, 'visibleIndex', currentColumn); }; -export const getColumnIndexByVisibleIndex = function (that: ColumnsController, visibleIndex, location) { - // @ts-expect-error +function getColumnsByLocation( + that: ColumnsController, + location: DropLocationNames, + rowIndex: number | null, +): Column[] { + switch (location) { + case GROUP_LOCATION: + return that.getGroupColumns(); + case COLUMN_CHOOSER_LOCATION: + return that.getChooserColumns(); + default: + return that.getVisibleColumns(rowIndex); + } +} + +function correctVisibleIndex( + that: ColumnsController, + visibleIndex: ColumnIndex, +): number { + return isObject(visibleIndex) ? visibleIndex.columnIndex : visibleIndex; +} + +function getColumnByVisibleIndex( + that: ColumnsController, + visibleIndex: ColumnIndex, + location: DropLocationNames, +): Column { const rowIndex = isObject(visibleIndex) ? visibleIndex.rowIndex : null; - const columns = location === GROUP_LOCATION ? that.getGroupColumns() : location === COLUMN_CHOOSER_LOCATION ? that.getChooserColumns() : that.getVisibleColumns(rowIndex, true); - let column; + const columns = getColumnsByLocation(that, location, rowIndex); + const correctedVisibleIndex = correctVisibleIndex(that, visibleIndex); + const column = columns[correctedVisibleIndex]; - // @ts-expect-error - visibleIndex = isObject(visibleIndex) ? visibleIndex.columnIndex : visibleIndex; - column = columns[visibleIndex]; + if (column?.type === GROUP_COMMAND_COLUMN_NAME) { + return that._columns.filter((col) => column.type === col.type)[0] || column; + } - if (column && column.type === GROUP_COMMAND_COLUMN_NAME) { - column = that._columns.filter((col) => column.type === col.type)[0] || column; + if (that.isVirtualMode() && (!column || column.command === VIRTUAL_COMMAND_COLUMN_NAME)) { + const columnIndexOffset = that.getColumnIndexOffset(); + + return that.getVisibleColumns(rowIndex, true)[correctedVisibleIndex + columnIndexOffset]; } - return column && isDefined(column.index) ? column.index : -1; -}; + return column; +} + +export function getColumnIndexByVisibleIndex( + that: ColumnsController, + visibleIndex: ColumnIndex, + location: DropLocationNames, +): number { + const column = getColumnByVisibleIndex(that, visibleIndex, location); + + return column?.index ?? -1; +} export const moveColumnToGroup = function (that: ColumnsController, column, groupIndex) { const groupColumns = that.getGroupColumns(); diff --git a/packages/devextreme/js/__internal/grids/grid_core/columns_controller/types.ts b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/types.ts new file mode 100644 index 000000000000..90dd5a1e741e --- /dev/null +++ b/packages/devextreme/js/__internal/grids/grid_core/columns_controller/types.ts @@ -0,0 +1,14 @@ +import type { + COLUMN_CHOOSER_LOCATION, + GROUP_LOCATION, + HEADERS_LOCATION, +} from './const'; + +export type DropLocationNames = typeof GROUP_LOCATION + | typeof COLUMN_CHOOSER_LOCATION + | typeof HEADERS_LOCATION; + +export type ColumnIndex = number | { + rowIndex: number; + columnIndex: number; +}; 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 c3ac7b77cabe..965791dbd8b5 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 @@ -63,11 +63,6 @@ const allowReordering = function (that) { return that.option('allowColumnReordering') || that.getController('columns').isColumnOptionUsed('allowReordering'); }; -type ColumnIndex = number | { - rowIndex: number; - columnIndex: number; -}; - export class TrackerView extends modules.View { private _positionChanged: any; @@ -1582,8 +1577,8 @@ export class DraggingHeaderViewController extends modules.ViewController { private allowDrop(parameters) { return this._columnsController.allowMoveColumn( - this.addColumnIndexOffset(parameters.sourceColumnIndex), - this.addColumnIndexOffset(parameters.targetColumnIndex), + parameters.sourceColumnIndex, + parameters.targetColumnIndex, parameters.sourceLocation, parameters.targetLocation, ); @@ -1643,19 +1638,6 @@ export class DraggingHeaderViewController extends modules.ViewController { } } - private addColumnIndexOffset(columnIndex: ColumnIndex): ColumnIndex { - const offset = this._columnsController.getColumnIndexOffset(); - - if (isObject(columnIndex)) { - return { - ...columnIndex, - columnIndex: columnIndex.columnIndex + offset, - }; - } - - return columnIndex + offset; - } - private drop(parameters) { const { sourceColumnElement } = parameters; @@ -1673,8 +1655,8 @@ export class DraggingHeaderViewController extends modules.ViewController { } this._columnsController.moveColumn( - this.addColumnIndexOffset(parameters.sourceColumnIndex), - this.addColumnIndexOffset(parameters.targetColumnIndex), + parameters.sourceColumnIndex, + parameters.targetColumnIndex, parameters.sourceLocation, parameters.targetLocation, ); diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_column_keyboard_navigation_core.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_column_keyboard_navigation_core.ts index 63635ebebc18..4de2724c236e 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_column_keyboard_navigation_core.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_column_keyboard_navigation_core.ts @@ -1,5 +1,6 @@ import { isDefined, isEmptyObject } from '@js/core/utils/type'; +import type { Column } from '../columns_controller/m_columns_controller'; import { Direction } from './const'; import type { ColumnFocusDispatcher } from './m_column_focus_dispatcher'; import { KeyboardNavigationController as KeyboardNavigationControllerCore } from './m_keyboard_navigation_core'; @@ -12,13 +13,10 @@ export class ColumnKeyboardNavigationController extends KeyboardNavigationContro } protected getVisibleIndex( - column, + column: Column, rowIndex?: number, ): number { - const visibleIndex = this._columnsController.getVisibleIndex(column.index, rowIndex); - const columnIndexOffset = this.getColumnIndexOffset(visibleIndex); - - return visibleIndex >= 0 ? visibleIndex + columnIndexOffset : -1; + return this._columnsController.getVisibleIndex(column.index, rowIndex); } protected getNewVisibleIndex( diff --git a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts index 2cd7171ea677..0ff0e50ef9c7 100644 --- a/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts +++ b/packages/devextreme/js/__internal/grids/grid_core/keyboard_navigation/m_headers_keyboard_navigation.ts @@ -38,6 +38,16 @@ export class HeadersKeyboardNavigationController extends ColumnKeyboardNavigatio } } + private correctFocusedColumnIndexAfterScroll(columnIndexOffset: number): void { + if (isDefined(this._focusedCellPosition?.columnIndex)) { + const columnIndexOffsetDiff = this._columnsController.getColumnIndexOffset() - columnIndexOffset; + + this.setFocusedColumnIndex( + this._focusedCellPosition.columnIndex - columnIndexOffsetDiff, + ); + } + } + protected getColumnVisibleIndexCorrection( // eslint-disable-next-line @typescript-eslint/no-unused-vars visibleColumnIndex: number, @@ -122,15 +132,7 @@ export class HeadersKeyboardNavigationController extends ColumnKeyboardNavigatio } protected _getCell(cellPosition): dxElementWrapper { - const columnIndexOffset = this.getColumnIndexOffset(cellPosition.columnIndex); - const columnIndex = cellPosition.columnIndex >= 0 - ? cellPosition.columnIndex - columnIndexOffset - : -1; - - return this._columnHeadersView?.getCell({ - rowIndex: cellPosition.rowIndex, - columnIndex, - }); + return this._columnHeadersView?.getCell(cellPosition); } protected getFocusedView(): any { @@ -217,7 +219,11 @@ export class HeadersKeyboardNavigationController extends ColumnKeyboardNavigatio ); if (focusedCellIsOutsideVisibleArea) { + const columnIndexOffset = this._columnsController.getColumnIndexOffset(); + + this.needToRestoreFocus = false; this.scrollToNextCell($focusedCell).then(() => { + this.correctFocusedColumnIndexAfterScroll(columnIndexOffset); super.restoreFocus(); }); return;