@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/document.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
|
/**
|
|
@@ -9,10 +9,7 @@ import Differ from './differ';
|
|
|
9
9
|
import DocumentSelection from './documentselection';
|
|
10
10
|
import History from './history';
|
|
11
11
|
import RootElement from './rootelement';
|
|
12
|
-
import Collection from '@ckeditor/ckeditor5-utils
|
|
13
|
-
import { Emitter } from '@ckeditor/ckeditor5-utils/src/emittermixin';
|
|
14
|
-
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
|
|
15
|
-
import { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';
|
|
12
|
+
import { CKEditorError, Collection, EmitterMixin, isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils';
|
|
16
13
|
import { clone } from 'lodash-es';
|
|
17
14
|
// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );
|
|
18
15
|
const graveyardName = '$graveyard';
|
|
@@ -25,69 +22,26 @@ const graveyardName = '$graveyard';
|
|
|
25
22
|
* Usually, the document contains just one {@link module:engine/model/document~Document#roots root element}, so
|
|
26
23
|
* you can retrieve it by just calling {@link module:engine/model/document~Document#getRoot} without specifying its name:
|
|
27
24
|
*
|
|
28
|
-
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* model.document.getRoot(); // -> returns the main root
|
|
27
|
+
* ```
|
|
29
28
|
*
|
|
30
29
|
* However, the document may contain multiple roots – e.g. when the editor has multiple editable areas
|
|
31
30
|
* (e.g. a title and a body of a message).
|
|
32
|
-
*
|
|
33
|
-
* @mixes module:utils/emittermixin~EmitterMixin
|
|
34
31
|
*/
|
|
35
|
-
export default class Document extends
|
|
32
|
+
export default class Document extends EmitterMixin() {
|
|
36
33
|
/**
|
|
37
34
|
* Creates an empty document instance with no {@link #roots} (other than
|
|
38
35
|
* the {@link #graveyard graveyard root}).
|
|
39
36
|
*/
|
|
40
37
|
constructor(model) {
|
|
41
38
|
super();
|
|
42
|
-
/**
|
|
43
|
-
* The {@link module:engine/model/model~Model model} that the document is a part of.
|
|
44
|
-
*
|
|
45
|
-
* @readonly
|
|
46
|
-
* @type {module:engine/model/model~Model}
|
|
47
|
-
*/
|
|
48
39
|
this.model = model;
|
|
49
|
-
/**
|
|
50
|
-
* The document's history.
|
|
51
|
-
*
|
|
52
|
-
* @readonly
|
|
53
|
-
* @type {module:engine/model/history~History}
|
|
54
|
-
*/
|
|
55
40
|
this.history = new History();
|
|
56
|
-
/**
|
|
57
|
-
* The selection in this document.
|
|
58
|
-
*
|
|
59
|
-
* @readonly
|
|
60
|
-
* @type {module:engine/model/documentselection~DocumentSelection}
|
|
61
|
-
*/
|
|
62
41
|
this.selection = new DocumentSelection(this);
|
|
63
|
-
/**
|
|
64
|
-
* A list of roots that are owned and managed by this document. Use {@link #createRoot} and
|
|
65
|
-
* {@link #getRoot} to manipulate it.
|
|
66
|
-
*
|
|
67
|
-
* @readonly
|
|
68
|
-
* @type {module:utils/collection~Collection}
|
|
69
|
-
*/
|
|
70
42
|
this.roots = new Collection({ idProperty: 'rootName' });
|
|
71
|
-
/**
|
|
72
|
-
* The model differ object. Its role is to buffer changes done on the model document and then calculate a diff of those changes.
|
|
73
|
-
*
|
|
74
|
-
* @readonly
|
|
75
|
-
* @type {module:engine/model/differ~Differ}
|
|
76
|
-
*/
|
|
77
43
|
this.differ = new Differ(model.markers);
|
|
78
|
-
/**
|
|
79
|
-
* Post-fixer callbacks registered to the model document.
|
|
80
|
-
*
|
|
81
|
-
* @private
|
|
82
|
-
* @type {Set.<Function>}
|
|
83
|
-
*/
|
|
84
44
|
this._postFixers = new Set();
|
|
85
|
-
/**
|
|
86
|
-
* A boolean indicates whether the selection has changed until
|
|
87
|
-
*
|
|
88
|
-
* @private
|
|
89
|
-
* @type {Boolean}
|
|
90
|
-
*/
|
|
91
45
|
this._hasSelectionChangedFromTheLastChangeBlock = false;
|
|
92
46
|
// Graveyard tree root. Document always have a graveyard root, which stores removed nodes.
|
|
93
47
|
this.createRoot('$root', graveyardName);
|
|
@@ -134,8 +88,6 @@ export default class Document extends Emitter {
|
|
|
134
88
|
*
|
|
135
89
|
* If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,
|
|
136
90
|
* a {@link module:utils/ckeditorerror~CKEditorError model-document-applyoperation-wrong-version} error is thrown.
|
|
137
|
-
*
|
|
138
|
-
* @type {Number}
|
|
139
91
|
*/
|
|
140
92
|
get version() {
|
|
141
93
|
return this.history.version;
|
|
@@ -145,9 +97,6 @@ export default class Document extends Emitter {
|
|
|
145
97
|
}
|
|
146
98
|
/**
|
|
147
99
|
* The graveyard tree root. A document always has a graveyard root that stores removed nodes.
|
|
148
|
-
*
|
|
149
|
-
* @readonly
|
|
150
|
-
* @member {module:engine/model/rootelement~RootElement}
|
|
151
100
|
*/
|
|
152
101
|
get graveyard() {
|
|
153
102
|
return this.getRoot(graveyardName);
|
|
@@ -155,10 +104,10 @@ export default class Document extends Emitter {
|
|
|
155
104
|
/**
|
|
156
105
|
* Creates a new root.
|
|
157
106
|
*
|
|
158
|
-
* @param
|
|
107
|
+
* @param elementName The element name. Defaults to `'$root'` which also has some basic schema defined
|
|
159
108
|
* (`$block`s are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.
|
|
160
|
-
* @param
|
|
161
|
-
* @returns
|
|
109
|
+
* @param rootName A unique root name.
|
|
110
|
+
* @returns The created root.
|
|
162
111
|
*/
|
|
163
112
|
createRoot(elementName = '$root', rootName = 'main') {
|
|
164
113
|
if (this.roots.get(rootName)) {
|
|
@@ -166,8 +115,6 @@ export default class Document extends Emitter {
|
|
|
166
115
|
* A root with the specified name already exists.
|
|
167
116
|
*
|
|
168
117
|
* @error model-document-createroot-name-exists
|
|
169
|
-
* @param {module:engine/model/document~Document} doc
|
|
170
|
-
* @param {String} name
|
|
171
118
|
*/
|
|
172
119
|
throw new CKEditorError('model-document-createroot-name-exists', this, { name: rootName });
|
|
173
120
|
}
|
|
@@ -185,9 +132,8 @@ export default class Document extends Emitter {
|
|
|
185
132
|
/**
|
|
186
133
|
* Returns a root by its name.
|
|
187
134
|
*
|
|
188
|
-
* @param
|
|
189
|
-
* @returns
|
|
190
|
-
* there is no root with the given name.
|
|
135
|
+
* @param name A unique root name.
|
|
136
|
+
* @returns The root registered under a given name or `null` when there is no root with the given name.
|
|
191
137
|
*/
|
|
192
138
|
getRoot(name = 'main') {
|
|
193
139
|
return this.roots.get(name);
|
|
@@ -195,7 +141,7 @@ export default class Document extends Emitter {
|
|
|
195
141
|
/**
|
|
196
142
|
* Returns an array with names of all roots (without the {@link #graveyard}) added to the document.
|
|
197
143
|
*
|
|
198
|
-
* @returns
|
|
144
|
+
* @returns Roots names.
|
|
199
145
|
*/
|
|
200
146
|
getRootNames() {
|
|
201
147
|
return Array.from(this.roots, root => root.rootName).filter(name => name != graveyardName);
|
|
@@ -218,24 +164,24 @@ export default class Document extends Emitter {
|
|
|
218
164
|
* An example of a post-fixer is a callback that checks if all the data were removed from the editor. If so, the
|
|
219
165
|
* callback should add an empty paragraph so that the editor is never empty:
|
|
220
166
|
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
167
|
+
* ```ts
|
|
168
|
+
* document.registerPostFixer( writer => {
|
|
169
|
+
* const changes = document.differ.getChanges();
|
|
223
170
|
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
171
|
+
* // Check if the changes lead to an empty root in the editor.
|
|
172
|
+
* for ( const entry of changes ) {
|
|
173
|
+
* if ( entry.type == 'remove' && entry.position.root.isEmpty ) {
|
|
174
|
+
* writer.insertElement( 'paragraph', entry.position.root, 0 );
|
|
228
175
|
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
176
|
+
* // It is fine to return early, even if multiple roots would need to be fixed.
|
|
177
|
+
* // All post-fixers will be fired again, so if there are more empty roots, those will be fixed, too.
|
|
178
|
+
* return true;
|
|
179
|
+
* }
|
|
180
|
+
* }
|
|
234
181
|
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
* @param {Function} postFixer
|
|
182
|
+
* return false;
|
|
183
|
+
* } );
|
|
184
|
+
* ```
|
|
239
185
|
*/
|
|
240
186
|
registerPostFixer(postFixer) {
|
|
241
187
|
this._postFixers.add(postFixer);
|
|
@@ -243,7 +189,7 @@ export default class Document extends Emitter {
|
|
|
243
189
|
/**
|
|
244
190
|
* A custom `toJSON()` method to solve child-parent circular dependencies.
|
|
245
191
|
*
|
|
246
|
-
* @returns
|
|
192
|
+
* @returns A clone of this object with the document property changed to a string.
|
|
247
193
|
*/
|
|
248
194
|
toJSON() {
|
|
249
195
|
const json = clone(this);
|
|
@@ -258,10 +204,9 @@ export default class Document extends Emitter {
|
|
|
258
204
|
* Fire `change:data` event when at least one operation or buffered marker changes the data.
|
|
259
205
|
*
|
|
260
206
|
* @internal
|
|
261
|
-
* @protected
|
|
262
207
|
* @fires change
|
|
263
208
|
* @fires change:data
|
|
264
|
-
* @param
|
|
209
|
+
* @param writer The writer on which post-fixers will be called.
|
|
265
210
|
*/
|
|
266
211
|
_handleChangeBlock(writer) {
|
|
267
212
|
if (this._hasDocumentChangedFromTheLastChangeBlock()) {
|
|
@@ -286,8 +231,7 @@ export default class Document extends Emitter {
|
|
|
286
231
|
* {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block}
|
|
287
232
|
* or {@link module:engine/model/model~Model#change `change()` block}.
|
|
288
233
|
*
|
|
289
|
-
* @
|
|
290
|
-
* @returns {Boolean} Returns `true` if document has changed from the last `change()` or `enqueueChange()` block.
|
|
234
|
+
* @returns Returns `true` if document has changed from the last `change()` or `enqueueChange()` block.
|
|
291
235
|
*/
|
|
292
236
|
_hasDocumentChangedFromTheLastChangeBlock() {
|
|
293
237
|
return !this.differ.isEmpty || this._hasSelectionChangedFromTheLastChangeBlock;
|
|
@@ -296,8 +240,7 @@ export default class Document extends Emitter {
|
|
|
296
240
|
* Returns the default root for this document which is either the first root that was added to the document using
|
|
297
241
|
* {@link #createRoot} or the {@link #graveyard graveyard root} if no other roots were created.
|
|
298
242
|
*
|
|
299
|
-
* @
|
|
300
|
-
* @returns {module:engine/model/rootelement~RootElement} The default root for this document.
|
|
243
|
+
* @returns The default root for this document.
|
|
301
244
|
*/
|
|
302
245
|
_getDefaultRoot() {
|
|
303
246
|
for (const root of this.roots) {
|
|
@@ -312,8 +255,6 @@ export default class Document extends Emitter {
|
|
|
312
255
|
* at the beginning of this selection's document {@link #_getDefaultRoot default root}.
|
|
313
256
|
*
|
|
314
257
|
* @internal
|
|
315
|
-
* @protected
|
|
316
|
-
* @returns {module:engine/model/range~Range}
|
|
317
258
|
*/
|
|
318
259
|
_getDefaultRange() {
|
|
319
260
|
const defaultRoot = this._getDefaultRoot();
|
|
@@ -330,9 +271,8 @@ export default class Document extends Emitter {
|
|
|
330
271
|
* the {@link #selection document's selection}.
|
|
331
272
|
*
|
|
332
273
|
* @internal
|
|
333
|
-
* @
|
|
334
|
-
* @
|
|
335
|
-
* @returns {Boolean} `true` if `range` is valid, `false` otherwise.
|
|
274
|
+
* @param range A range to check.
|
|
275
|
+
* @returns `true` if `range` is valid, `false` otherwise.
|
|
336
276
|
*/
|
|
337
277
|
_validateSelectionRange(range) {
|
|
338
278
|
return validateTextNodePosition(range.start) && validateTextNodePosition(range.end);
|
|
@@ -340,8 +280,7 @@ export default class Document extends Emitter {
|
|
|
340
280
|
/**
|
|
341
281
|
* Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.
|
|
342
282
|
*
|
|
343
|
-
* @
|
|
344
|
-
* @param {module:engine/model/writer~Writer} writer The writer on which post-fixer callbacks will be called.
|
|
283
|
+
* @param writer The writer on which post-fixer callbacks will be called.
|
|
345
284
|
*/
|
|
346
285
|
_callPostFixers(writer) {
|
|
347
286
|
let wasFixed = false;
|
|
@@ -362,8 +301,10 @@ export default class Document extends Emitter {
|
|
|
362
301
|
} while (wasFixed);
|
|
363
302
|
}
|
|
364
303
|
}
|
|
365
|
-
|
|
366
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Checks whether given range boundary position is valid for document selection, meaning that is not between
|
|
306
|
+
* unicode surrogate pairs or base character and combining marks.
|
|
307
|
+
*/
|
|
367
308
|
function validateTextNodePosition(rangeBoundary) {
|
|
368
309
|
const textNode = rangeBoundary.textNode;
|
|
369
310
|
if (textNode) {
|
|
@@ -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
|
/**
|
|
@@ -10,7 +10,7 @@ import Element from './element';
|
|
|
10
10
|
import NodeList from './nodelist';
|
|
11
11
|
import Text from './text';
|
|
12
12
|
import TextProxy from './textproxy';
|
|
13
|
-
import isIterable from '@ckeditor/ckeditor5-utils
|
|
13
|
+
import { isIterable } from '@ckeditor/ckeditor5-utils';
|
|
14
14
|
// @if CK_DEBUG_ENGINE // const { stringifyMap } = require( '../dev-utils/utils' );
|
|
15
15
|
/**
|
|
16
16
|
* DocumentFragment represents a part of model which does not have a common root but its top-level nodes
|
|
@@ -27,9 +27,8 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
27
27
|
* **Note:** Constructor of this class shouldn't be used directly in the code.
|
|
28
28
|
* Use the {@link module:engine/model/writer~Writer#createDocumentFragment} method instead.
|
|
29
29
|
*
|
|
30
|
-
* @
|
|
31
|
-
* @param
|
|
32
|
-
* Nodes to be contained inside the `DocumentFragment`.
|
|
30
|
+
* @internal
|
|
31
|
+
* @param children Nodes to be contained inside the `DocumentFragment`.
|
|
33
32
|
*/
|
|
34
33
|
constructor(children) {
|
|
35
34
|
super();
|
|
@@ -37,16 +36,10 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
37
36
|
* DocumentFragment static markers map. This is a list of names and {@link module:engine/model/range~Range ranges}
|
|
38
37
|
* which will be set as Markers to {@link module:engine/model/model~Model#markers model markers collection}
|
|
39
38
|
* when DocumentFragment will be inserted to the document.
|
|
40
|
-
*
|
|
41
|
-
* @readonly
|
|
42
|
-
* @member {Map<String,module:engine/model/range~Range>} module:engine/model/documentfragment~DocumentFragment#markers
|
|
43
39
|
*/
|
|
44
40
|
this.markers = new Map();
|
|
45
41
|
/**
|
|
46
42
|
* List of nodes contained inside the document fragment.
|
|
47
|
-
*
|
|
48
|
-
* @private
|
|
49
|
-
* @member {module:engine/model/nodelist~NodeList} module:engine/model/documentfragment~DocumentFragment#_children
|
|
50
43
|
*/
|
|
51
44
|
this._children = new NodeList();
|
|
52
45
|
if (children) {
|
|
@@ -55,88 +48,60 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
55
48
|
}
|
|
56
49
|
/**
|
|
57
50
|
* Returns an iterator that iterates over all nodes contained inside this document fragment.
|
|
58
|
-
*
|
|
59
|
-
* @returns {Iterator.<module:engine/model/node~Node>}
|
|
60
51
|
*/
|
|
61
52
|
[Symbol.iterator]() {
|
|
62
53
|
return this.getChildren();
|
|
63
54
|
}
|
|
64
55
|
/**
|
|
65
56
|
* Number of this document fragment's children.
|
|
66
|
-
*
|
|
67
|
-
* @readonly
|
|
68
|
-
* @type {Number}
|
|
69
57
|
*/
|
|
70
58
|
get childCount() {
|
|
71
59
|
return this._children.length;
|
|
72
60
|
}
|
|
73
61
|
/**
|
|
74
62
|
* Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this document fragment's children.
|
|
75
|
-
*
|
|
76
|
-
* @readonly
|
|
77
|
-
* @type {Number}
|
|
78
63
|
*/
|
|
79
64
|
get maxOffset() {
|
|
80
65
|
return this._children.maxOffset;
|
|
81
66
|
}
|
|
82
67
|
/**
|
|
83
68
|
* Is `true` if there are no nodes inside this document fragment, `false` otherwise.
|
|
84
|
-
*
|
|
85
|
-
* @readonly
|
|
86
|
-
* @type {Boolean}
|
|
87
69
|
*/
|
|
88
70
|
get isEmpty() {
|
|
89
71
|
return this.childCount === 0;
|
|
90
72
|
}
|
|
91
73
|
/**
|
|
92
74
|
* Artificial next sibling. Returns `null`. Added for compatibility reasons.
|
|
93
|
-
*
|
|
94
|
-
* @readonly
|
|
95
|
-
* @type {null}
|
|
96
75
|
*/
|
|
97
76
|
get nextSibling() {
|
|
98
77
|
return null;
|
|
99
78
|
}
|
|
100
79
|
/**
|
|
101
80
|
* Artificial previous sibling. Returns `null`. Added for compatibility reasons.
|
|
102
|
-
*
|
|
103
|
-
* @readonly
|
|
104
|
-
* @type {null}
|
|
105
81
|
*/
|
|
106
82
|
get previousSibling() {
|
|
107
83
|
return null;
|
|
108
84
|
}
|
|
109
85
|
/**
|
|
110
86
|
* Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.
|
|
111
|
-
*
|
|
112
|
-
* @readonly
|
|
113
|
-
* @type {module:engine/model/documentfragment~DocumentFragment}
|
|
114
87
|
*/
|
|
115
88
|
get root() {
|
|
116
89
|
return this;
|
|
117
90
|
}
|
|
118
91
|
/**
|
|
119
92
|
* Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.
|
|
120
|
-
*
|
|
121
|
-
* @readonly
|
|
122
|
-
* @type {null}
|
|
123
93
|
*/
|
|
124
94
|
get parent() {
|
|
125
95
|
return null;
|
|
126
96
|
}
|
|
127
97
|
/**
|
|
128
98
|
* Artificial owner of `DocumentFragment`. Returns `null`. Added for compatibility reasons.
|
|
129
|
-
*
|
|
130
|
-
* @readonly
|
|
131
|
-
* @type {null}
|
|
132
99
|
*/
|
|
133
100
|
get document() {
|
|
134
101
|
return null;
|
|
135
102
|
}
|
|
136
103
|
/**
|
|
137
104
|
* Returns empty array. Added for compatibility reasons.
|
|
138
|
-
*
|
|
139
|
-
* @returns {Array}
|
|
140
105
|
*/
|
|
141
106
|
getAncestors() {
|
|
142
107
|
return [];
|
|
@@ -144,16 +109,14 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
144
109
|
/**
|
|
145
110
|
* Gets the child at the given index. Returns `null` if incorrect index was passed.
|
|
146
111
|
*
|
|
147
|
-
* @param
|
|
148
|
-
* @returns
|
|
112
|
+
* @param index Index of child.
|
|
113
|
+
* @returns Child node.
|
|
149
114
|
*/
|
|
150
115
|
getChild(index) {
|
|
151
116
|
return this._children.getNode(index);
|
|
152
117
|
}
|
|
153
118
|
/**
|
|
154
119
|
* Returns an iterator that iterates over all of this document fragment's children.
|
|
155
|
-
*
|
|
156
|
-
* @returns {Iterable.<module:engine/model/node~Node>}
|
|
157
120
|
*/
|
|
158
121
|
getChildren() {
|
|
159
122
|
return this._children[Symbol.iterator]();
|
|
@@ -161,8 +124,8 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
161
124
|
/**
|
|
162
125
|
* Returns an index of the given child node. Returns `null` if given node is not a child of this document fragment.
|
|
163
126
|
*
|
|
164
|
-
* @param
|
|
165
|
-
* @returns
|
|
127
|
+
* @param node Child node to look for.
|
|
128
|
+
* @returns Child node's index.
|
|
166
129
|
*/
|
|
167
130
|
getChildIndex(node) {
|
|
168
131
|
return this._children.getNodeIndex(node);
|
|
@@ -172,16 +135,14 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
172
135
|
* {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if
|
|
173
136
|
* given node is not a child of this document fragment.
|
|
174
137
|
*
|
|
175
|
-
* @param
|
|
176
|
-
* @returns
|
|
138
|
+
* @param node Child node to look for.
|
|
139
|
+
* @returns Child node's starting offset.
|
|
177
140
|
*/
|
|
178
141
|
getChildStartOffset(node) {
|
|
179
142
|
return this._children.getNodeStartOffset(node);
|
|
180
143
|
}
|
|
181
144
|
/**
|
|
182
145
|
* Returns path to a `DocumentFragment`, which is an empty array. Added for compatibility reasons.
|
|
183
|
-
*
|
|
184
|
-
* @returns {Array}
|
|
185
146
|
*/
|
|
186
147
|
getPath() {
|
|
187
148
|
return [];
|
|
@@ -189,13 +150,14 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
189
150
|
/**
|
|
190
151
|
* Returns a descendant node by its path relative to this element.
|
|
191
152
|
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
153
|
+
* ```ts
|
|
154
|
+
* // <this>a<b>c</b></this>
|
|
155
|
+
* this.getNodeByPath( [ 0 ] ); // -> "a"
|
|
156
|
+
* this.getNodeByPath( [ 1 ] ); // -> <b>
|
|
157
|
+
* this.getNodeByPath( [ 1, 0 ] ); // -> "c"
|
|
158
|
+
* ```
|
|
196
159
|
*
|
|
197
|
-
* @param
|
|
198
|
-
* @returns {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}
|
|
160
|
+
* @param relativePath Path of the node to find, relative to this element.
|
|
199
161
|
*/
|
|
200
162
|
getNodeByPath(relativePath) {
|
|
201
163
|
// eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
|
|
@@ -211,18 +173,20 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
211
173
|
* Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is
|
|
212
174
|
* too high, returns index after last child}.
|
|
213
175
|
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
176
|
+
* ```ts
|
|
177
|
+
* const textNode = new Text( 'foo' );
|
|
178
|
+
* const pElement = new Element( 'p' );
|
|
179
|
+
* const docFrag = new DocumentFragment( [ textNode, pElement ] );
|
|
180
|
+
* docFrag.offsetToIndex( -1 ); // Returns 0, because offset is too low.
|
|
181
|
+
* docFrag.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.
|
|
182
|
+
* docFrag.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.
|
|
183
|
+
* docFrag.offsetToIndex( 2 ); // Returns 0.
|
|
184
|
+
* docFrag.offsetToIndex( 3 ); // Returns 1.
|
|
185
|
+
* docFrag.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.
|
|
186
|
+
* ```
|
|
223
187
|
*
|
|
224
|
-
* @param
|
|
225
|
-
* @returns
|
|
188
|
+
* @param offset Offset to look for.
|
|
189
|
+
* @returns Index of a node that occupies given offset.
|
|
226
190
|
*/
|
|
227
191
|
offsetToIndex(offset) {
|
|
228
192
|
return this._children.offsetToIndex(offset);
|
|
@@ -231,7 +195,7 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
231
195
|
* Converts `DocumentFragment` instance to plain object and returns it.
|
|
232
196
|
* Takes care of converting all of this document fragment's children.
|
|
233
197
|
*
|
|
234
|
-
* @returns
|
|
198
|
+
* @returns `DocumentFragment` instance converted to plain object.
|
|
235
199
|
*/
|
|
236
200
|
toJSON() {
|
|
237
201
|
const json = [];
|
|
@@ -244,8 +208,8 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
244
208
|
* Creates a `DocumentFragment` instance from given plain object (i.e. parsed JSON string).
|
|
245
209
|
* Converts `DocumentFragment` children to proper nodes.
|
|
246
210
|
*
|
|
247
|
-
* @param
|
|
248
|
-
* @returns
|
|
211
|
+
* @param json Plain object to be converted to `DocumentFragment`.
|
|
212
|
+
* @returns `DocumentFragment` instance created using given plain object.
|
|
249
213
|
*/
|
|
250
214
|
static fromJSON(json) {
|
|
251
215
|
const children = [];
|
|
@@ -265,8 +229,7 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
265
229
|
* {@link #_insertChild Inserts} one or more nodes at the end of this document fragment.
|
|
266
230
|
*
|
|
267
231
|
* @internal
|
|
268
|
-
* @
|
|
269
|
-
* @param {String|module:engine/model/item~Item|Iterable.<String|module:engine/model/item~Item>} items Items to be inserted.
|
|
232
|
+
* @param items Items to be inserted.
|
|
270
233
|
*/
|
|
271
234
|
_appendChild(items) {
|
|
272
235
|
this._insertChild(this.childCount, items);
|
|
@@ -276,9 +239,8 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
276
239
|
* to this document fragment.
|
|
277
240
|
*
|
|
278
241
|
* @internal
|
|
279
|
-
* @
|
|
280
|
-
* @param
|
|
281
|
-
* @param {String|module:engine/model/item~Item|Iterable.<String|module:engine/model/item~Item>} items Items to be inserted.
|
|
242
|
+
* @param index Index at which nodes should be inserted.
|
|
243
|
+
* @param items Items to be inserted.
|
|
282
244
|
*/
|
|
283
245
|
_insertChild(index, items) {
|
|
284
246
|
const nodes = normalize(items);
|
|
@@ -296,10 +258,9 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
296
258
|
* and sets {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
|
|
297
259
|
*
|
|
298
260
|
* @internal
|
|
299
|
-
* @
|
|
300
|
-
* @param
|
|
301
|
-
* @
|
|
302
|
-
* @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.
|
|
261
|
+
* @param index Index of the first node to remove.
|
|
262
|
+
* @param howMany Number of nodes to remove.
|
|
263
|
+
* @returns Array containing removed nodes.
|
|
303
264
|
*/
|
|
304
265
|
_removeChildren(index, howMany = 1) {
|
|
305
266
|
const nodes = this._children._removeNodes(index, howMany);
|
|
@@ -309,28 +270,14 @@ export default class DocumentFragment extends TypeCheckable {
|
|
|
309
270
|
return nodes;
|
|
310
271
|
}
|
|
311
272
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
*
|
|
315
|
-
* docFrag.is( 'documentFragment' ); // -> true
|
|
316
|
-
* docFrag.is( 'model:documentFragment' ); // -> true
|
|
317
|
-
*
|
|
318
|
-
* docFrag.is( 'view:documentFragment' ); // -> false
|
|
319
|
-
* docFrag.is( 'element' ); // -> false
|
|
320
|
-
* docFrag.is( 'node' ); // -> false
|
|
321
|
-
*
|
|
322
|
-
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
|
|
323
|
-
*
|
|
324
|
-
* @param {String} type
|
|
325
|
-
* @returns {Boolean}
|
|
326
|
-
*/
|
|
273
|
+
// The magic of type inference using `is` method is centralized in `TypeCheckable` class.
|
|
274
|
+
// Proper overload would interfere with that.
|
|
327
275
|
DocumentFragment.prototype.is = function (type) {
|
|
328
276
|
return type === 'documentFragment' || type === 'model:documentFragment';
|
|
329
277
|
};
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
// @returns {Iterable.<module:engine/model/node~Node>}
|
|
278
|
+
/**
|
|
279
|
+
* Converts strings to Text and non-iterables to arrays.
|
|
280
|
+
*/
|
|
334
281
|
function normalize(nodes) {
|
|
335
282
|
// Separate condition because string is iterable.
|
|
336
283
|
if (typeof nodes == 'string') {
|