-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
undoediting.ts
128 lines (106 loc) · 3.81 KB
/
undoediting.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @module undo/undoediting
*/
import { Plugin } from '@ckeditor/ckeditor5-core';
import UndoCommand, { type UndoCommandRevertEvent } from './undocommand.js';
import RedoCommand from './redocommand.js';
import type {
Batch,
ModelApplyOperationEvent
} from '@ckeditor/ckeditor5-engine';
/**
* The undo engine feature.
*
* It introduces the `'undo'` and `'redo'` commands to the editor.
*/
export default class UndoEditing extends Plugin {
/**
* The command that manages the undo {@link module:engine/model/batch~Batch batches} stack (history).
* Created and registered during the {@link #init feature initialization}.
*/
private _undoCommand!: UndoCommand;
/**
* The command that manages the redo {@link module:engine/model/batch~Batch batches} stack (history).
* Created and registered during the {@link #init feature initialization}.
*/
private _redoCommand!: RedoCommand;
/**
* Keeps track of which batches were registered in undo.
*/
private _batchRegistry = new WeakSet<Batch>();
/**
* @inheritDoc
*/
public static get pluginName() {
return 'UndoEditing' as const;
}
/**
* @inheritDoc
*/
public init(): void {
const editor = this.editor;
const t = editor.t;
// Create commands.
this._undoCommand = new UndoCommand( editor );
this._redoCommand = new RedoCommand( editor );
// Register command to the editor.
editor.commands.add( 'undo', this._undoCommand );
editor.commands.add( 'redo', this._redoCommand );
this.listenTo<ModelApplyOperationEvent>( editor.model, 'applyOperation', ( evt, args ) => {
const operation = args[ 0 ];
// Do not register batch if the operation is not a document operation.
// This prevents from creating empty undo steps, where all operations where non-document operations.
// Non-document operations creates and alters content in detached tree fragments (for example, document fragments).
// Most of time this is preparing data before it is inserted into actual tree (for example during copy & paste).
// Such operations should not be reversed.
if ( !operation.isDocumentOperation ) {
return;
}
const batch = operation.batch!;
const isRedoBatch = this._redoCommand.createdBatches.has( batch );
const isUndoBatch = this._undoCommand.createdBatches.has( batch );
const wasProcessed = this._batchRegistry.has( batch );
// Skip the batch if it was already processed.
if ( wasProcessed ) {
return;
}
// Add the batch to the registry so it will not be processed again.
this._batchRegistry.add( batch );
if ( !batch.isUndoable ) {
return;
}
if ( isRedoBatch ) {
// If this batch comes from `redoCommand`, add it to the `undoCommand` stack.
this._undoCommand.addBatch( batch );
} else if ( !isUndoBatch ) {
// If the batch comes neither from `redoCommand` nor from `undoCommand` then it is a new, regular batch.
// Add the batch to the `undoCommand` stack and clear the `redoCommand` stack.
this._undoCommand.addBatch( batch );
this._redoCommand.clearStack();
}
}, { priority: 'highest' } );
this.listenTo<UndoCommandRevertEvent>( this._undoCommand, 'revert', ( evt, undoneBatch, undoingBatch ) => {
this._redoCommand.addBatch( undoingBatch );
} );
editor.keystrokes.set( 'CTRL+Z', 'undo' );
editor.keystrokes.set( 'CTRL+Y', 'redo' );
editor.keystrokes.set( 'CTRL+SHIFT+Z', 'redo' );
// Add the information about the keystrokes to the accessibility database.
editor.accessibility.addKeystrokeInfos( {
keystrokes: [
{
label: t( 'Undo' ),
keystroke: 'CTRL+Z'
},
{
label: t( 'Redo' ),
keystroke: [ [ 'CTRL+Y' ], [ 'CTRL+SHIFT+Z' ] ]
}
]
} );
}
}