Skip to content

Commit b93ea8d

Browse files
committed
feat: drag order undo redo
1 parent 380c718 commit b93ea8d

File tree

6 files changed

+189
-1
lines changed

6 files changed

+189
-1
lines changed

packages/vtable-sheet/examples/sheet/history.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@ export function createTable() {
8383
firstRowAsHeader: true,
8484
active: true
8585
}
86-
]
86+
],
87+
/** 拖拽列顺序和行顺序配置 如果sheets中单独配置过,这个配置会被忽略*/
88+
dragOrder: {
89+
enableDragColumnOrder: true,
90+
enableDragRowOrder: true
91+
}
8792
};
8893

8994
const sheet = new VTableSheet(container, options);

packages/vtable/__tests__/columns/listTable-dragHeader.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,33 @@ describe('listTable-cellType-function init test', () => {
9898
{ field: 'city', title: 'city' }
9999
]);
100100
});
101+
test('listTable changeHeaderPosition moves columns', () => {
102+
const containerDom2: HTMLElement = createDiv();
103+
containerDom2.style.position = 'relative';
104+
containerDom2.style.width = '1000px';
105+
containerDom2.style.height = '800px';
106+
const records2 = [
107+
{ a: 1, b: 2, c: 3 },
108+
{ a: 4, b: 5, c: 6 }
109+
];
110+
const columns2 = [
111+
{ field: 'a', title: 'A' },
112+
{ field: 'b', title: 'B' },
113+
{ field: 'c', title: 'C' }
114+
];
115+
const listTable2 = new ListTable(containerDom2, { records: records2, columns: columns2, dragHeaderMode: 'all' });
116+
listTable2.changeHeaderPosition({
117+
source: { col: 1, row: 0 },
118+
target: { col: 2, row: 0 },
119+
movingColumnOrRow: 'column'
120+
});
121+
expect(listTable2.columns).toEqual([
122+
{ field: 'a', title: 'A' },
123+
{ field: 'c', title: 'C' },
124+
{ field: 'b', title: 'B' }
125+
]);
126+
listTable2.release();
127+
});
101128
test('listTable dragHeader interaction', () => {
102129
option.transpose = true;
103130
listTable.updateOption(option);

packages/vtable/__tests__/data-update/listTable-pagination-dragOrder.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,37 @@ describe('listTable-pagination-dragOrder test', () => {
141141
listTable.release();
142142
});
143143

144+
test('dragOrder should be blocked when sorted', () => {
145+
const records = generateRecords(10);
146+
147+
const option: VTable.ListTableConstructorOptions = {
148+
records,
149+
columns: [
150+
{ field: 'Order ID', title: 'Order ID', width: 'auto' },
151+
{ field: 'Customer ID', title: 'Customer ID', width: 'auto' }
152+
],
153+
widthMode: 'standard',
154+
rowSeriesNumber: {
155+
dragOrder: true,
156+
title: '序号',
157+
width: 'auto'
158+
}
159+
};
160+
161+
const listTable = new ListTable(containerDom, option);
162+
listTable.updateSortState({ field: 'Order ID', order: 'asc' } as any, true);
163+
164+
const before = listTable.getRecordByCell(1, 1)?.['Order ID'];
165+
listTable.stateManager.startMoveCol(0, 1, 10, 10, null, 'row');
166+
listTable.stateManager.updateMoveCol(0, 3, 10, 30, null);
167+
const ok = listTable.stateManager.endMoveCol();
168+
const after = listTable.getRecordByCell(1, 1)?.['Order ID'];
169+
170+
expect(ok).toBe(false);
171+
expect(after).toBe(before);
172+
listTable.release();
173+
});
174+
144175
test('dragOrder with pagination - multiple page changes and drag operations', () => {
145176
const records = generateRecords(15);
146177

packages/vtable/src/core/BaseTable.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3396,6 +3396,122 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI {
33963396
this.stateManager.select.selecting = false;
33973397
}
33983398

3399+
changeHeaderPosition(args: {
3400+
source: CellAddress;
3401+
target: CellAddress;
3402+
movingColumnOrRow?: 'column' | 'row';
3403+
}): boolean {
3404+
if (
3405+
!('canMoveHeaderPosition' in this.internalProps.layoutMap) ||
3406+
this.options.customConfig?.notUpdateInColumnRowMove === true
3407+
) {
3408+
return false;
3409+
}
3410+
const prevMoving = this.stateManager.columnMove.movingColumnOrRow;
3411+
this.stateManager.columnMove.movingColumnOrRow = args.movingColumnOrRow;
3412+
try {
3413+
if (this.internalProps.layoutMap.canMoveHeaderPosition?.(args.source, args.target) === false) {
3414+
return false;
3415+
}
3416+
const oldSourceMergeInfo = this.getCellRange(args.source.col, args.source.row);
3417+
const oldTargetMergeInfo = this.getCellRange(args.target.col, args.target.row);
3418+
const moveContext = this._moveHeaderPosition(args.source, args.target);
3419+
if (!moveContext || moveContext.targetIndex === moveContext.sourceIndex) {
3420+
return false;
3421+
}
3422+
this.internalProps.useOneRowHeightFillAll = false;
3423+
this.internalProps.layoutMap.clearCellRangeMap();
3424+
const sourceMergeInfo = this.getCellRange(args.source.col, args.source.row);
3425+
const targetMergeInfo = this.getCellRange(args.target.col, args.target.row);
3426+
3427+
const colMin = Math.min(
3428+
sourceMergeInfo.start.col,
3429+
targetMergeInfo.start.col,
3430+
oldSourceMergeInfo.start.col,
3431+
oldTargetMergeInfo.start.col
3432+
);
3433+
const colMax = Math.max(
3434+
sourceMergeInfo.end.col,
3435+
targetMergeInfo.end.col,
3436+
oldSourceMergeInfo.end.col,
3437+
oldTargetMergeInfo.end.col
3438+
);
3439+
const rowMin = Math.min(
3440+
sourceMergeInfo.start.row,
3441+
targetMergeInfo.start.row,
3442+
oldSourceMergeInfo.start.row,
3443+
oldTargetMergeInfo.start.row
3444+
);
3445+
let rowMax = Math.max(
3446+
sourceMergeInfo.end.row,
3447+
targetMergeInfo.end.row,
3448+
oldSourceMergeInfo.end.row,
3449+
oldTargetMergeInfo.end.row
3450+
);
3451+
if (
3452+
moveContext.moveType === 'row' &&
3453+
(this.internalProps.layoutMap as PivotHeaderLayoutMap).rowHierarchyType === 'tree'
3454+
) {
3455+
if (moveContext.targetIndex > moveContext.sourceIndex) {
3456+
rowMax = rowMax + moveContext.targetSize - 1;
3457+
} else {
3458+
rowMax = rowMax + moveContext.sourceSize - 1;
3459+
}
3460+
}
3461+
3462+
if (
3463+
!(this as any).transpose &&
3464+
(this.isSeriesNumberInBody(args.source.col, args.source.row) || args.movingColumnOrRow === 'row')
3465+
) {
3466+
this.changeRecordOrder(moveContext.sourceIndex, moveContext.targetIndex);
3467+
this.stateManager.changeCheckboxAndRadioOrder(moveContext.sourceIndex, moveContext.targetIndex);
3468+
}
3469+
3470+
if (moveContext.moveType === 'column') {
3471+
for (let col = colMin; col <= colMax; col++) {
3472+
this._clearColRangeWidthsMap(col);
3473+
}
3474+
} else {
3475+
for (let row = rowMin; row <= rowMax; row++) {
3476+
this._clearRowRangeHeightsMap(row);
3477+
}
3478+
}
3479+
3480+
this.clearCellStyleCache();
3481+
if (this.isSeriesNumberInBody(args.source.col, args.source.row) || args.movingColumnOrRow === 'row') {
3482+
this.scenegraph.updateHeaderPosition(
3483+
this.scenegraph.proxy.colStart,
3484+
this.scenegraph.proxy.colEnd,
3485+
this.scenegraph.proxy.rowStart,
3486+
this.scenegraph.proxy.rowEnd,
3487+
moveContext.moveType
3488+
);
3489+
} else if (moveContext.moveType === 'column') {
3490+
this.scenegraph.updateHeaderPosition(colMin, colMax, 0, -1, moveContext.moveType);
3491+
} else {
3492+
this.scenegraph.updateHeaderPosition(0, -1, rowMin, rowMax, moveContext.moveType);
3493+
}
3494+
3495+
if (this.internalProps.frozenColDragHeaderMode === 'adjustFrozenCount' && this.isListTable()) {
3496+
if (this.isLeftFrozenColumn(args.target.col) && !this.isLeftFrozenColumn(args.source.col)) {
3497+
this.frozenColCount += sourceMergeInfo.end.col - sourceMergeInfo.start.col + 1;
3498+
} else if (this.isLeftFrozenColumn(args.source.col) && !this.isLeftFrozenColumn(args.target.col)) {
3499+
this.frozenColCount -= sourceMergeInfo.end.col - sourceMergeInfo.start.col + 1;
3500+
}
3501+
if (this.isRightFrozenColumn(args.target.col) && !this.isRightFrozenColumn(args.source.col)) {
3502+
this.rightFrozenColCount += sourceMergeInfo.end.col - sourceMergeInfo.start.col + 1;
3503+
} else if (this.isRightFrozenColumn(args.source.col) && !this.isRightFrozenColumn(args.target.col)) {
3504+
this.rightFrozenColCount -= sourceMergeInfo.end.col - sourceMergeInfo.start.col + 1;
3505+
}
3506+
}
3507+
3508+
this.scenegraph.updateNextFrame?.();
3509+
return true;
3510+
} finally {
3511+
this.stateManager.columnMove.movingColumnOrRow = prevMoving;
3512+
}
3513+
}
3514+
33993515
abstract isListTable(): boolean;
34003516
abstract isPivotTable(): boolean;
34013517
abstract isPivotChart(): boolean;

packages/vtable/src/data/DataSource.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,10 @@ export class DataSource extends EventTarget implements DataSourceAPI {
16811681
return this.dataSourceObj.canChangeOrder(sourceIndex, targetIndex);
16821682
}
16831683

1684+
if (this.lastSortStates?.some(state => state.order === 'asc' || state.order === 'desc')) {
1685+
return false;
1686+
}
1687+
16841688
if (this.hasHierarchyStateExpand) {
16851689
let sourceIndexs = this.currentPagerIndexedData[sourceIndex] as number[];
16861690
let targetIndexs = this.currentPagerIndexedData[targetIndex] as number[];

packages/vtable/src/ts-types/base-table.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,11 @@ export interface BaseTableAPI {
951951
getHierarchyState: (col: number, row: number) => HierarchyState | null;
952952

953953
_canDragHeaderPosition: (col: number, row: number) => boolean;
954+
changeHeaderPosition: (args: {
955+
source: CellAddress;
956+
target: CellAddress;
957+
movingColumnOrRow?: 'column' | 'row';
958+
}) => boolean;
954959

955960
isHeader: (col: number, row: number) => boolean;
956961

0 commit comments

Comments
 (0)