Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undo will work for moving columns #10746

Merged
merged 8 commits into from
Jan 31, 2024
8 changes: 8 additions & 0 deletions .changelogs/10746.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"issuesOrigin": "private",
"title": "Undo will work for moving columns",
"type": "added",
"issueOrPR": 10746,
"breaking": false,
"framework": "none"
}
Original file line number Diff line number Diff line change
Expand Up @@ -1349,4 +1349,134 @@ describe('manualColumnMove', () => {
});
});
});

describe('undoRedo', () => {
describe('should back changes', () => {
it('when moving single row from the left to the right', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumn(1, 4);
hot.render();

hot.undo();

expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']);
});

it('when moving multiple columns from the left to the right', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumns([0, 1], 4);
hot.render();

hot.undo();

expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']);
});

it('when moving multiple columns from the right to the left', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumns([4, 5], 1);
hot.render();

hot.undo();

expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']);
});

it('when moving multiple columns with mixed indexes', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumns([0, 1, 8, 4, 7], 2);
hot.render();

hot.undo();

expect(hot.getDataAtRow(0)).toEqual(['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'J1']);
});
});

describe('should revert changes', () => {
it('when moving single row from the left to the right', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumn(1, 4);
hot.render();

hot.undo();
hot.redo();

expect(hot.getDataAtRow(0)).toEqual(['A1', 'C1', 'D1', 'E1', 'B1', 'F1', 'G1', 'H1', 'I1', 'J1']);
});

it('when moving multiple columns from the left to the right', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumns([0, 1], 4);
hot.render();

hot.undo();
hot.redo();

expect(hot.getDataAtRow(0)).toEqual(['C1', 'D1', 'E1', 'F1', 'A1', 'B1', 'G1', 'H1', 'I1', 'J1']);
});

it('when moving multiple columns from the right to the left', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumns([4, 5], 1);
hot.render();

hot.undo();
hot.redo();

expect(hot.getDataAtRow(0)).toEqual(['A1', 'E1', 'F1', 'B1', 'C1', 'D1', 'G1', 'H1', 'I1', 'J1']);
});

it('when moving multiple columns with mixed indexes', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
manualColumnMove: true,
});

hot.getPlugin('manualColumnMove').moveColumns([0, 1, 8, 4, 7], 2);
hot.render();

hot.undo();
hot.redo();

expect(hot.getDataAtRow(0)).toEqual(['C1', 'D1', 'A1', 'B1', 'I1', 'E1', 'H1', 'F1', 'G1', 'J1']);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ describe('manualColumnMove', () => {
expect(getSelected()).toEqual([[-1, 1, 9, 3]]);
});

