@ckeditor/ckeditor5-undo 38.1.0 → 38.1.1
Sign up to get free protection for your applications and to get access to all the features.
- package/package.json +4 -4
- package/src/augmentation.d.ts +16 -16
- package/src/augmentation.js +5 -5
- package/src/basecommand.d.ts +72 -72
- package/src/basecommand.js +192 -192
- package/src/index.d.ts +13 -13
- package/src/index.js +11 -11
- package/src/redocommand.d.ts +27 -27
- package/src/redocommand.js +40 -40
- package/src/undo.d.ts +117 -117
- package/src/undo.js +121 -121
- package/src/undocommand.d.ts +37 -37
- package/src/undocommand.js +41 -41
- package/src/undoediting.d.ts +37 -37
- package/src/undoediting.js +82 -82
- package/src/undoui.d.ts +30 -30
- package/src/undoui.js +61 -61
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ckeditor/ckeditor5-undo",
|
3
|
-
"version": "38.1.
|
3
|
+
"version": "38.1.1",
|
4
4
|
"description": "Undo feature for CKEditor 5.",
|
5
5
|
"keywords": [
|
6
6
|
"ckeditor",
|
@@ -12,9 +12,9 @@
|
|
12
12
|
],
|
13
13
|
"main": "src/index.js",
|
14
14
|
"dependencies": {
|
15
|
-
"@ckeditor/ckeditor5-core": "38.1.
|
16
|
-
"@ckeditor/ckeditor5-engine": "38.1.
|
17
|
-
"@ckeditor/ckeditor5-ui": "38.1.
|
15
|
+
"@ckeditor/ckeditor5-core": "38.1.1",
|
16
|
+
"@ckeditor/ckeditor5-engine": "38.1.1",
|
17
|
+
"@ckeditor/ckeditor5-ui": "38.1.1"
|
18
18
|
},
|
19
19
|
"engines": {
|
20
20
|
"node": ">=16.0.0",
|
package/src/augmentation.d.ts
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
-
*/
|
5
|
-
import type { Undo, UndoEditing, UndoUI, UndoCommand, RedoCommand } from './index';
|
6
|
-
declare module '@ckeditor/ckeditor5-core' {
|
7
|
-
interface CommandsMap {
|
8
|
-
undo: UndoCommand;
|
9
|
-
redo: RedoCommand;
|
10
|
-
}
|
11
|
-
interface PluginsMap {
|
12
|
-
[Undo.pluginName]: Undo;
|
13
|
-
[UndoEditing.pluginName]: UndoEditing;
|
14
|
-
[UndoUI.pluginName]: UndoUI;
|
15
|
-
}
|
16
|
-
}
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
import type { Undo, UndoEditing, UndoUI, UndoCommand, RedoCommand } from './index';
|
6
|
+
declare module '@ckeditor/ckeditor5-core' {
|
7
|
+
interface CommandsMap {
|
8
|
+
undo: UndoCommand;
|
9
|
+
redo: RedoCommand;
|
10
|
+
}
|
11
|
+
interface PluginsMap {
|
12
|
+
[Undo.pluginName]: Undo;
|
13
|
+
[UndoEditing.pluginName]: UndoEditing;
|
14
|
+
[UndoUI.pluginName]: UndoUI;
|
15
|
+
}
|
16
|
+
}
|
package/src/augmentation.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
-
*/
|
5
|
-
export {};
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
export {};
|
package/src/basecommand.d.ts
CHANGED
@@ -1,72 +1,72 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
-
*/
|
5
|
-
/**
|
6
|
-
* @module undo/basecommand
|
7
|
-
*/
|
8
|
-
import { Command, type Editor } from '@ckeditor/ckeditor5-core';
|
9
|
-
import { type Batch, type Operation, type Range } from '@ckeditor/ckeditor5-engine';
|
10
|
-
/**
|
11
|
-
* Base class for the undo feature commands: {@link module:undo/undocommand~UndoCommand} and {@link module:undo/redocommand~RedoCommand}.
|
12
|
-
*/
|
13
|
-
export default abstract class BaseCommand extends Command {
|
14
|
-
/**
|
15
|
-
* Stack of items stored by the command. These are pairs of:
|
16
|
-
*
|
17
|
-
* * {@link module:engine/model/batch~Batch batch} saved by the command,
|
18
|
-
* * {@link module:engine/model/selection~Selection selection} state at the moment of saving the batch.
|
19
|
-
*/
|
20
|
-
protected _stack: Array<{
|
21
|
-
batch: Batch;
|
22
|
-
selection: {
|
23
|
-
ranges: Array<Range>;
|
24
|
-
isBackward: boolean;
|
25
|
-
};
|
26
|
-
}>;
|
27
|
-
/**
|
28
|
-
* Stores all batches that were created by this command.
|
29
|
-
*
|
30
|
-
* @internal
|
31
|
-
*/
|
32
|
-
_createdBatches: WeakSet<Batch>;
|
33
|
-
/**
|
34
|
-
* @inheritDoc
|
35
|
-
*/
|
36
|
-
constructor(editor: Editor);
|
37
|
-
/**
|
38
|
-
* @inheritDoc
|
39
|
-
*/
|
40
|
-
refresh(): void;
|
41
|
-
/**
|
42
|
-
* Returns all batches created by this command.
|
43
|
-
*/
|
44
|
-
get createdBatches(): WeakSet<Batch>;
|
45
|
-
/**
|
46
|
-
* Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}
|
47
|
-
* created by the editor which this command is registered to.
|
48
|
-
*
|
49
|
-
* @param batch The batch to add.
|
50
|
-
*/
|
51
|
-
addBatch(batch: Batch): void;
|
52
|
-
/**
|
53
|
-
* Removes all items from the stack.
|
54
|
-
*/
|
55
|
-
clearStack(): void;
|
56
|
-
/**
|
57
|
-
* Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.
|
58
|
-
*
|
59
|
-
* @param ranges Ranges to be restored.
|
60
|
-
* @param isBackward A flag describing whether the restored range was selected forward or backward.
|
61
|
-
* @param operations Operations which has been applied since selection has been stored.
|
62
|
-
*/
|
63
|
-
protected _restoreSelection(ranges: Array<Range>, isBackward: boolean, operations: Array<Operation>): void;
|
64
|
-
/**
|
65
|
-
* Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.
|
66
|
-
* This is a helper method for {@link #execute}.
|
67
|
-
*
|
68
|
-
* @param batchToUndo The batch to be undone.
|
69
|
-
* @param undoingBatch The batch that will contain undoing changes.
|
70
|
-
*/
|
71
|
-
protected _undo(batchToUndo: Batch, undoingBatch: Batch): void;
|
72
|
-
}
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* @module undo/basecommand
|
7
|
+
*/
|
8
|
+
import { Command, type Editor } from '@ckeditor/ckeditor5-core';
|
9
|
+
import { type Batch, type Operation, type Range } from '@ckeditor/ckeditor5-engine';
|
10
|
+
/**
|
11
|
+
* Base class for the undo feature commands: {@link module:undo/undocommand~UndoCommand} and {@link module:undo/redocommand~RedoCommand}.
|
12
|
+
*/
|
13
|
+
export default abstract class BaseCommand extends Command {
|
14
|
+
/**
|
15
|
+
* Stack of items stored by the command. These are pairs of:
|
16
|
+
*
|
17
|
+
* * {@link module:engine/model/batch~Batch batch} saved by the command,
|
18
|
+
* * {@link module:engine/model/selection~Selection selection} state at the moment of saving the batch.
|
19
|
+
*/
|
20
|
+
protected _stack: Array<{
|
21
|
+
batch: Batch;
|
22
|
+
selection: {
|
23
|
+
ranges: Array<Range>;
|
24
|
+
isBackward: boolean;
|
25
|
+
};
|
26
|
+
}>;
|
27
|
+
/**
|
28
|
+
* Stores all batches that were created by this command.
|
29
|
+
*
|
30
|
+
* @internal
|
31
|
+
*/
|
32
|
+
_createdBatches: WeakSet<Batch>;
|
33
|
+
/**
|
34
|
+
* @inheritDoc
|
35
|
+
*/
|
36
|
+
constructor(editor: Editor);
|
37
|
+
/**
|
38
|
+
* @inheritDoc
|
39
|
+
*/
|
40
|
+
refresh(): void;
|
41
|
+
/**
|
42
|
+
* Returns all batches created by this command.
|
43
|
+
*/
|
44
|
+
get createdBatches(): WeakSet<Batch>;
|
45
|
+
/**
|
46
|
+
* Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}
|
47
|
+
* created by the editor which this command is registered to.
|
48
|
+
*
|
49
|
+
* @param batch The batch to add.
|
50
|
+
*/
|
51
|
+
addBatch(batch: Batch): void;
|
52
|
+
/**
|
53
|
+
* Removes all items from the stack.
|
54
|
+
*/
|
55
|
+
clearStack(): void;
|
56
|
+
/**
|
57
|
+
* Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.
|
58
|
+
*
|
59
|
+
* @param ranges Ranges to be restored.
|
60
|
+
* @param isBackward A flag describing whether the restored range was selected forward or backward.
|
61
|
+
* @param operations Operations which has been applied since selection has been stored.
|
62
|
+
*/
|
63
|
+
protected _restoreSelection(ranges: Array<Range>, isBackward: boolean, operations: Array<Operation>): void;
|
64
|
+
/**
|
65
|
+
* Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.
|
66
|
+
* This is a helper method for {@link #execute}.
|
67
|
+
*
|
68
|
+
* @param batchToUndo The batch to be undone.
|
69
|
+
* @param undoingBatch The batch that will contain undoing changes.
|
70
|
+
*/
|
71
|
+
protected _undo(batchToUndo: Batch, undoingBatch: Batch): void;
|
72
|
+
}
|
package/src/basecommand.js
CHANGED
@@ -1,192 +1,192 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
-
*/
|
5
|
-
/**
|
6
|
-
* @module undo/basecommand
|
7
|
-
*/
|
8
|
-
import { Command } from '@ckeditor/ckeditor5-core';
|
9
|
-
import { transformSets, NoOperation } from '@ckeditor/ckeditor5-engine';
|
10
|
-
/**
|
11
|
-
* Base class for the undo feature commands: {@link module:undo/undocommand~UndoCommand} and {@link module:undo/redocommand~RedoCommand}.
|
12
|
-
*/
|
13
|
-
export default class BaseCommand extends Command {
|
14
|
-
/**
|
15
|
-
* @inheritDoc
|
16
|
-
*/
|
17
|
-
constructor(editor) {
|
18
|
-
super(editor);
|
19
|
-
/**
|
20
|
-
* Stack of items stored by the command. These are pairs of:
|
21
|
-
*
|
22
|
-
* * {@link module:engine/model/batch~Batch batch} saved by the command,
|
23
|
-
* * {@link module:engine/model/selection~Selection selection} state at the moment of saving the batch.
|
24
|
-
*/
|
25
|
-
this._stack = [];
|
26
|
-
/**
|
27
|
-
* Stores all batches that were created by this command.
|
28
|
-
*
|
29
|
-
* @internal
|
30
|
-
*/
|
31
|
-
this._createdBatches = new WeakSet();
|
32
|
-
// Refresh state, so the command is inactive right after initialization.
|
33
|
-
this.refresh();
|
34
|
-
// This command should not depend on selection change.
|
35
|
-
this._isEnabledBasedOnSelection = false;
|
36
|
-
// Set the transparent batch for the `editor.data.set()` call if the
|
37
|
-
// batch type is not set already.
|
38
|
-
this.listenTo(editor.data, 'set', (evt, data) => {
|
39
|
-
// Create a shallow copy of the options to not change the original args.
|
40
|
-
// And make sure that an object is assigned to data[ 1 ].
|
41
|
-
data[1] = { ...data[1] };
|
42
|
-
const options = data[1];
|
43
|
-
// If batch type is not set, default to non-undoable batch.
|
44
|
-
if (!options.batchType) {
|
45
|
-
options.batchType = { isUndoable: false };
|
46
|
-
}
|
47
|
-
}, { priority: 'high' });
|
48
|
-
// Clear the stack for the `transparent` batches.
|
49
|
-
this.listenTo(editor.data, 'set', (evt, data) => {
|
50
|
-
// We can assume that the object exists and it has a `batchType` property.
|
51
|
-
// It was ensured with a higher priority listener before.
|
52
|
-
const options = data[1];
|
53
|
-
if (!options.batchType.isUndoable) {
|
54
|
-
this.clearStack();
|
55
|
-
}
|
56
|
-
});
|
57
|
-
}
|
58
|
-
/**
|
59
|
-
* @inheritDoc
|
60
|
-
*/
|
61
|
-
refresh() {
|
62
|
-
this.isEnabled = this._stack.length > 0;
|
63
|
-
}
|
64
|
-
/**
|
65
|
-
* Returns all batches created by this command.
|
66
|
-
*/
|
67
|
-
get createdBatches() {
|
68
|
-
return this._createdBatches;
|
69
|
-
}
|
70
|
-
/**
|
71
|
-
* Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}
|
72
|
-
* created by the editor which this command is registered to.
|
73
|
-
*
|
74
|
-
* @param batch The batch to add.
|
75
|
-
*/
|
76
|
-
addBatch(batch) {
|
77
|
-
const docSelection = this.editor.model.document.selection;
|
78
|
-
const selection = {
|
79
|
-
ranges: docSelection.hasOwnRange ? Array.from(docSelection.getRanges()) : [],
|
80
|
-
isBackward: docSelection.isBackward
|
81
|
-
};
|
82
|
-
this._stack.push({ batch, selection });
|
83
|
-
this.refresh();
|
84
|
-
}
|
85
|
-
/**
|
86
|
-
* Removes all items from the stack.
|
87
|
-
*/
|
88
|
-
clearStack() {
|
89
|
-
this._stack = [];
|
90
|
-
this.refresh();
|
91
|
-
}
|
92
|
-
/**
|
93
|
-
* Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.
|
94
|
-
*
|
95
|
-
* @param ranges Ranges to be restored.
|
96
|
-
* @param isBackward A flag describing whether the restored range was selected forward or backward.
|
97
|
-
* @param operations Operations which has been applied since selection has been stored.
|
98
|
-
*/
|
99
|
-
_restoreSelection(ranges, isBackward, operations) {
|
100
|
-
const model = this.editor.model;
|
101
|
-
const document = model.document;
|
102
|
-
// This will keep the transformed selection ranges.
|
103
|
-
const selectionRanges = [];
|
104
|
-
// Transform all ranges from the restored selection.
|
105
|
-
const transformedRangeGroups = ranges.map(range => range.getTransformedByOperations(operations));
|
106
|
-
const allRanges = transformedRangeGroups.flat();
|
107
|
-
for (const rangeGroup of transformedRangeGroups) {
|
108
|
-
// While transforming there could appear ranges that are contained by other ranges, we shall ignore them.
|
109
|
-
const transformed = rangeGroup
|
110
|
-
.filter(range => range.root != document.graveyard)
|
111
|
-
.filter(range => !isRangeContainedByAnyOtherRange(range, allRanges));
|
112
|
-
// All the transformed ranges ended up in graveyard.
|
113
|
-
if (!transformed.length) {
|
114
|
-
continue;
|
115
|
-
}
|
116
|
-
// After the range got transformed, we have an array of ranges. Some of those
|
117
|
-
// ranges may be "touching" -- they can be next to each other and could be merged.
|
118
|
-
normalizeRanges(transformed);
|
119
|
-
// For each `range` from `ranges`, we take only one transformed range.
|
120
|
-
// This is because we want to prevent situation where single-range selection
|
121
|
-
// got transformed to multi-range selection.
|
122
|
-
selectionRanges.push(transformed[0]);
|
123
|
-
}
|
124
|
-
// @if CK_DEBUG_ENGINE // console.log( `Restored selection by undo: ${ selectionRanges.join( ', ' ) }` );
|
125
|
-
// `selectionRanges` may be empty if all ranges ended up in graveyard. If that is the case, do not restore selection.
|
126
|
-
if (selectionRanges.length) {
|
127
|
-
model.change(writer => {
|
128
|
-
writer.setSelection(selectionRanges, { backward: isBackward });
|
129
|
-
});
|
130
|
-
}
|
131
|
-
}
|
132
|
-
/**
|
133
|
-
* Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.
|
134
|
-
* This is a helper method for {@link #execute}.
|
135
|
-
*
|
136
|
-
* @param batchToUndo The batch to be undone.
|
137
|
-
* @param undoingBatch The batch that will contain undoing changes.
|
138
|
-
*/
|
139
|
-
_undo(batchToUndo, undoingBatch) {
|
140
|
-
const model = this.editor.model;
|
141
|
-
const document = model.document;
|
142
|
-
// All changes done by the command execution will be saved as one batch.
|
143
|
-
this._createdBatches.add(undoingBatch);
|
144
|
-
const operationsToUndo = batchToUndo.operations.slice().filter(operation => operation.isDocumentOperation);
|
145
|
-
operationsToUndo.reverse();
|
146
|
-
// We will process each operation from `batchToUndo`, in reverse order. If there were operations A, B and C in undone batch,
|
147
|
-
// we need to revert them in reverse order, so first C' (reversed C), then B', then A'.
|
148
|
-
for (const operationToUndo of operationsToUndo) {
|
149
|
-
const nextBaseVersion = operationToUndo.baseVersion + 1;
|
150
|
-
const historyOperations = Array.from(document.history.getOperations(nextBaseVersion));
|
151
|
-
const transformedSets = transformSets([operationToUndo.getReversed()], historyOperations, {
|
152
|
-
useRelations: true,
|
153
|
-
document: this.editor.model.document,
|
154
|
-
padWithNoOps: false,
|
155
|
-
forceWeakRemove: true
|
156
|
-
});
|
157
|
-
const reversedOperations = transformedSets.operationsA;
|
158
|
-
// After reversed operation has been transformed by all history operations, apply it.
|
159
|
-
for (let operation of reversedOperations) {
|
160
|
-
// Do not apply any operation on non-editable space.
|
161
|
-
const affectedSelectable = operation.affectedSelectable;
|
162
|
-
if (affectedSelectable && !model.canEditAt(affectedSelectable)) {
|
163
|
-
operation = new NoOperation(operation.baseVersion);
|
164
|
-
}
|
165
|
-
// Before applying, add the operation to the `undoingBatch`.
|
166
|
-
undoingBatch.addOperation(operation);
|
167
|
-
model.applyOperation(operation);
|
168
|
-
document.history.setOperationAsUndone(operationToUndo, operation);
|
169
|
-
}
|
170
|
-
}
|
171
|
-
}
|
172
|
-
}
|
173
|
-
/**
|
174
|
-
* Normalizes list of ranges by joining intersecting or "touching" ranges.
|
175
|
-
*
|
176
|
-
* @param ranges Ranges to be normalized.
|
177
|
-
*/
|
178
|
-
function normalizeRanges(ranges) {
|
179
|
-
ranges.sort((a, b) => a.start.isBefore(b.start) ? -1 : 1);
|
180
|
-
for (let i = 1; i < ranges.length; i++) {
|
181
|
-
const previousRange = ranges[i - 1];
|
182
|
-
const joinedRange = previousRange.getJoined(ranges[i], true);
|
183
|
-
if (joinedRange) {
|
184
|
-
// Replace the ranges on the list with the new joined range.
|
185
|
-
i--;
|
186
|
-
ranges.splice(i, 2, joinedRange);
|
187
|
-
}
|
188
|
-
}
|
189
|
-
}
|
190
|
-
function isRangeContainedByAnyOtherRange(range, ranges) {
|
191
|
-
return ranges.some(otherRange => otherRange !== range && otherRange.containsRange(range, true));
|
192
|
-
}
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* @module undo/basecommand
|
7
|
+
*/
|
8
|
+
import { Command } from '@ckeditor/ckeditor5-core';
|
9
|
+
import { transformSets, NoOperation } from '@ckeditor/ckeditor5-engine';
|
10
|
+
/**
|
11
|
+
* Base class for the undo feature commands: {@link module:undo/undocommand~UndoCommand} and {@link module:undo/redocommand~RedoCommand}.
|
12
|
+
*/
|
13
|
+
export default class BaseCommand extends Command {
|
14
|
+
/**
|
15
|
+
* @inheritDoc
|
16
|
+
*/
|
17
|
+
constructor(editor) {
|
18
|
+
super(editor);
|
19
|
+
/**
|
20
|
+
* Stack of items stored by the command. These are pairs of:
|
21
|
+
*
|
22
|
+
* * {@link module:engine/model/batch~Batch batch} saved by the command,
|
23
|
+
* * {@link module:engine/model/selection~Selection selection} state at the moment of saving the batch.
|
24
|
+
*/
|
25
|
+
this._stack = [];
|
26
|
+
/**
|
27
|
+
* Stores all batches that were created by this command.
|
28
|
+
*
|
29
|
+
* @internal
|
30
|
+
*/
|
31
|
+
this._createdBatches = new WeakSet();
|
32
|
+
// Refresh state, so the command is inactive right after initialization.
|
33
|
+
this.refresh();
|
34
|
+
// This command should not depend on selection change.
|
35
|
+
this._isEnabledBasedOnSelection = false;
|
36
|
+
// Set the transparent batch for the `editor.data.set()` call if the
|
37
|
+
// batch type is not set already.
|
38
|
+
this.listenTo(editor.data, 'set', (evt, data) => {
|
39
|
+
// Create a shallow copy of the options to not change the original args.
|
40
|
+
// And make sure that an object is assigned to data[ 1 ].
|
41
|
+
data[1] = { ...data[1] };
|
42
|
+
const options = data[1];
|
43
|
+
// If batch type is not set, default to non-undoable batch.
|
44
|
+
if (!options.batchType) {
|
45
|
+
options.batchType = { isUndoable: false };
|
46
|
+
}
|
47
|
+
}, { priority: 'high' });
|
48
|
+
// Clear the stack for the `transparent` batches.
|
49
|
+
this.listenTo(editor.data, 'set', (evt, data) => {
|
50
|
+
// We can assume that the object exists and it has a `batchType` property.
|
51
|
+
// It was ensured with a higher priority listener before.
|
52
|
+
const options = data[1];
|
53
|
+
if (!options.batchType.isUndoable) {
|
54
|
+
this.clearStack();
|
55
|
+
}
|
56
|
+
});
|
57
|
+
}
|
58
|
+
/**
|
59
|
+
* @inheritDoc
|
60
|
+
*/
|
61
|
+
refresh() {
|
62
|
+
this.isEnabled = this._stack.length > 0;
|
63
|
+
}
|
64
|
+
/**
|
65
|
+
* Returns all batches created by this command.
|
66
|
+
*/
|
67
|
+
get createdBatches() {
|
68
|
+
return this._createdBatches;
|
69
|
+
}
|
70
|
+
/**
|
71
|
+
* Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}
|
72
|
+
* created by the editor which this command is registered to.
|
73
|
+
*
|
74
|
+
* @param batch The batch to add.
|
75
|
+
*/
|
76
|
+
addBatch(batch) {
|
77
|
+
const docSelection = this.editor.model.document.selection;
|
78
|
+
const selection = {
|
79
|
+
ranges: docSelection.hasOwnRange ? Array.from(docSelection.getRanges()) : [],
|
80
|
+
isBackward: docSelection.isBackward
|
81
|
+
};
|
82
|
+
this._stack.push({ batch, selection });
|
83
|
+
this.refresh();
|
84
|
+
}
|
85
|
+
/**
|
86
|
+
* Removes all items from the stack.
|
87
|
+
*/
|
88
|
+
clearStack() {
|
89
|
+
this._stack = [];
|
90
|
+
this.refresh();
|
91
|
+
}
|
92
|
+
/**
|
93
|
+
* Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.
|
94
|
+
*
|
95
|
+
* @param ranges Ranges to be restored.
|
96
|
+
* @param isBackward A flag describing whether the restored range was selected forward or backward.
|
97
|
+
* @param operations Operations which has been applied since selection has been stored.
|
98
|
+
*/
|
99
|
+
_restoreSelection(ranges, isBackward, operations) {
|
100
|
+
const model = this.editor.model;
|
101
|
+
const document = model.document;
|
102
|
+
// This will keep the transformed selection ranges.
|
103
|
+
const selectionRanges = [];
|
104
|
+
// Transform all ranges from the restored selection.
|
105
|
+
const transformedRangeGroups = ranges.map(range => range.getTransformedByOperations(operations));
|
106
|
+
const allRanges = transformedRangeGroups.flat();
|
107
|
+
for (const rangeGroup of transformedRangeGroups) {
|
108
|
+
// While transforming there could appear ranges that are contained by other ranges, we shall ignore them.
|
109
|
+
const transformed = rangeGroup
|
110
|
+
.filter(range => range.root != document.graveyard)
|
111
|
+
.filter(range => !isRangeContainedByAnyOtherRange(range, allRanges));
|
112
|
+
// All the transformed ranges ended up in graveyard.
|
113
|
+
if (!transformed.length) {
|
114
|
+
continue;
|
115
|
+
}
|
116
|
+
// After the range got transformed, we have an array of ranges. Some of those
|
117
|
+
// ranges may be "touching" -- they can be next to each other and could be merged.
|
118
|
+
normalizeRanges(transformed);
|
119
|
+
// For each `range` from `ranges`, we take only one transformed range.
|
120
|
+
// This is because we want to prevent situation where single-range selection
|
121
|
+
// got transformed to multi-range selection.
|
122
|
+
selectionRanges.push(transformed[0]);
|
123
|
+
}
|
124
|
+
// @if CK_DEBUG_ENGINE // console.log( `Restored selection by undo: ${ selectionRanges.join( ', ' ) }` );
|
125
|
+
// `selectionRanges` may be empty if all ranges ended up in graveyard. If that is the case, do not restore selection.
|
126
|
+
if (selectionRanges.length) {
|
127
|
+
model.change(writer => {
|
128
|
+
writer.setSelection(selectionRanges, { backward: isBackward });
|
129
|
+
});
|
130
|
+
}
|
131
|
+
}
|
132
|
+
/**
|
133
|
+
* Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.
|
134
|
+
* This is a helper method for {@link #execute}.
|
135
|
+
*
|
136
|
+
* @param batchToUndo The batch to be undone.
|
137
|
+
* @param undoingBatch The batch that will contain undoing changes.
|
138
|
+
*/
|
139
|
+
_undo(batchToUndo, undoingBatch) {
|
140
|
+
const model = this.editor.model;
|
141
|
+
const document = model.document;
|
142
|
+
// All changes done by the command execution will be saved as one batch.
|
143
|
+
this._createdBatches.add(undoingBatch);
|
144
|
+
const operationsToUndo = batchToUndo.operations.slice().filter(operation => operation.isDocumentOperation);
|
145
|
+
operationsToUndo.reverse();
|
146
|
+
// We will process each operation from `batchToUndo`, in reverse order. If there were operations A, B and C in undone batch,
|
147
|
+
// we need to revert them in reverse order, so first C' (reversed C), then B', then A'.
|
148
|
+
for (const operationToUndo of operationsToUndo) {
|
149
|
+
const nextBaseVersion = operationToUndo.baseVersion + 1;
|
150
|
+
const historyOperations = Array.from(document.history.getOperations(nextBaseVersion));
|
151
|
+
const transformedSets = transformSets([operationToUndo.getReversed()], historyOperations, {
|
152
|
+
useRelations: true,
|
153
|
+
document: this.editor.model.document,
|
154
|
+
padWithNoOps: false,
|
155
|
+
forceWeakRemove: true
|
156
|
+
});
|
157
|
+
const reversedOperations = transformedSets.operationsA;
|
158
|
+
// After reversed operation has been transformed by all history operations, apply it.
|
159
|
+
for (let operation of reversedOperations) {
|
160
|
+
// Do not apply any operation on non-editable space.
|
161
|
+
const affectedSelectable = operation.affectedSelectable;
|
162
|
+
if (affectedSelectable && !model.canEditAt(affectedSelectable)) {
|
163
|
+
operation = new NoOperation(operation.baseVersion);
|
164
|
+
}
|
165
|
+
// Before applying, add the operation to the `undoingBatch`.
|
166
|
+
undoingBatch.addOperation(operation);
|
167
|
+
model.applyOperation(operation);
|
168
|
+
document.history.setOperationAsUndone(operationToUndo, operation);
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
/**
|
174
|
+
* Normalizes list of ranges by joining intersecting or "touching" ranges.
|
175
|
+
*
|
176
|
+
* @param ranges Ranges to be normalized.
|
177
|
+
*/
|
178
|
+
function normalizeRanges(ranges) {
|
179
|
+
ranges.sort((a, b) => a.start.isBefore(b.start) ? -1 : 1);
|
180
|
+
for (let i = 1; i < ranges.length; i++) {
|
181
|
+
const previousRange = ranges[i - 1];
|
182
|
+
const joinedRange = previousRange.getJoined(ranges[i], true);
|
183
|
+
if (joinedRange) {
|
184
|
+
// Replace the ranges on the list with the new joined range.
|
185
|
+
i--;
|
186
|
+
ranges.splice(i, 2, joinedRange);
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
function isRangeContainedByAnyOtherRange(range, ranges) {
|
191
|
+
return ranges.some(otherRange => otherRange !== range && otherRange.containsRange(range, true));
|
192
|
+
}
|
package/src/index.d.ts
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
-
*/
|
5
|
-
/**
|
6
|
-
* @module undo
|
7
|
-
*/
|
8
|
-
export { default as Undo } from './undo';
|
9
|
-
export { default as UndoEditing } from './undoediting';
|
10
|
-
export { default as UndoUI } from './undoui';
|
11
|
-
export type { default as UndoCommand } from './undocommand';
|
12
|
-
export type { default as RedoCommand } from './redocommand';
|
13
|
-
import './augmentation';
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* @module undo
|
7
|
+
*/
|
8
|
+
export { default as Undo } from './undo';
|
9
|
+
export { default as UndoEditing } from './undoediting';
|
10
|
+
export { default as UndoUI } from './undoui';
|
11
|
+
export type { default as UndoCommand } from './undocommand';
|
12
|
+
export type { default as RedoCommand } from './redocommand';
|
13
|
+
import './augmentation';
|
package/src/index.js
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
-
*/
|
5
|
-
/**
|
6
|
-
* @module undo
|
7
|
-
*/
|
8
|
-
export { default as Undo } from './undo';
|
9
|
-
export { default as UndoEditing } from './undoediting';
|
10
|
-
export { default as UndoUI } from './undoui';
|
11
|
-
import './augmentation';
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* @module undo
|
7
|
+
*/
|
8
|
+
export { default as Undo } from './undo';
|
9
|
+
export { default as UndoEditing } from './undoediting';
|
10
|
+
export { default as UndoUI } from './undoui';
|
11
|
+
import './augmentation';
|