@ckeditor/ckeditor5-engine 30.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/LICENSE.md +17 -0
  2. package/README.md +30 -0
  3. package/package.json +70 -0
  4. package/src/controller/datacontroller.js +563 -0
  5. package/src/controller/editingcontroller.js +149 -0
  6. package/src/conversion/conversion.js +644 -0
  7. package/src/conversion/conversionhelpers.js +40 -0
  8. package/src/conversion/downcastdispatcher.js +914 -0
  9. package/src/conversion/downcasthelpers.js +1706 -0
  10. package/src/conversion/mapper.js +696 -0
  11. package/src/conversion/modelconsumable.js +329 -0
  12. package/src/conversion/upcastdispatcher.js +807 -0
  13. package/src/conversion/upcasthelpers.js +997 -0
  14. package/src/conversion/viewconsumable.js +623 -0
  15. package/src/dataprocessor/basichtmlwriter.js +32 -0
  16. package/src/dataprocessor/dataprocessor.jsdoc +64 -0
  17. package/src/dataprocessor/htmldataprocessor.js +159 -0
  18. package/src/dataprocessor/htmlwriter.js +22 -0
  19. package/src/dataprocessor/xmldataprocessor.js +161 -0
  20. package/src/dev-utils/model.js +482 -0
  21. package/src/dev-utils/operationreplayer.js +140 -0
  22. package/src/dev-utils/utils.js +103 -0
  23. package/src/dev-utils/view.js +1091 -0
  24. package/src/index.js +52 -0
  25. package/src/model/batch.js +82 -0
  26. package/src/model/differ.js +1282 -0
  27. package/src/model/document.js +483 -0
  28. package/src/model/documentfragment.js +390 -0
  29. package/src/model/documentselection.js +1261 -0
  30. package/src/model/element.js +438 -0
  31. package/src/model/history.js +138 -0
  32. package/src/model/item.jsdoc +14 -0
  33. package/src/model/liveposition.js +182 -0
  34. package/src/model/liverange.js +221 -0
  35. package/src/model/markercollection.js +553 -0
  36. package/src/model/model.js +934 -0
  37. package/src/model/node.js +507 -0
  38. package/src/model/nodelist.js +217 -0
  39. package/src/model/operation/attributeoperation.js +202 -0
  40. package/src/model/operation/detachoperation.js +103 -0
  41. package/src/model/operation/insertoperation.js +188 -0
  42. package/src/model/operation/markeroperation.js +154 -0
  43. package/src/model/operation/mergeoperation.js +216 -0
  44. package/src/model/operation/moveoperation.js +209 -0
  45. package/src/model/operation/nooperation.js +58 -0
  46. package/src/model/operation/operation.js +139 -0
  47. package/src/model/operation/operationfactory.js +49 -0
  48. package/src/model/operation/renameoperation.js +155 -0
  49. package/src/model/operation/rootattributeoperation.js +211 -0
  50. package/src/model/operation/splitoperation.js +254 -0
  51. package/src/model/operation/transform.js +2389 -0
  52. package/src/model/operation/utils.js +292 -0
  53. package/src/model/position.js +1164 -0
  54. package/src/model/range.js +1049 -0
  55. package/src/model/rootelement.js +111 -0
  56. package/src/model/schema.js +1851 -0
  57. package/src/model/selection.js +902 -0
  58. package/src/model/text.js +138 -0
  59. package/src/model/textproxy.js +279 -0
  60. package/src/model/treewalker.js +414 -0
  61. package/src/model/utils/autoparagraphing.js +77 -0
  62. package/src/model/utils/deletecontent.js +528 -0
  63. package/src/model/utils/getselectedcontent.js +150 -0
  64. package/src/model/utils/insertcontent.js +824 -0
  65. package/src/model/utils/modifyselection.js +229 -0
  66. package/src/model/utils/selection-post-fixer.js +297 -0
  67. package/src/model/writer.js +1574 -0
  68. package/src/view/attributeelement.js +274 -0
  69. package/src/view/containerelement.js +123 -0
  70. package/src/view/document.js +221 -0
  71. package/src/view/documentfragment.js +273 -0
  72. package/src/view/documentselection.js +387 -0
  73. package/src/view/domconverter.js +1437 -0
  74. package/src/view/downcastwriter.js +2121 -0
  75. package/src/view/editableelement.js +118 -0
  76. package/src/view/element.js +945 -0
  77. package/src/view/elementdefinition.jsdoc +59 -0
  78. package/src/view/emptyelement.js +119 -0
  79. package/src/view/filler.js +161 -0
  80. package/src/view/item.jsdoc +14 -0
  81. package/src/view/matcher.js +776 -0
  82. package/src/view/node.js +391 -0
  83. package/src/view/observer/arrowkeysobserver.js +58 -0
  84. package/src/view/observer/bubblingemittermixin.js +307 -0
  85. package/src/view/observer/bubblingeventinfo.js +71 -0
  86. package/src/view/observer/clickobserver.js +46 -0
  87. package/src/view/observer/compositionobserver.js +79 -0
  88. package/src/view/observer/domeventdata.js +82 -0
  89. package/src/view/observer/domeventobserver.js +99 -0
  90. package/src/view/observer/fakeselectionobserver.js +118 -0
  91. package/src/view/observer/focusobserver.js +106 -0
  92. package/src/view/observer/inputobserver.js +44 -0
  93. package/src/view/observer/keyobserver.js +83 -0
  94. package/src/view/observer/mouseobserver.js +56 -0
  95. package/src/view/observer/mutationobserver.js +345 -0
  96. package/src/view/observer/observer.js +118 -0
  97. package/src/view/observer/selectionobserver.js +242 -0
  98. package/src/view/placeholder.js +285 -0
  99. package/src/view/position.js +426 -0
  100. package/src/view/range.js +533 -0
  101. package/src/view/rawelement.js +148 -0
  102. package/src/view/renderer.js +1037 -0
  103. package/src/view/rooteditableelement.js +107 -0
  104. package/src/view/selection.js +718 -0
  105. package/src/view/styles/background.js +73 -0
  106. package/src/view/styles/border.js +362 -0
  107. package/src/view/styles/margin.js +41 -0
  108. package/src/view/styles/padding.js +40 -0
  109. package/src/view/styles/utils.js +277 -0
  110. package/src/view/stylesmap.js +938 -0
  111. package/src/view/text.js +147 -0
  112. package/src/view/textproxy.js +199 -0
  113. package/src/view/treewalker.js +496 -0
  114. package/src/view/uielement.js +238 -0
  115. package/src/view/upcastwriter.js +484 -0
  116. package/src/view/view.js +721 -0
  117. package/theme/placeholder.css +27 -0