// The `ManualColumnMove` plugin doesn't cooperate with the `UndoRedo` plugin.
describe('should be shown properly after undo action', () => {
xit('when moving multiple columns from the left to the right', () => {
it('when moving multiple columns from the left to the right', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
Expand All @@ -86,10 +85,10 @@ describe('manualColumnMove', () => {

hot.undo();

expect(getSelected()).toEqual([[0, 0, 9, 2]]);
expect(getSelected()).toEqual([[-1, 0, 9, 2]]);
});

xit('when moving multiple columns from the right to the left', () => {
it('when moving multiple columns from the right to the left', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
Expand All @@ -112,12 +111,12 @@ describe('manualColumnMove', () => {

hot.undo();

expect(getSelected()).toEqual([[0, 3, 9, 5]]);
expect(getSelected()).toEqual([[-1, 3, 9, 5]]);
});
});

describe('should be shown properly after redo action', () => {
xit('when moving multiple columns from the left to the right', () => {
it('when moving multiple columns from the left to the right', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
Expand All @@ -141,10 +140,10 @@ describe('manualColumnMove', () => {
hot.undo();
hot.redo();

expect(getSelected()).toEqual([[0, 1, 9, 3]]);
expect(getSelected()).toEqual([[-1, 1, 9, 3]]);
});

xit('when moving multiple columns from the right to the left', () => {
it('when moving multiple columns from the right to the left', () => {
const hot = handsontable({
data: Handsontable.helper.createSpreadsheetData(10, 10),
colHeaders: true,
Expand All @@ -168,7 +167,7 @@ describe('manualColumnMove', () => {
hot.undo();
hot.redo();

expect(getSelected()).toEqual([[0, 1, 9, 3]]);
expect(getSelected()).toEqual([[-1, 1, 9, 3]]);
});
});
});
Expand Down
65 changes: 60 additions & 5 deletions handsontable/src/plugins/undoRedo/undoRedo.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ function UndoRedo(instance) {
plugin.done(() => new UndoRedo.RowMoveAction(rows, finalIndex));
});

instance.addHook('beforeColumnMove', (columns, finalIndex) => {
if (columns === false) {
return;
}

plugin.done(() => new UndoRedo.ColumnMoveAction(columns, finalIndex));
});

instance.addHook('beforeMergeCells', (cellRange, auto) => {
if (auto) {
return;
Expand Down Expand Up @@ -887,16 +895,16 @@ UndoRedo.UnmergeCellsAction = UnmergeCellsAction;
*/
UndoRedo.RowMoveAction = function(rows, finalIndex) {
this.rows = rows.slice();
this.finalIndex = finalIndex;
this.finalRowIndex = finalIndex;
this.actionType = 'row_move';
};
inherit(UndoRedo.RowMoveAction, UndoRedo.Action);

UndoRedo.RowMoveAction.prototype.undo = function(instance, undoneCallback) {
const manualRowMove = instance.getPlugin('manualRowMove');
const copyOfRows = [].concat(this.rows);
const rowsMovedUp = copyOfRows.filter(a => a > this.finalIndex);
const rowsMovedDown = copyOfRows.filter(a => a <= this.finalIndex);
const rowsMovedUp = copyOfRows.filter(a => a > this.finalRowIndex);
const rowsMovedDown = copyOfRows.filter(a => a <= this.finalRowIndex);
const allMovedRows = rowsMovedUp.sort((a, b) => b - a).concat(rowsMovedDown.sort((a, b) => a - b));

instance.addHookOnce('afterViewRender', undoneCallback);
Expand All @@ -918,11 +926,58 @@ UndoRedo.RowMoveAction.prototype.redo = function(instance, redoneCallback) {
const manualRowMove = instance.getPlugin('manualRowMove');

instance.addHookOnce('afterViewRender', redoneCallback);
manualRowMove.moveRows(this.rows.slice(), this.finalIndex);
manualRowMove.moveRows(this.rows.slice(), this.finalRowIndex);
instance.render();

instance.deselectCell();
instance.selectRows(this.finalRowIndex, this.finalRowIndex + this.rows.length - 1);
};

/**
* ManualColumnMove action.
*
* @private
* @param {number[]} columns An array with moved columns.
* @param {number} finalIndex The destination index.
*/
UndoRedo.ColumnMoveAction = function(columns, finalIndex) {
this.columns = columns.slice();
this.finalColumnIndex = finalIndex;
this.actionType = 'col_move';
};
inherit(UndoRedo.ColumnMoveAction, UndoRedo.Action);

UndoRedo.ColumnMoveAction.prototype.undo = function(instance, undoneCallback) {
const manualColumnMove = instance.getPlugin('manualColumnMove');
const copyOfColumns = [].concat(this.columns);
const columnsMovedLeft = copyOfColumns.filter(a => a > this.finalColumnIndex);
const rowsMovedRight = copyOfColumns.filter(a => a <= this.finalColumnIndex);
const allMovedColumns = columnsMovedLeft.sort((a, b) => b - a).concat(rowsMovedRight.sort((a, b) => a - b));

instance.addHookOnce('afterViewRender', undoneCallback);

// Moving columns from those with higher indexes to those with lower indexes when action was performed from right to left
// Moving columns from those with lower indexes to those with higher indexes when action was performed from left to right
for (let i = 0; i < allMovedColumns.length; i += 1) {
const newPhysicalColumn = instance.toVisualColumn(allMovedColumns[i]);

manualColumnMove.moveColumn(newPhysicalColumn, allMovedColumns[i]);
}

instance.render();

instance.deselectCell();
instance.selectColumns(this.columns[0], this.columns[0] + this.columns.length - 1);
};
UndoRedo.ColumnMoveAction.prototype.redo = function(instance, redoneCallback) {
const manualColumnMove = instance.getPlugin('manualColumnMove');

instance.addHookOnce('afterViewRender', redoneCallback);
manualColumnMove.moveColumns(this.columns.slice(), this.finalColumnIndex);
instance.render();

instance.deselectCell();
instance.selectRows(this.finalIndex, this.finalIndex + this.rows.length - 1);
instance.selectColumns(this.finalColumnIndex, this.finalColumnIndex + this.columns.length - 1);
};

/**
Expand Down