@ckeditor/ckeditor5-engine 35.3.2 → 36.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.
- package/LICENSE.md +1 -1
- package/package.json +22 -22
- package/src/controller/datacontroller.js +10 -8
- package/src/controller/editingcontroller.js +3 -4
- package/src/conversion/conversion.js +2 -3
- package/src/conversion/conversionhelpers.js +1 -1
- package/src/conversion/downcastdispatcher.js +3 -3
- package/src/conversion/downcasthelpers.js +2 -3
- package/src/conversion/mapper.js +3 -4
- package/src/conversion/modelconsumable.js +2 -2
- package/src/conversion/upcastdispatcher.js +3 -4
- package/src/conversion/upcasthelpers.js +10 -3
- package/src/conversion/viewconsumable.js +2 -2
- package/src/dataprocessor/basichtmlwriter.js +1 -1
- package/src/dataprocessor/dataprocessor.js +1 -1
- package/src/dataprocessor/htmldataprocessor.js +3 -3
- package/src/dataprocessor/htmlwriter.js +1 -1
- package/src/dataprocessor/xmldataprocessor.js +6 -2
- package/src/dev-utils/model.js +3 -3
- package/src/dev-utils/operationreplayer.js +1 -1
- package/src/dev-utils/utils.js +1 -1
- package/src/dev-utils/view.js +1 -1
- package/src/index.js +13 -3
- package/src/model/batch.js +10 -47
- package/src/model/differ.js +81 -174
- package/src/model/document.js +38 -97
- package/src/model/documentfragment.js +44 -97
- package/src/model/documentselection.js +152 -251
- package/src/model/element.js +48 -101
- package/src/model/history.js +15 -46
- package/src/model/item.js +1 -1
- package/src/model/liveposition.js +11 -39
- package/src/model/liverange.js +14 -38
- package/src/model/markercollection.js +42 -115
- package/src/model/model.js +214 -292
- package/src/model/node.js +36 -128
- package/src/model/nodelist.js +12 -41
- package/src/model/operation/attributeoperation.js +14 -45
- package/src/model/operation/detachoperation.js +4 -17
- package/src/model/operation/insertoperation.js +7 -35
- package/src/model/operation/markeroperation.js +9 -48
- package/src/model/operation/mergeoperation.js +9 -42
- package/src/model/operation/moveoperation.js +15 -39
- package/src/model/operation/nooperation.js +1 -7
- package/src/model/operation/operation.js +5 -63
- package/src/model/operation/operationfactory.js +3 -6
- package/src/model/operation/renameoperation.js +9 -29
- package/src/model/operation/rootattributeoperation.js +19 -48
- package/src/model/operation/splitoperation.js +10 -48
- package/src/model/operation/transform.js +110 -151
- package/src/model/operation/utils.js +37 -52
- package/src/model/position.js +118 -230
- package/src/model/range.js +146 -202
- package/src/model/rootelement.js +8 -47
- package/src/model/schema.js +245 -282
- package/src/model/selection.js +135 -196
- package/src/model/text.js +10 -37
- package/src/model/textproxy.js +16 -70
- package/src/model/treewalker.js +11 -102
- package/src/model/typecheckable.js +1 -1
- package/src/model/utils/autoparagraphing.js +11 -12
- package/src/model/utils/deletecontent.js +93 -62
- package/src/model/utils/findoptimalinsertionrange.js +25 -25
- package/src/model/utils/getselectedcontent.js +3 -6
- package/src/model/utils/insertcontent.js +37 -130
- package/src/model/utils/insertobject.js +40 -40
- package/src/model/utils/modifyselection.js +24 -34
- package/src/model/utils/selection-post-fixer.js +53 -59
- package/src/model/writer.js +209 -316
- package/src/view/attributeelement.js +2 -2
- package/src/view/containerelement.js +1 -1
- package/src/view/datatransfer.js +1 -1
- package/src/view/document.js +3 -5
- package/src/view/documentfragment.js +50 -4
- package/src/view/documentselection.js +2 -3
- package/src/view/domconverter.js +4 -8
- package/src/view/downcastwriter.js +2 -3
- package/src/view/editableelement.js +2 -3
- package/src/view/element.js +6 -8
- package/src/view/elementdefinition.js +1 -1
- package/src/view/emptyelement.js +2 -2
- package/src/view/filler.js +2 -3
- package/src/view/item.js +1 -1
- package/src/view/matcher.js +2 -2
- package/src/view/node.js +2 -5
- package/src/view/observer/arrowkeysobserver.js +1 -1
- package/src/view/observer/bubblingemittermixin.js +3 -6
- package/src/view/observer/bubblingeventinfo.js +2 -2
- package/src/view/observer/clickobserver.js +1 -1
- package/src/view/observer/compositionobserver.js +1 -1
- package/src/view/observer/domeventdata.js +1 -1
- package/src/view/observer/domeventobserver.js +1 -1
- package/src/view/observer/fakeselectionobserver.js +2 -2
- package/src/view/observer/focusobserver.js +25 -3
- package/src/view/observer/inputobserver.js +2 -2
- package/src/view/observer/keyobserver.js +2 -2
- package/src/view/observer/mouseobserver.js +1 -1
- package/src/view/observer/mutationobserver.js +1 -1
- package/src/view/observer/observer.js +3 -3
- package/src/view/observer/selectionobserver.js +21 -3
- package/src/view/observer/tabobserver.js +2 -2
- package/src/view/placeholder.js +1 -1
- package/src/view/position.js +2 -3
- package/src/view/range.js +1 -1
- package/src/view/rawelement.js +2 -2
- package/src/view/renderer.js +3 -12
- package/src/view/rooteditableelement.js +1 -1
- package/src/view/selection.js +2 -6
- package/src/view/styles/background.js +1 -1
- package/src/view/styles/border.js +1 -1
- package/src/view/styles/margin.js +1 -1
- package/src/view/styles/padding.js +1 -1
- package/src/view/styles/utils.js +1 -1
- package/src/view/stylesmap.js +1 -1
- package/src/view/text.js +1 -1
- package/src/view/textproxy.js +2 -2
- package/src/view/treewalker.js +2 -2
- package/src/view/typecheckable.js +1 -1
- package/src/view/uielement.js +2 -3
- package/src/view/upcastwriter.js +1 -1
- package/src/view/view.js +7 -7
- package/theme/placeholder.css +1 -1
- package/theme/renderer.css +1 -1
package/src/model/node.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
@@ -7,9 +7,7 @@
|
|
|
7
7
|
* @module engine/model/node
|
|
8
8
|
*/
|
|
9
9
|
import TypeCheckable from './typecheckable';
|
|
10
|
-
import toMap from '@ckeditor/ckeditor5-utils
|
|
11
|
-
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
|
|
12
|
-
import compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';
|
|
10
|
+
import { CKEditorError, compareArrays, toMap } from '@ckeditor/ckeditor5-utils';
|
|
13
11
|
// To check if component is loaded more than once.
|
|
14
12
|
import '@ckeditor/ckeditor5-utils/src/version';
|
|
15
13
|
/**
|
|
@@ -46,8 +44,7 @@ export default class Node extends TypeCheckable {
|
|
|
46
44
|
*
|
|
47
45
|
* This is an abstract class, so this constructor should not be used directly.
|
|
48
46
|
*
|
|
49
|
-
* @
|
|
50
|
-
* @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
|
|
47
|
+
* @param attrs Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
|
|
51
48
|
*/
|
|
52
49
|
constructor(attrs) {
|
|
53
50
|
super();
|
|
@@ -55,24 +52,12 @@ export default class Node extends TypeCheckable {
|
|
|
55
52
|
* Parent of this node. It could be {@link module:engine/model/element~Element}
|
|
56
53
|
* or {@link module:engine/model/documentfragment~DocumentFragment}.
|
|
57
54
|
* Equals to `null` if the node has no parent.
|
|
58
|
-
*
|
|
59
|
-
* @readonly
|
|
60
|
-
* @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}
|
|
61
55
|
*/
|
|
62
56
|
this.parent = null;
|
|
63
|
-
/**
|
|
64
|
-
* Attributes set on this node.
|
|
65
|
-
*
|
|
66
|
-
* @private
|
|
67
|
-
* @member {Map} module:engine/model/node~Node#_attrs
|
|
68
|
-
*/
|
|
69
57
|
this._attrs = toMap(attrs);
|
|
70
58
|
}
|
|
71
59
|
/**
|
|
72
60
|
* {@link module:engine/model/document~Document Document} that owns this root element.
|
|
73
|
-
*
|
|
74
|
-
* @readonly
|
|
75
|
-
* @type {module:engine/model/document~Document|null}
|
|
76
61
|
*/
|
|
77
62
|
get document() {
|
|
78
63
|
return null;
|
|
@@ -82,9 +67,6 @@ export default class Node extends TypeCheckable {
|
|
|
82
67
|
*
|
|
83
68
|
* Accessing this property throws an error if this node's parent element does not contain it.
|
|
84
69
|
* This means that model tree got broken.
|
|
85
|
-
*
|
|
86
|
-
* @readonly
|
|
87
|
-
* @type {Number|null}
|
|
88
70
|
*/
|
|
89
71
|
get index() {
|
|
90
72
|
let pos;
|
|
@@ -102,9 +84,6 @@ export default class Node extends TypeCheckable {
|
|
|
102
84
|
*
|
|
103
85
|
* Accessing this property throws an error if this node's parent element does not contain it.
|
|
104
86
|
* This means that model tree got broken.
|
|
105
|
-
*
|
|
106
|
-
* @readonly
|
|
107
|
-
* @type {Number|null}
|
|
108
87
|
*/
|
|
109
88
|
get startOffset() {
|
|
110
89
|
let pos;
|
|
@@ -121,9 +100,6 @@ export default class Node extends TypeCheckable {
|
|
|
121
100
|
* It is important for {@link module:engine/model/position~Position position}. When node has `offsetSize` greater than `1`, position
|
|
122
101
|
* can be placed between that node start and end. `offsetSize` greater than `1` is for nodes that represents more
|
|
123
102
|
* than one entity, i.e. {@link module:engine/model/text~Text text node}.
|
|
124
|
-
*
|
|
125
|
-
* @readonly
|
|
126
|
-
* @type {Number}
|
|
127
103
|
*/
|
|
128
104
|
get offsetSize() {
|
|
129
105
|
return 1;
|
|
@@ -132,9 +108,6 @@ export default class Node extends TypeCheckable {
|
|
|
132
108
|
* Offset at which this node ends in it's parent. It is equal to the sum of this node's
|
|
133
109
|
* {@link module:engine/model/node~Node#startOffset start offset} and {@link #offsetSize offset size}.
|
|
134
110
|
* Equals to `null` if the node has no parent.
|
|
135
|
-
*
|
|
136
|
-
* @readonly
|
|
137
|
-
* @type {Number|null}
|
|
138
111
|
*/
|
|
139
112
|
get endOffset() {
|
|
140
113
|
if (!this.parent) {
|
|
@@ -144,9 +117,6 @@ export default class Node extends TypeCheckable {
|
|
|
144
117
|
}
|
|
145
118
|
/**
|
|
146
119
|
* Node's next sibling or `null` if the node is a last child of it's parent or if the node has no parent.
|
|
147
|
-
*
|
|
148
|
-
* @readonly
|
|
149
|
-
* @type {module:engine/model/node~Node|null}
|
|
150
120
|
*/
|
|
151
121
|
get nextSibling() {
|
|
152
122
|
const index = this.index;
|
|
@@ -154,9 +124,6 @@ export default class Node extends TypeCheckable {
|
|
|
154
124
|
}
|
|
155
125
|
/**
|
|
156
126
|
* Node's previous sibling or `null` if the node is a first child of it's parent or if the node has no parent.
|
|
157
|
-
*
|
|
158
|
-
* @readonly
|
|
159
|
-
* @type {module:engine/model/node~Node|null}
|
|
160
127
|
*/
|
|
161
128
|
get previousSibling() {
|
|
162
129
|
const index = this.index;
|
|
@@ -165,9 +132,6 @@ export default class Node extends TypeCheckable {
|
|
|
165
132
|
/**
|
|
166
133
|
* The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part
|
|
167
134
|
* of {@link module:engine/model/documentfragment~DocumentFragment}, it's `root` is equal to that `DocumentFragment`.
|
|
168
|
-
*
|
|
169
|
-
* @readonly
|
|
170
|
-
* @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}
|
|
171
135
|
*/
|
|
172
136
|
get root() {
|
|
173
137
|
// eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
|
|
@@ -179,8 +143,6 @@ export default class Node extends TypeCheckable {
|
|
|
179
143
|
}
|
|
180
144
|
/**
|
|
181
145
|
* Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).
|
|
182
|
-
*
|
|
183
|
-
* @returns {Boolean}
|
|
184
146
|
*/
|
|
185
147
|
isAttached() {
|
|
186
148
|
return this.root.is('rootElement');
|
|
@@ -190,16 +152,16 @@ export default class Node extends TypeCheckable {
|
|
|
190
152
|
* beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to
|
|
191
153
|
* create {@link module:engine/model/position~Position Position} instance.
|
|
192
154
|
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
155
|
+
* ```ts
|
|
156
|
+
* const abc = new Text( 'abc' );
|
|
157
|
+
* const foo = new Text( 'foo' );
|
|
158
|
+
* const h1 = new Element( 'h1', null, new Text( 'header' ) );
|
|
159
|
+
* const p = new Element( 'p', null, [ abc, foo ] );
|
|
160
|
+
* const div = new Element( 'div', null, [ h1, p ] );
|
|
161
|
+
* foo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.
|
|
162
|
+
* h1.getPath(); // Returns [ 0 ].
|
|
163
|
+
* div.getPath(); // Returns [].
|
|
164
|
+
* ```
|
|
203
165
|
*/
|
|
204
166
|
getPath() {
|
|
205
167
|
const path = [];
|
|
@@ -214,11 +176,11 @@ export default class Node extends TypeCheckable {
|
|
|
214
176
|
/**
|
|
215
177
|
* Returns ancestors array of this node.
|
|
216
178
|
*
|
|
217
|
-
* @param
|
|
218
|
-
* @param
|
|
219
|
-
* @param
|
|
179
|
+
* @param options Options object.
|
|
180
|
+
* @param options.includeSelf When set to `true` this node will be also included in parent's array.
|
|
181
|
+
* @param options.parentFirst When set to `true`, array will be sorted from node's parent to root element,
|
|
220
182
|
* otherwise root element will be the first item in the array.
|
|
221
|
-
* @returns
|
|
183
|
+
* @returns Array with ancestors.
|
|
222
184
|
*/
|
|
223
185
|
getAncestors(options = {}) {
|
|
224
186
|
const ancestors = [];
|
|
@@ -233,11 +195,10 @@ export default class Node extends TypeCheckable {
|
|
|
233
195
|
* Returns a {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}
|
|
234
196
|
* which is a common ancestor of both nodes.
|
|
235
197
|
*
|
|
236
|
-
* @param
|
|
237
|
-
* @param
|
|
238
|
-
* @param
|
|
198
|
+
* @param node The second node.
|
|
199
|
+
* @param options Options object.
|
|
200
|
+
* @param options.includeSelf When set to `true` both nodes will be considered "ancestors" too.
|
|
239
201
|
* Which means that if e.g. node A is inside B, then their common ancestor will be B.
|
|
240
|
-
* @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}
|
|
241
202
|
*/
|
|
242
203
|
getCommonAncestor(node, options = {}) {
|
|
243
204
|
const ancestorsA = this.getAncestors(options);
|
|
@@ -252,8 +213,7 @@ export default class Node extends TypeCheckable {
|
|
|
252
213
|
* Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,
|
|
253
214
|
* in different {@link module:engine/model/documentfragment~DocumentFragment}s).
|
|
254
215
|
*
|
|
255
|
-
* @param
|
|
256
|
-
* @returns {Boolean}
|
|
216
|
+
* @param node Node to compare with.
|
|
257
217
|
*/
|
|
258
218
|
isBefore(node) {
|
|
259
219
|
// Given node is not before this node if they are same.
|
|
@@ -280,8 +240,7 @@ export default class Node extends TypeCheckable {
|
|
|
280
240
|
* Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,
|
|
281
241
|
* in different {@link module:engine/model/documentfragment~DocumentFragment}s).
|
|
282
242
|
*
|
|
283
|
-
* @param
|
|
284
|
-
* @returns {Boolean}
|
|
243
|
+
* @param node Node to compare with.
|
|
285
244
|
*/
|
|
286
245
|
isAfter(node) {
|
|
287
246
|
// Given node is not before this node if they are same.
|
|
@@ -298,8 +257,8 @@ export default class Node extends TypeCheckable {
|
|
|
298
257
|
/**
|
|
299
258
|
* Checks if the node has an attribute with given key.
|
|
300
259
|
*
|
|
301
|
-
* @param
|
|
302
|
-
* @returns
|
|
260
|
+
* @param key Key of attribute to check.
|
|
261
|
+
* @returns `true` if attribute with given key is set on node, `false` otherwise.
|
|
303
262
|
*/
|
|
304
263
|
hasAttribute(key) {
|
|
305
264
|
return this._attrs.has(key);
|
|
@@ -307,8 +266,8 @@ export default class Node extends TypeCheckable {
|
|
|
307
266
|
/**
|
|
308
267
|
* Gets an attribute value for given key or `undefined` if that attribute is not set on node.
|
|
309
268
|
*
|
|
310
|
-
* @param
|
|
311
|
-
* @returns
|
|
269
|
+
* @param key Key of attribute to look for.
|
|
270
|
+
* @returns Attribute value or `undefined`.
|
|
312
271
|
*/
|
|
313
272
|
getAttribute(key) {
|
|
314
273
|
return this._attrs.get(key);
|
|
@@ -318,16 +277,12 @@ export default class Node extends TypeCheckable {
|
|
|
318
277
|
*
|
|
319
278
|
* Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
|
|
320
279
|
* This format is accepted by native `Map` object and also can be passed in `Node` constructor.
|
|
321
|
-
*
|
|
322
|
-
* @returns {Iterable.<*>}
|
|
323
280
|
*/
|
|
324
281
|
getAttributes() {
|
|
325
282
|
return this._attrs.entries();
|
|
326
283
|
}
|
|
327
284
|
/**
|
|
328
285
|
* Returns iterator that iterates over this node's attribute keys.
|
|
329
|
-
*
|
|
330
|
-
* @returns {Iterable.<String>}
|
|
331
286
|
*/
|
|
332
287
|
getAttributeKeys() {
|
|
333
288
|
return this._attrs.keys();
|
|
@@ -335,7 +290,7 @@ export default class Node extends TypeCheckable {
|
|
|
335
290
|
/**
|
|
336
291
|
* Converts `Node` to plain object and returns it.
|
|
337
292
|
*
|
|
338
|
-
* @returns
|
|
293
|
+
* @returns `Node` converted to plain object.
|
|
339
294
|
*/
|
|
340
295
|
toJSON() {
|
|
341
296
|
const json = {};
|
|
@@ -353,18 +308,16 @@ export default class Node extends TypeCheckable {
|
|
|
353
308
|
* Creates a copy of this node, that is a node with exactly same attributes, and returns it.
|
|
354
309
|
*
|
|
355
310
|
* @internal
|
|
356
|
-
* @
|
|
357
|
-
* @returns {module:engine/model/node~Node} Node with same attributes as this node.
|
|
311
|
+
* @returns Node with same attributes as this node.
|
|
358
312
|
*/
|
|
359
313
|
_clone(_deep) {
|
|
360
|
-
return new
|
|
314
|
+
return new this.constructor(this._attrs);
|
|
361
315
|
}
|
|
362
316
|
/**
|
|
363
317
|
* Removes this node from it's parent.
|
|
364
318
|
*
|
|
365
319
|
* @internal
|
|
366
320
|
* @see module:engine/model/writer~Writer#remove
|
|
367
|
-
* @protected
|
|
368
321
|
*/
|
|
369
322
|
_remove() {
|
|
370
323
|
this.parent._removeChildren(this.index);
|
|
@@ -374,9 +327,8 @@ export default class Node extends TypeCheckable {
|
|
|
374
327
|
*
|
|
375
328
|
* @see module:engine/model/writer~Writer#setAttribute
|
|
376
329
|
* @internal
|
|
377
|
-
* @
|
|
378
|
-
* @param
|
|
379
|
-
* @param {*} value Attribute value.
|
|
330
|
+
* @param key Key of attribute to set.
|
|
331
|
+
* @param value Attribute value.
|
|
380
332
|
*/
|
|
381
333
|
_setAttribute(key, value) {
|
|
382
334
|
this._attrs.set(key, value);
|
|
@@ -386,8 +338,7 @@ export default class Node extends TypeCheckable {
|
|
|
386
338
|
*
|
|
387
339
|
* @see module:engine/model/writer~Writer#setAttributes
|
|
388
340
|
* @internal
|
|
389
|
-
* @
|
|
390
|
-
* @param {Object} [attrs] Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.
|
|
341
|
+
* @param attrs Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.
|
|
391
342
|
*/
|
|
392
343
|
_setAttributesTo(attrs) {
|
|
393
344
|
this._attrs = toMap(attrs);
|
|
@@ -397,9 +348,8 @@ export default class Node extends TypeCheckable {
|
|
|
397
348
|
*
|
|
398
349
|
* @see module:engine/model/writer~Writer#removeAttribute
|
|
399
350
|
* @internal
|
|
400
|
-
* @
|
|
401
|
-
* @
|
|
402
|
-
* @returns {Boolean} `true` if the attribute was set on the element, `false` otherwise.
|
|
351
|
+
* @param key Key of attribute to remove.
|
|
352
|
+
* @returns `true` if the attribute was set on the element, `false` otherwise.
|
|
403
353
|
*/
|
|
404
354
|
_removeAttribute(key) {
|
|
405
355
|
return this._attrs.delete(key);
|
|
@@ -409,55 +359,13 @@ export default class Node extends TypeCheckable {
|
|
|
409
359
|
*
|
|
410
360
|
* @see module:engine/model/writer~Writer#clearAttributes
|
|
411
361
|
* @internal
|
|
412
|
-
* @protected
|
|
413
362
|
*/
|
|
414
363
|
_clearAttributes() {
|
|
415
364
|
this._attrs.clear();
|
|
416
365
|
}
|
|
417
366
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
*
|
|
421
|
-
* This method is useful when processing model objects that are of unknown type. For example, a function
|
|
422
|
-
* may return a {@link module:engine/model/documentfragment~DocumentFragment} or a {@link module:engine/model/node~Node}
|
|
423
|
-
* that can be either a text node or an element. This method can be used to check what kind of object is returned.
|
|
424
|
-
*
|
|
425
|
-
* someObject.is( 'element' ); // -> true if this is an element
|
|
426
|
-
* someObject.is( 'node' ); // -> true if this is a node (a text node or an element)
|
|
427
|
-
* someObject.is( 'documentFragment' ); // -> true if this is a document fragment
|
|
428
|
-
*
|
|
429
|
-
* Since this method is also available on a range of view objects, you can prefix the type of the object with
|
|
430
|
-
* `model:` or `view:` to check, for example, if this is the model's or view's element:
|
|
431
|
-
*
|
|
432
|
-
* modelElement.is( 'model:element' ); // -> true
|
|
433
|
-
* modelElement.is( 'view:element' ); // -> false
|
|
434
|
-
*
|
|
435
|
-
* By using this method it is also possible to check a name of an element:
|
|
436
|
-
*
|
|
437
|
-
* imageElement.is( 'element', 'imageBlock' ); // -> true
|
|
438
|
-
* imageElement.is( 'element', 'imageBlock' ); // -> same as above
|
|
439
|
-
* imageElement.is( 'model:element', 'imageBlock' ); // -> same as above, but more precise
|
|
440
|
-
*
|
|
441
|
-
* The list of model objects which implement the `is()` method:
|
|
442
|
-
*
|
|
443
|
-
* * {@link module:engine/model/node~Node#is `Node#is()`}
|
|
444
|
-
* * {@link module:engine/model/text~Text#is `Text#is()`}
|
|
445
|
-
* * {@link module:engine/model/element~Element#is `Element#is()`}
|
|
446
|
-
* * {@link module:engine/model/rootelement~RootElement#is `RootElement#is()`}
|
|
447
|
-
* * {@link module:engine/model/position~Position#is `Position#is()`}
|
|
448
|
-
* * {@link module:engine/model/liveposition~LivePosition#is `LivePosition#is()`}
|
|
449
|
-
* * {@link module:engine/model/range~Range#is `Range#is()`}
|
|
450
|
-
* * {@link module:engine/model/liverange~LiveRange#is `LiveRange#is()`}
|
|
451
|
-
* * {@link module:engine/model/documentfragment~DocumentFragment#is `DocumentFragment#is()`}
|
|
452
|
-
* * {@link module:engine/model/selection~Selection#is `Selection#is()`}
|
|
453
|
-
* * {@link module:engine/model/documentselection~DocumentSelection#is `DocumentSelection#is()`}
|
|
454
|
-
* * {@link module:engine/model/markercollection~Marker#is `Marker#is()`}
|
|
455
|
-
* * {@link module:engine/model/textproxy~TextProxy#is `TextProxy#is()`}
|
|
456
|
-
*
|
|
457
|
-
* @method #is
|
|
458
|
-
* @param {String} type Type to check.
|
|
459
|
-
* @returns {Boolean}
|
|
460
|
-
*/
|
|
367
|
+
// The magic of type inference using `is` method is centralized in `TypeCheckable` class.
|
|
368
|
+
// Proper overload would interfere with that.
|
|
461
369
|
Node.prototype.is = function (type) {
|
|
462
370
|
return type === 'node' || type === 'model:node';
|
|
463
371
|
};
|
package/src/model/nodelist.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
6
|
* @module engine/model/nodelist
|
|
7
7
|
*/
|
|
8
8
|
import Node from './node';
|
|
9
|
-
import CKEditorError from '@ckeditor/ckeditor5-utils
|
|
10
|
-
import spliceArray from '@ckeditor/ckeditor5-utils/src/splicearray';
|
|
9
|
+
import { CKEditorError, spliceArray } from '@ckeditor/ckeditor5-utils';
|
|
11
10
|
/**
|
|
12
11
|
* Provides an interface to operate on a list of {@link module:engine/model/node~Node nodes}. `NodeList` is used internally
|
|
13
12
|
* in classes like {@link module:engine/model/element~Element Element}
|
|
@@ -17,15 +16,12 @@ export default class NodeList {
|
|
|
17
16
|
/**
|
|
18
17
|
* Creates an empty node list.
|
|
19
18
|
*
|
|
20
|
-
* @
|
|
21
|
-
* @param
|
|
19
|
+
* @internal
|
|
20
|
+
* @param nodes Nodes contained in this node list.
|
|
22
21
|
*/
|
|
23
22
|
constructor(nodes) {
|
|
24
23
|
/**
|
|
25
24
|
* Nodes contained in this node list.
|
|
26
|
-
*
|
|
27
|
-
* @private
|
|
28
|
-
* @member {Array.<module:engine/model/node~Node>}
|
|
29
25
|
*/
|
|
30
26
|
this._nodes = [];
|
|
31
27
|
if (nodes) {
|
|
@@ -36,44 +32,30 @@ export default class NodeList {
|
|
|
36
32
|
* Iterable interface.
|
|
37
33
|
*
|
|
38
34
|
* Iterates over all nodes contained inside this node list.
|
|
39
|
-
*
|
|
40
|
-
* @returns {Iterator.<module:engine/model/node~Node>}
|
|
41
35
|
*/
|
|
42
36
|
[Symbol.iterator]() {
|
|
43
37
|
return this._nodes[Symbol.iterator]();
|
|
44
38
|
}
|
|
45
39
|
/**
|
|
46
40
|
* Number of nodes contained inside this node list.
|
|
47
|
-
*
|
|
48
|
-
* @readonly
|
|
49
|
-
* @type {Number}
|
|
50
41
|
*/
|
|
51
42
|
get length() {
|
|
52
43
|
return this._nodes.length;
|
|
53
44
|
}
|
|
54
45
|
/**
|
|
55
46
|
* Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes contained inside this node list.
|
|
56
|
-
*
|
|
57
|
-
* @readonly
|
|
58
|
-
* @type {Number}
|
|
59
47
|
*/
|
|
60
48
|
get maxOffset() {
|
|
61
49
|
return this._nodes.reduce((sum, node) => sum + node.offsetSize, 0);
|
|
62
50
|
}
|
|
63
51
|
/**
|
|
64
52
|
* Gets the node at the given index. Returns `null` if incorrect index was passed.
|
|
65
|
-
*
|
|
66
|
-
* @param {Number} index Index of node.
|
|
67
|
-
* @returns {module:engine/model/node~Node|null} Node at given index.
|
|
68
53
|
*/
|
|
69
54
|
getNode(index) {
|
|
70
55
|
return this._nodes[index] || null;
|
|
71
56
|
}
|
|
72
57
|
/**
|
|
73
58
|
* Returns an index of the given node. Returns `null` if given node is not inside this node list.
|
|
74
|
-
*
|
|
75
|
-
* @param {module:engine/model/node~Node} node Child node to look for.
|
|
76
|
-
* @returns {Number|null} Child node's index.
|
|
77
59
|
*/
|
|
78
60
|
getNodeIndex(node) {
|
|
79
61
|
const index = this._nodes.indexOf(node);
|
|
@@ -82,9 +64,6 @@ export default class NodeList {
|
|
|
82
64
|
/**
|
|
83
65
|
* Returns the starting offset of given node. Starting offset is equal to the sum of
|
|
84
66
|
* {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes that are before this node in this node list.
|
|
85
|
-
*
|
|
86
|
-
* @param {module:engine/model/node~Node} node Node to look for.
|
|
87
|
-
* @returns {Number|null} Node's starting offset.
|
|
88
67
|
*/
|
|
89
68
|
getNodeStartOffset(node) {
|
|
90
69
|
const index = this.getNodeIndex(node);
|
|
@@ -95,9 +74,6 @@ export default class NodeList {
|
|
|
95
74
|
*
|
|
96
75
|
* Returns starting offset of a node that is at given index. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
|
|
97
76
|
* `model-nodelist-index-out-of-bounds` if given index is less than `0` or more than {@link #length}.
|
|
98
|
-
*
|
|
99
|
-
* @param {Number} index Node's index.
|
|
100
|
-
* @returns {Number} Node's starting offset.
|
|
101
77
|
*/
|
|
102
78
|
indexToOffset(index) {
|
|
103
79
|
if (index == this._nodes.length) {
|
|
@@ -119,9 +95,6 @@ export default class NodeList {
|
|
|
119
95
|
*
|
|
120
96
|
* Returns index of a node that occupies given offset. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
|
|
121
97
|
* `model-nodelist-offset-out-of-bounds` if given offset is less than `0` or more than {@link #maxOffset}.
|
|
122
|
-
*
|
|
123
|
-
* @param {Number} offset Offset to look for.
|
|
124
|
-
* @returns {Number} Index of a node that occupies given offset.
|
|
125
98
|
*/
|
|
126
99
|
offsetToIndex(offset) {
|
|
127
100
|
let totalOffset = 0;
|
|
@@ -136,8 +109,8 @@ export default class NodeList {
|
|
|
136
109
|
* Given offset cannot be found in the node list.
|
|
137
110
|
*
|
|
138
111
|
* @error model-nodelist-offset-out-of-bounds
|
|
139
|
-
* @param
|
|
140
|
-
* @param
|
|
112
|
+
* @param offset
|
|
113
|
+
* @param nodeList Stringified node list.
|
|
141
114
|
*/
|
|
142
115
|
throw new CKEditorError('model-nodelist-offset-out-of-bounds', this, {
|
|
143
116
|
offset,
|
|
@@ -150,9 +123,8 @@ export default class NodeList {
|
|
|
150
123
|
* Inserts given nodes at given index.
|
|
151
124
|
*
|
|
152
125
|
* @internal
|
|
153
|
-
* @
|
|
154
|
-
* @param
|
|
155
|
-
* @param {Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.
|
|
126
|
+
* @param index Index at which nodes should be inserted.
|
|
127
|
+
* @param nodes Nodes to be inserted.
|
|
156
128
|
*/
|
|
157
129
|
_insertNodes(index, nodes) {
|
|
158
130
|
// Validation.
|
|
@@ -172,10 +144,9 @@ export default class NodeList {
|
|
|
172
144
|
* Removes one or more nodes starting at the given index.
|
|
173
145
|
*
|
|
174
146
|
* @internal
|
|
175
|
-
* @
|
|
176
|
-
* @param
|
|
177
|
-
* @
|
|
178
|
-
* @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.
|
|
147
|
+
* @param indexStart Index of the first node to remove.
|
|
148
|
+
* @param howMany Number of nodes to remove.
|
|
149
|
+
* @returns Array containing removed nodes.
|
|
179
150
|
*/
|
|
180
151
|
_removeNodes(indexStart, howMany = 1) {
|
|
181
152
|
return this._nodes.splice(indexStart, howMany);
|
|
@@ -184,7 +155,7 @@ export default class NodeList {
|
|
|
184
155
|
* Converts `NodeList` instance to an array containing nodes that were inserted in the node list. Nodes
|
|
185
156
|
* are also converted to their plain object representation.
|
|
186
157
|
*
|
|
187
|
-
* @returns
|
|
158
|
+
* @returns `NodeList` instance converted to `Array`.
|
|
188
159
|
*/
|
|
189
160
|
toJSON() {
|
|
190
161
|
return this._nodes.map(node => node.toJSON());
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
@@ -8,14 +8,12 @@
|
|
|
8
8
|
import Operation from './operation';
|
|
9
9
|
import { _setAttribute } from './utils';
|
|
10
10
|
import Range from '../range';
|
|
11
|
-
import CKEditorError from '@ckeditor/ckeditor5-utils
|
|
11
|
+
import { CKEditorError } from '@ckeditor/ckeditor5-utils';
|
|
12
12
|
import { isEqual } from 'lodash-es';
|
|
13
13
|
/**
|
|
14
14
|
* Operation to change nodes' attribute.
|
|
15
15
|
*
|
|
16
16
|
* Using this class you can add, remove or change value of the attribute.
|
|
17
|
-
*
|
|
18
|
-
* @extends module:engine/model/operation/operation~Operation
|
|
19
17
|
*/
|
|
20
18
|
export default class AttributeOperation extends Operation {
|
|
21
19
|
/**
|
|
@@ -30,42 +28,18 @@ export default class AttributeOperation extends Operation {
|
|
|
30
28
|
* If both `newValue` and `oldValue` are set, then the operation will change the attribute value. Note that all nodes in
|
|
31
29
|
* operation's ranges must already have an attribute with given key and `oldValue` as value
|
|
32
30
|
*
|
|
33
|
-
* @param
|
|
34
|
-
* @param
|
|
35
|
-
* @param
|
|
36
|
-
* @param
|
|
37
|
-
* @param
|
|
31
|
+
* @param range Range on which the operation should be applied. Must be a flat range.
|
|
32
|
+
* @param key Key of an attribute to change or remove.
|
|
33
|
+
* @param oldValue Old value of the attribute with given key or `null`, if attribute was not set before.
|
|
34
|
+
* @param newValue New value of the attribute with given key or `null`, if operation should remove attribute.
|
|
35
|
+
* @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
|
|
38
36
|
* can be applied or `null` if the operation operates on detached (non-document) tree.
|
|
39
37
|
*/
|
|
40
38
|
constructor(range, key, oldValue, newValue, baseVersion) {
|
|
41
39
|
super(baseVersion);
|
|
42
|
-
/**
|
|
43
|
-
* Range on which operation should be applied.
|
|
44
|
-
*
|
|
45
|
-
* @readonly
|
|
46
|
-
* @member {module:engine/model/range~Range}
|
|
47
|
-
*/
|
|
48
40
|
this.range = range.clone();
|
|
49
|
-
/**
|
|
50
|
-
* Key of an attribute to change or remove.
|
|
51
|
-
*
|
|
52
|
-
* @readonly
|
|
53
|
-
* @member {String}
|
|
54
|
-
*/
|
|
55
41
|
this.key = key;
|
|
56
|
-
/**
|
|
57
|
-
* Old value of the attribute with given key or `null`, if attribute was not set before.
|
|
58
|
-
*
|
|
59
|
-
* @readonly
|
|
60
|
-
* @member {*}
|
|
61
|
-
*/
|
|
62
42
|
this.oldValue = oldValue === undefined ? null : oldValue;
|
|
63
|
-
/**
|
|
64
|
-
* New value of the attribute with given key or `null`, if operation should remove attribute.
|
|
65
|
-
*
|
|
66
|
-
* @readonly
|
|
67
|
-
* @member {*}
|
|
68
|
-
*/
|
|
69
43
|
this.newValue = newValue === undefined ? null : newValue;
|
|
70
44
|
}
|
|
71
45
|
/**
|
|
@@ -84,16 +58,12 @@ export default class AttributeOperation extends Operation {
|
|
|
84
58
|
}
|
|
85
59
|
/**
|
|
86
60
|
* Creates and returns an operation that has the same parameters as this operation.
|
|
87
|
-
*
|
|
88
|
-
* @returns {module:engine/model/operation/attributeoperation~AttributeOperation} Clone of this operation.
|
|
89
61
|
*/
|
|
90
62
|
clone() {
|
|
91
63
|
return new AttributeOperation(this.range, this.key, this.oldValue, this.newValue, this.baseVersion);
|
|
92
64
|
}
|
|
93
65
|
/**
|
|
94
66
|
* See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
|
|
95
|
-
*
|
|
96
|
-
* @returns {module:engine/model/operation/attributeoperation~AttributeOperation}
|
|
97
67
|
*/
|
|
98
68
|
getReversed() {
|
|
99
69
|
return new AttributeOperation(this.range, this.key, this.newValue, this.oldValue, this.baseVersion + 1);
|
|
@@ -125,9 +95,9 @@ export default class AttributeOperation extends Operation {
|
|
|
125
95
|
* Changed node has different attribute value than operation's old attribute value.
|
|
126
96
|
*
|
|
127
97
|
* @error attribute-operation-wrong-old-value
|
|
128
|
-
* @param
|
|
129
|
-
* @param
|
|
130
|
-
* @param
|
|
98
|
+
* @param item
|
|
99
|
+
* @param key
|
|
100
|
+
* @param value
|
|
131
101
|
*/
|
|
132
102
|
throw new CKEditorError('attribute-operation-wrong-old-value', this, { item, key: this.key, value: this.oldValue });
|
|
133
103
|
}
|
|
@@ -136,8 +106,8 @@ export default class AttributeOperation extends Operation {
|
|
|
136
106
|
* The attribute with given key already exists for the given node.
|
|
137
107
|
*
|
|
138
108
|
* @error attribute-operation-attribute-exists
|
|
139
|
-
* @param
|
|
140
|
-
* @param
|
|
109
|
+
* @param node
|
|
110
|
+
* @param key
|
|
141
111
|
*/
|
|
142
112
|
throw new CKEditorError('attribute-operation-attribute-exists', this, { node: item, key: this.key });
|
|
143
113
|
}
|
|
@@ -163,9 +133,8 @@ export default class AttributeOperation extends Operation {
|
|
|
163
133
|
/**
|
|
164
134
|
* Creates `AttributeOperation` object from deserilized object, i.e. from parsed JSON string.
|
|
165
135
|
*
|
|
166
|
-
* @param
|
|
167
|
-
* @param
|
|
168
|
-
* @returns {module:engine/model/operation/attributeoperation~AttributeOperation}
|
|
136
|
+
* @param json Deserialized JSON object.
|
|
137
|
+
* @param document Document on which this operation will be applied.
|
|
169
138
|
*/
|
|
170
139
|
static fromJSON(json, document) {
|
|
171
140
|
return new AttributeOperation(Range.fromJSON(json.range, document), json.key, json.oldValue, json.newValue, json.baseVersion);
|