/
undoediting.js
119 lines (101 loc) · 3.63 KB
/
undoediting.js
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
/**
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. 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/src/plugin';
import UndoCommand from './undocommand';
import RedoCommand from './redocommand';
/**
* The undo engine feature.
*
* It introduces the `'undo'` and `'redo'` commands to the editor.
*
* @extends module:core/plugin~Plugin
*/
export default class UndoEditing extends Plugin {
/**
* @inheritDoc
*/
static get pluginName() {
return 'UndoEditing';
}
/**
* @inheritDoc
*/
constructor( editor ) {
super( editor );
/**
* The command that manages undo {@link module:engine/model/batch~Batch batches} stack (history).
* Created and registered during the {@link #init feature initialization}.
*
* @private
* @member {module:undo/undocommand~UndoCommand} #_undoCommand
*/
/**
* The command that manages redo {@link module:engine/model/batch~Batch batches} stack (history).
* Created and registered during the {@link #init feature initialization}.
*
* @private
* @member {module:undo/undocommand~UndoCommand} #_redoCommand
*/
/**
* Keeps track of which batches were registered in undo.
*
* @private
* @member {WeakSet.<module:engine/model/batch~Batch>}
*/
this._batchRegistry = new WeakSet();
}
/**
* @inheritDoc
*/
init() {
const editor = this.editor;
// 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( 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 isRegisteredBatch = this._batchRegistry.has( batch );
// If changes are not a part of a batch or this is not a new batch, omit those changes.
if ( isRegisteredBatch || ( batch.type == 'transparent' && !isRedoBatch && !isUndoBatch ) ) {
return;
} else {
if ( isRedoBatch ) {
// If this batch comes from `redoCommand`, add it to `undoCommand` stack.
this._undoCommand.addBatch( batch );
} else if ( !isUndoBatch ) {
// A default batch - these are new changes in the document, not introduced by undo feature.
// Add them to `undoCommand` stack and clear `redoCommand` stack.
this._undoCommand.addBatch( batch );
this._redoCommand.clearStack();
}
}
// Add the batch to the registry so it will not be processed again.
this._batchRegistry.add( batch );
}, { priority: 'highest' } );
this.listenTo( 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' );
}
}