@@ -0,0 +1,154 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module engine/model/operation/markeroperation
8
+ */
9
+
10
+ import Operation from './operation';
11
+ import Range from '../range';
12
+
13
+ /**
14
+ * @extends module:engine/model/operation/operation~Operation
15
+ */
16
+ export default class MarkerOperation extends Operation {
17
+ /**
18
+ * @param {String} name Marker name.
19
+ * @param {module:engine/model/range~Range} oldRange Marker range before the change.
20
+ * @param {module:engine/model/range~Range} newRange Marker range after the change.
21
+ * @param {module:engine/model/markercollection~MarkerCollection} markers Marker collection on which change should be executed.
22
+ * @param {Boolean} affectsData Specifies whether the marker operation affects the data produced by the data pipeline
23
+ * (is persisted in the editor's data).
24
+ * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation
25
+ * can be applied or `null` if the operation operates on detached (non-document) tree.
26
+ */
27
+ constructor( name, oldRange, newRange, markers, affectsData, baseVersion ) {
28
+ super( baseVersion );
29
+
30
+ /**
31
+ * Marker name.
32
+ *
33
+ * @readonly
34
+ * @member {String}
35
+ */
36
+ this.name = name;
37
+
38
+ /**
39
+ * Marker range before the change.
40
+ *
41
+ * @readonly
42
+ * @member {module:engine/model/range~Range}
43
+ */
44
+ this.oldRange = oldRange ? oldRange.clone() : null;
45
+
46
+ /**
47
+ * Marker range after the change.
48
+ *
49
+ * @readonly
50
+ * @member {module:engine/model/range~Range}
51
+ */
52
+ this.newRange = newRange ? newRange.clone() : null;
53
+
54
+ /**
55
+ * Specifies whether the marker operation affects the data produced by the data pipeline
56
+ * (is persisted in the editor's data).
57
+ *
58
+ * @readonly
59
+ * @member {Boolean}
60
+ */
61
+ this.affectsData = affectsData;
62
+
63
+ /**
64
+ * Marker collection on which change should be executed.
65
+ *
66
+ * @private
67
+ * @member {module:engine/model/markercollection~MarkerCollection}
68
+ */
69
+ this._markers = markers;
70
+ }
71
+
72
+ /**
73
+ * @inheritDoc
74
+ */
75
+ get type() {
76
+ return 'marker';
77
+ }
78
+
79
+ /**
80
+ * Creates and returns an operation that has the same parameters as this operation.
81
+ *
82
+ * @returns {module:engine/model/operation/markeroperation~MarkerOperation} Clone of this operation.
83
+ */
84
+ clone() {
85
+ return new MarkerOperation( this.name, this.oldRange, this.newRange, this._markers, this.affectsData, this.baseVersion );
86
+ }
87
+
88
+ /**
89
+ * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
90
+ *
91
+ * @returns {module:engine/model/operation/markeroperation~MarkerOperation}
92
+ */
93
+ getReversed() {
94
+ return new MarkerOperation( this.name, this.newRange, this.oldRange, this._markers, this.affectsData, this.baseVersion + 1 );
95
+ }
96
+
97
+ /**
98
+ * @inheritDoc
99
+ */
100
+ _execute() {
101
+ const type = this.newRange ? '_set' : '_remove';
102
+
103
+ this._markers[ type ]( this.name, this.newRange, true, this.affectsData );
104
+ }
105
+
106
+ /**
107
+ * @inheritDoc
108
+ */
109
+ toJSON() {
110
+ const json = super.toJSON();
111
+
112
+ if ( this.oldRange ) {
113
+ json.oldRange = this.oldRange.toJSON();
114
+ }
115
+
116
+ if ( this.newRange ) {
117
+ json.newRange = this.newRange.toJSON();
118
+ }
119
+
120
+ delete json._markers;
121
+
122
+ return json;
123
+ }
124
+
125
+ /**
126
+ * @inheritDoc
127
+ */
128
+ static get className() {
129
+ return 'MarkerOperation';
130
+ }
131
+
132
+ /**
133
+ * Creates `MarkerOperation` object from deserialized object, i.e. from parsed JSON string.
134
+ *
135
+ * @param {Object} json Deserialized JSON object.
136
+ * @param {module:engine/model/document~Document} document Document on which this operation will be applied.
137
+ * @returns {module:engine/model/operation/markeroperation~MarkerOperation}
138
+ */
139
+ static fromJSON( json, document ) {
140
+ return new MarkerOperation(
141
+ json.name,
142
+ json.oldRange ? Range.fromJSON( json.oldRange, document ) : null,
143
+ json.newRange ? Range.fromJSON( json.newRange, document ) : null,
144
+ document.model.markers,
145
+ json.affectsData,
146
+ json.baseVersion
147
+ );
148
+ }
149
+
150
+ // @if CK_DEBUG_ENGINE // toString() {
151
+ // @if CK_DEBUG_ENGINE // return `MarkerOperation( ${ this.baseVersion } ): ` +
152
+ // @if CK_DEBUG_ENGINE // `"${ this.name }": ${ this.oldRange } -> ${ this.newRange }`;
153
+ // @if CK_DEBUG_ENGINE // }
154
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module engine/model/operation/mergeoperation
8
+ */
9
+
10
+ import Operation from './operation';
11
+ import SplitOperation from './splitoperation';
12
+ import Position from '../position';
13
+ import Range from '../range';
14
+ import { _move } from './utils';
15
+
16
+ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
17
+
18
+ /**
19
+ * Operation to merge two {@link module:engine/model/element~Element elements}.
20
+ *
21
+ * The merged element is the parent of {@link ~MergeOperation#sourcePosition} and it is merged into the parent of
22
+ * {@link ~MergeOperation#targetPosition}. All nodes from the merged element are moved to {@link ~MergeOperation#targetPosition}.
23
+ *
24
+ * The merged element is moved to the graveyard at {@link ~MergeOperation#graveyardPosition}.
25
+ *
26
+ * @extends module:engine/model/operation/operation~Operation
27
+ */
28
+ export default class MergeOperation extends Operation {
29
+ /**
30
+ * Creates a merge operation.
31
+ *
32
+ * @param {module:engine/model/position~Position} sourcePosition Position inside the merged element. All nodes from that
33
+ * element after that position will be moved to {@link ~#targetPosition}.
34
+ * @param {Number} howMany Summary offset size of nodes which will be moved from the merged element to the new parent.
35
+ * @param {module:engine/model/position~Position} targetPosition Position which the nodes from the merged elements will be moved to.
36
+ * @param {module:engine/model/position~Position} graveyardPosition Position in graveyard to which the merged element will be moved.
37
+ * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation
38
+ * can be applied or `null` if the operation operates on detached (non-document) tree.
39
+ */
40
+ constructor( sourcePosition, howMany, targetPosition, graveyardPosition, baseVersion ) {
41
+ super( baseVersion );
42
+
43
+ /**
44
+ * Position inside the merged element. All nodes from that element after that position will be moved to {@link ~#targetPosition}.
45
+ *
46
+ * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#sourcePosition
47
+ */
48
+ this.sourcePosition = sourcePosition.clone();
49
+ // This is, and should always remain, the first position in its parent.
50
+ this.sourcePosition.stickiness = 'toPrevious';
51
+
52
+ /**
53
+ * Summary offset size of nodes which will be moved from the merged element to the new parent.
54
+ *
55
+ * @member {Number} module:engine/model/operation/mergeoperation~MergeOperation#howMany
56
+ */
57
+ this.howMany = howMany;
58
+
59
+ /**
60
+ * Position which the nodes from the merged elements will be moved to.
61
+ *
62
+ * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#targetPosition
63
+ */
64
+ this.targetPosition = targetPosition.clone();
65
+ // Except of a rare scenario in `MergeOperation` x `MergeOperation` transformation,
66
+ // this is, and should always remain, the last position in its parent.
67
+ this.targetPosition.stickiness = 'toNext';
68
+
69
+ /**
70
+ * Position in graveyard to which the merged element will be moved.
71
+ *
72
+ * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#graveyardPosition
73
+ */
74
+ this.graveyardPosition = graveyardPosition.clone();
75
+ }
76
+
77
+ /**
78
+ * @inheritDoc
79
+ */
80
+ get type() {
81
+ return 'merge';
82
+ }
83
+
84
+ /**
85
+ * Position before the merged element (which will be deleted).
86
+ *
87
+ * @readonly
88
+ * @type {module:engine/model/position~Position}
89
+ */
90
+ get deletionPosition() {
91
+ return new Position( this.sourcePosition.root, this.sourcePosition.path.slice( 0, -1 ) );
92
+ }
93
+
94
+ /**
95
+ * Artificial range that contains all the nodes from the merged element that will be moved to {@link ~MergeOperation#sourcePosition}.
96
+ * The range starts at {@link ~MergeOperation#sourcePosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.
97
+ *
98
+ * @readonly
99
+ * @type {module:engine/model/range~Range}
100
+ */
101
+ get movedRange() {
102
+ const end = this.sourcePosition.getShiftedBy( Number.POSITIVE_INFINITY );
103
+
104
+ return new Range( this.sourcePosition, end );
105
+ }
106
+
107
+ /**
108
+ * Creates and returns an operation that has the same parameters as this operation.
109
+ *
110
+ * @returns {module:engine/model/operation/mergeoperation~MergeOperation} Clone of this operation.
111
+ */
112
+ clone() {
113
+ return new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.graveyardPosition, this.baseVersion );
114
+ }
115
+
116
+ /**
117
+ * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
118
+ *
119
+ * @returns {module:engine/model/operation/splitoperation~SplitOperation}
120
+ */
121
+ getReversed() {
122
+ // Positions in this method are transformed by this merge operation because the split operation bases on
123
+ // the context after this merge operation happened (because split operation reverses it).
124
+ // So we need to acknowledge that the merge operation happened and those positions changed a little.
125
+ const targetPosition = this.targetPosition._getTransformedByMergeOperation( this );
126
+
127
+ const path = this.sourcePosition.path.slice( 0, -1 );
128
+ const insertionPosition = new Position( this.sourcePosition.root, path )._getTransformedByMergeOperation( this );
129
+
130
+ return new SplitOperation( targetPosition, this.howMany, insertionPosition, this.graveyardPosition, this.baseVersion + 1 );
131
+ }
132
+
133
+ /**
134
+ * @inheritDoc
135
+ */
136
+ _validate() {
137
+ const sourceElement = this.sourcePosition.parent;
138
+ const targetElement = this.targetPosition.parent;
139
+
140
+ // Validate whether merge operation has correct parameters.
141
+ if ( !sourceElement.parent ) {
142
+ /**
143
+ * Merge source position is invalid. The element to be merged must have a parent node.
144
+ *
145
+ * @error merge-operation-source-position-invalid
146
+ */
147
+ throw new CKEditorError( 'merge-operation-source-position-invalid', this );
148
+ } else if ( !targetElement.parent ) {
149
+ /**
150
+ * Merge target position is invalid. The element to be merged must have a parent node.
151
+ *
152
+ * @error merge-operation-target-position-invalid
153
+ */
154
+ throw new CKEditorError( 'merge-operation-target-position-invalid', this );
155
+ } else if ( this.howMany != sourceElement.maxOffset ) {
156
+ /**
157
+ * Merge operation specifies wrong number of nodes to move.
158
+ *
159
+ * @error merge-operation-how-many-invalid
160
+ */
161
+ throw new CKEditorError( 'merge-operation-how-many-invalid', this );
162
+ }
163
+ }
164
+
165
+ /**
166
+ * @inheritDoc
167
+ */
168
+ _execute() {
169
+ const mergedElement = this.sourcePosition.parent;
170
+ const sourceRange = Range._createIn( mergedElement );
171
+
172
+ _move( sourceRange, this.targetPosition );
173
+ _move( Range._createOn( mergedElement ), this.graveyardPosition );
174
+ }
175
+
176
+ /**
177
+ * @inheritDoc
178
+ */
179
+ toJSON() {
180
+ const json = super.toJSON();
181
+
182
+ json.sourcePosition = json.sourcePosition.toJSON();
183
+ json.targetPosition = json.targetPosition.toJSON();
184
+ json.graveyardPosition = json.graveyardPosition.toJSON();
185
+
186
+ return json;
187
+ }
188
+
189
+ /**
190
+ * @inheritDoc
191
+ */
192
+ static get className() {
193
+ return 'MergeOperation';
194
+ }
195
+
196
+ /**
197
+ * Creates `MergeOperation` object from deserilized object, i.e. from parsed JSON string.
198
+ *
199
+ * @param {Object} json Deserialized JSON object.
200
+ * @param {module:engine/model/document~Document} document Document on which this operation will be applied.
201
+ * @returns {module:engine/model/operation/mergeoperation~MergeOperation}
202
+ */
203
+ static fromJSON( json, document ) {
204
+ const sourcePosition = Position.fromJSON( json.sourcePosition, document );
205
+ const targetPosition = Position.fromJSON( json.targetPosition, document );
206
+ const graveyardPosition = Position.fromJSON( json.graveyardPosition, document );
207
+
208
+ return new this( sourcePosition, json.howMany, targetPosition, graveyardPosition, json.baseVersion );
209
+ }
210
+
211
+ // @if CK_DEBUG_ENGINE // toString() {
212
+ // @if CK_DEBUG_ENGINE // return `MergeOperation( ${ this.baseVersion } ): ` +
213
+ // @if CK_DEBUG_ENGINE // `${ this.sourcePosition } -> ${ this.targetPosition }` +
214
+ // @if CK_DEBUG_ENGINE // ` ( ${ this.howMany } ), ${ this.graveyardPosition }`;
215
+ // @if CK_DEBUG_ENGINE // }
216
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module engine/model/operation/moveoperation
8
+ */
9
+
10
+ import Operation from './operation';
11
+ import Position from '../position';
12
+ import Range from '../range';
13
+ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
14
+ import compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';
15
+ import { _move } from './utils';
16
+
17
+ // @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;
18
+
19
+ /**
20
+ * Operation to move a range of {@link module:engine/model/item~Item model items}
21
+ * to given {@link module:engine/model/position~Position target position}.
22
+ *
23
+ * @extends module:engine/model/operation/operation~Operation
24
+ */
25
+ export default class MoveOperation extends Operation {
26
+ /**
27
+ * Creates a move operation.
28
+ *
29
+ * @param {module:engine/model/position~Position} sourcePosition
30
+ * Position before the first {@link module:engine/model/item~Item model item} to move.
31
+ * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at
32
+ * `sourcePosition` with offset shifted by `howMany`.
33
+ * @param {module:engine/model/position~Position} targetPosition Position at which moved nodes will be inserted.
34
+ * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation
35
+ * can be applied or `null` if the operation operates on detached (non-document) tree.
36
+ */
37
+ constructor( sourcePosition, howMany, targetPosition, baseVersion ) {
38
+ super( baseVersion );
39
+
40
+ /**
41
+ * Position before the first {@link module:engine/model/item~Item model item} to move.
42
+ *
43
+ * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#sourcePosition
44
+ */
45
+ this.sourcePosition = sourcePosition.clone();
46
+ // `'toNext'` because `sourcePosition` is a bit like a start of the moved range.
47
+ this.sourcePosition.stickiness = 'toNext';
48
+
49
+ /**
50
+ * Offset size of moved range.
51
+ *
52
+ * @member {Number} module:engine/model/operation/moveoperation~MoveOperation#howMany
53
+ */
54
+ this.howMany = howMany;
55
+
56
+ /**
57
+ * Position at which moved nodes will be inserted.
58
+ *
59
+ * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#targetPosition
60
+ */
61
+ this.targetPosition = targetPosition.clone();
62
+ this.targetPosition.stickiness = 'toNone';
63
+ }
64
+
65
+ /**
66
+ * @inheritDoc
67
+ */
68
+ get type() {
69
+ if ( this.targetPosition.root.rootName == '$graveyard' ) {
70
+ return 'remove';
71
+ } else if ( this.sourcePosition.root.rootName == '$graveyard' ) {
72
+ return 'reinsert';
73
+ }
74
+
75
+ return 'move';
76
+ }
77
+
78
+ /**
79
+ * Creates and returns an operation that has the same parameters as this operation.
80
+ *
81
+ * @returns {module:engine/model/operation/moveoperation~MoveOperation} Clone of this operation.
82
+ */
83
+ clone() {
84
+ return new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.baseVersion );
85
+ }
86
+
87
+ /**
88
+ * Returns the start position of the moved range after it got moved. This may be different than
89
+ * {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition} in some cases, i.e. when a range is moved
90
+ * inside the same parent but {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition targetPosition}
91
+ * is after {@link module:engine/model/operation/moveoperation~MoveOperation#sourcePosition sourcePosition}.
92
+ *
93
+ * vv vv
94
+ * abcdefg ===> adefbcg
95
+ * ^ ^
96
+ * targetPos movedRangeStart
97
+ * offset 6 offset 4
98
+ *
99
+ * @returns {module:engine/model/position~Position}
100
+ */
101
+ getMovedRangeStart() {
102
+ return this.targetPosition._getTransformedByDeletion( this.sourcePosition, this.howMany );
103
+ }
104
+
105
+ /**
106
+ * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
107
+ *
108
+ * @returns {module:engine/model/operation/moveoperation~MoveOperation}
109
+ */
110
+ getReversed() {
111
+ const newTargetPosition = this.sourcePosition._getTransformedByInsertion( this.targetPosition, this.howMany );
112
+
113
+ return new this.constructor( this.getMovedRangeStart(), this.howMany, newTargetPosition, this.baseVersion + 1 );
114
+ }
115
+
116
+ /**
117
+ * @inheritDoc
118
+ */
119
+ _validate() {
120
+ const sourceElement = this.sourcePosition.parent;
121
+ const targetElement = this.targetPosition.parent;
122
+ const sourceOffset = this.sourcePosition.offset;
123
+ const targetOffset = this.targetPosition.offset;
124
+
125
+ // Validate whether move operation has correct parameters.
126
+ // Validation is pretty complex but move operation is one of the core ways to manipulate the document state.
127
+ // We expect that many errors might be connected with one of scenarios described below.
128
+ if ( sourceOffset + this.howMany > sourceElement.maxOffset ) {
129
+ /**
130
+ * The nodes which should be moved do not exist.
131
+ *
132
+ * @error move-operation-nodes-do-not-exist
133
+ */
134
+ throw new CKEditorError(
135
+ 'move-operation-nodes-do-not-exist', this
136
+ );
137
+ } else if ( sourceElement === targetElement && sourceOffset < targetOffset && targetOffset < sourceOffset + this.howMany ) {
138
+ /**
139
+ * Trying to move a range of nodes into the middle of that range.
140
+ *
141
+ * @error move-operation-range-into-itself
142
+ */
143
+ throw new CKEditorError(
144
+ 'move-operation-range-into-itself', this
145
+ );
146
+ } else if ( this.sourcePosition.root == this.targetPosition.root ) {
147
+ if ( compareArrays( this.sourcePosition.getParentPath(), this.targetPosition.getParentPath() ) == 'prefix' ) {
148
+ const i = this.sourcePosition.path.length - 1;
149
+
150
+ if ( this.targetPosition.path[ i ] >= sourceOffset && this.targetPosition.path[ i ] < sourceOffset + this.howMany ) {
151
+ /**
152
+ * Trying to move a range of nodes into one of nodes from that range.
153
+ *
154
+ * @error move-operation-node-into-itself
155
+ */
156
+ throw new CKEditorError(
157
+ 'move-operation-node-into-itself', this
158
+ );
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ /**
165
+ * @inheritDoc
166
+ */
167
+ _execute() {
168
+ _move( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );
169
+ }
170
+
171
+ /**
172
+ * @inheritDoc
173
+ */
174
+ toJSON() {
175
+ const json = super.toJSON();
176
+
177
+ json.sourcePosition = this.sourcePosition.toJSON();
178
+ json.targetPosition = this.targetPosition.toJSON();
179
+
180
+ return json;
181
+ }
182
+
183
+ /**
184
+ * @inheritDoc
185
+ */
186
+ static get className() {
187
+ return 'MoveOperation';
188
+ }
189
+
190
+ /**
191
+ * Creates `MoveOperation` object from deserilized object, i.e. from parsed JSON string.
192
+ *
193
+ * @param {Object} json Deserialized JSON object.
194
+ * @param {module:engine/model/document~Document} document Document on which this operation will be applied.
195
+ * @returns {module:engine/model/operation/moveoperation~MoveOperation}
196
+ */
197
+ static fromJSON( json, document ) {
198
+ const sourcePosition = Position.fromJSON( json.sourcePosition, document );
199
+ const targetPosition = Position.fromJSON( json.targetPosition, document );
200
+
201
+ return new this( sourcePosition, json.howMany, targetPosition, json.baseVersion );
202
+ }
203
+
204
+ // @if CK_DEBUG_ENGINE // toString() {
205
+ // @if CK_DEBUG_ENGINE // const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );
206
+
207
+ // @if CK_DEBUG_ENGINE // return `MoveOperation( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`;
208
+ // @if CK_DEBUG_ENGINE // }
209
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module engine/model/operation/nooperation
8
+ */
9
+
10
+ import Operation from './operation';
11
+
12
+ /**
13
+ * Operation which is doing nothing ("empty operation", "do-nothing operation", "noop"). This is an operation,
14
+ * which when executed does not change the tree model. It still has some parameters defined for transformation purposes.
15
+ *
16
+ * In most cases this operation is a result of transforming operations. When transformation returns
17
+ * {@link module:engine/model/operation/nooperation~NoOperation} it means that changes done by the transformed operation
18
+ * have already been applied.
19
+ *
20
+ * @extends module:engine/model/operation/operation~Operation
21
+ */
22
+ export default class NoOperation extends Operation {
23
+ get type() {
24
+ return 'noop';
25
+ }
26
+
27
+ /**
28
+ * Creates and returns an operation that has the same parameters as this operation.
29
+ *
30
+ * @returns {module:engine/model/operation/nooperation~NoOperation} Clone of this operation.
31
+ */
32
+ clone() {
33
+ return new NoOperation( this.baseVersion );
34
+ }
35
+
36
+ /**
37
+ * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
38
+ *
39
+ * @returns {module:engine/model/operation/nooperation~NoOperation}
40
+ */
41
+ getReversed() {
42
+ return new NoOperation( this.baseVersion + 1 );
43
+ }
44
+
45
+ _execute() {
46
+ }
47
+
48
+ /**
49
+ * @inheritDoc
50
+ */
51
+ static get className() {
52
+ return 'NoOperation';
53
+ }
54
+
55
+ // @if CK_DEBUG_ENGINE // toString() {
56
+ // @if CK_DEBUG_ENGINE // return `NoOperation( ${ this.baseVersion } )`;
57
+ // @if CK_DEBUG_ENGINE // }
58
+ }