@ckeditor/ckeditor5-engine 35.4.0 → 36.0.1
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 +5 -1
- package/src/controller/editingcontroller.js +1 -1
- package/src/conversion/conversion.js +1 -1
- package/src/conversion/conversionhelpers.js +1 -1
- package/src/conversion/downcastdispatcher.js +1 -1
- package/src/conversion/downcasthelpers.js +1 -1
- package/src/conversion/mapper.js +1 -1
- package/src/conversion/modelconsumable.js +1 -1
- package/src/conversion/upcastdispatcher.js +1 -1
- package/src/conversion/upcasthelpers.js +8 -1
- package/src/conversion/viewconsumable.js +1 -1
- package/src/dataprocessor/basichtmlwriter.js +1 -1
- package/src/dataprocessor/dataprocessor.js +1 -1
- package/src/dataprocessor/htmldataprocessor.js +1 -2
- package/src/dataprocessor/htmlwriter.js +1 -1
- package/src/dataprocessor/xmldataprocessor.js +1 -1
- package/src/dev-utils/model.js +1 -1
- 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 +3 -2
- package/src/model/batch.js +9 -46
- package/src/model/differ.js +81 -174
- package/src/model/document.js +36 -92
- package/src/model/documentfragment.js +43 -96
- package/src/model/documentselection.js +151 -245
- package/src/model/element.js +47 -100
- package/src/model/history.js +15 -46
- package/src/model/item.js +1 -1
- package/src/model/liveposition.js +10 -36
- package/src/model/liverange.js +13 -36
- package/src/model/markercollection.js +40 -111
- package/src/model/model.js +212 -289
- package/src/model/node.js +35 -125
- package/src/model/nodelist.js +11 -39
- package/src/model/operation/attributeoperation.js +13 -44
- package/src/model/operation/detachoperation.js +3 -16
- package/src/model/operation/insertoperation.js +6 -34
- package/src/model/operation/markeroperation.js +9 -48
- package/src/model/operation/mergeoperation.js +8 -41
- package/src/model/operation/moveoperation.js +14 -37
- 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 +8 -28
- package/src/model/operation/rootattributeoperation.js +18 -47
- package/src/model/operation/splitoperation.js +9 -47
- package/src/model/operation/transform.js +109 -150
- package/src/model/operation/utils.js +36 -50
- package/src/model/position.js +117 -228
- package/src/model/range.js +145 -200
- package/src/model/rootelement.js +8 -47
- package/src/model/schema.js +236 -272
- package/src/model/selection.js +134 -192
- package/src/model/text.js +10 -37
- package/src/model/textproxy.js +15 -69
- package/src/model/treewalker.js +10 -101
- 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 +24 -24
- package/src/model/utils/getselectedcontent.js +3 -6
- package/src/model/utils/insertcontent.js +36 -129
- package/src/model/utils/insertobject.js +19 -21
- package/src/model/utils/modifyselection.js +23 -33
- package/src/model/utils/selection-post-fixer.js +53 -59
- package/src/model/writer.js +208 -314
- package/src/view/attributeelement.js +1 -1
- package/src/view/containerelement.js +1 -1
- package/src/view/datatransfer.js +25 -28
- package/src/view/document.js +1 -17
- package/src/view/documentfragment.js +49 -1
- package/src/view/documentselection.js +1 -1
- package/src/view/domconverter.js +4 -3
- package/src/view/downcastwriter.js +1 -1
- package/src/view/editableelement.js +1 -1
- package/src/view/element.js +5 -5
- package/src/view/elementdefinition.js +1 -1
- package/src/view/emptyelement.js +1 -1
- package/src/view/filler.js +1 -1
- package/src/view/item.js +1 -1
- package/src/view/matcher.js +1 -1
- package/src/view/node.js +1 -1
- package/src/view/observer/arrowkeysobserver.js +1 -1
- package/src/view/observer/bubblingemittermixin.js +1 -1
- package/src/view/observer/bubblingeventinfo.js +1 -1
- 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 +1 -1
- package/src/view/observer/focusobserver.js +22 -4
- package/src/view/observer/inputobserver.js +1 -1
- package/src/view/observer/keyobserver.js +1 -1
- package/src/view/observer/mouseobserver.js +1 -1
- package/src/view/observer/mutationobserver.js +1 -1
- package/src/view/observer/observer.js +1 -1
- package/src/view/observer/selectionobserver.js +13 -2
- package/src/view/observer/tabobserver.js +1 -1
- package/src/view/placeholder.js +1 -1
- package/src/view/position.js +1 -1
- package/src/view/range.js +1 -1
- package/src/view/rawelement.js +1 -1
- package/src/view/renderer.js +1 -14
- package/src/view/rooteditableelement.js +1 -1
- package/src/view/selection.js +1 -1
- 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 +1 -1
- package/src/view/treewalker.js +1 -1
- package/src/view/typecheckable.js +1 -1
- package/src/view/uielement.js +1 -1
- package/src/view/upcastwriter.js +1 -1
- package/src/view/view.js +5 -5
- package/theme/placeholder.css +1 -1
- package/theme/renderer.css +1 -1
package/src/model/selection.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
|
/**
|
|
@@ -16,84 +16,72 @@ import { CKEditorError, EmitterMixin, isIterable } from '@ckeditor/ckeditor5-uti
|
|
|
16
16
|
* (it can be {@link module:engine/model/selection~Selection#isBackward forward or backward}).
|
|
17
17
|
* Additionally, selection may have its own attributes (think – whether text typed in in this selection
|
|
18
18
|
* should have those attributes – e.g. whether you type a bolded text).
|
|
19
|
-
*
|
|
20
|
-
* @mixes module:utils/emittermixin~EmitterMixin
|
|
21
19
|
*/
|
|
22
20
|
export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
23
21
|
/**
|
|
24
22
|
* Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}
|
|
25
23
|
* or creates an empty selection if no arguments were passed.
|
|
26
24
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* // Creates empty selection without ranges.
|
|
27
|
+
* const selection = writer.createSelection();
|
|
29
28
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
29
|
+
* // Creates selection at the given range.
|
|
30
|
+
* const range = writer.createRange( start, end );
|
|
31
|
+
* const selection = writer.createSelection( range );
|
|
33
32
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
33
|
+
* // Creates selection at the given ranges
|
|
34
|
+
* const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
|
|
35
|
+
* const selection = writer.createSelection( ranges );
|
|
37
36
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
37
|
+
* // Creates selection from the other selection.
|
|
38
|
+
* // Note: It doesn't copy selection attributes.
|
|
39
|
+
* const otherSelection = writer.createSelection();
|
|
40
|
+
* const selection = writer.createSelection( otherSelection );
|
|
42
41
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
42
|
+
* // Creates selection from the given document selection.
|
|
43
|
+
* // Note: It doesn't copy selection attributes.
|
|
44
|
+
* const documentSelection = model.document.selection;
|
|
45
|
+
* const selection = writer.createSelection( documentSelection );
|
|
47
46
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
47
|
+
* // Creates selection at the given position.
|
|
48
|
+
* const position = writer.createPositionFromPath( root, path );
|
|
49
|
+
* const selection = writer.createSelection( position );
|
|
51
50
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
51
|
+
* // Creates selection at the given offset in the given element.
|
|
52
|
+
* const paragraph = writer.createElement( 'paragraph' );
|
|
53
|
+
* const selection = writer.createSelection( paragraph, offset );
|
|
55
54
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
55
|
+
* // Creates a range inside an {@link module:engine/model/element~Element element} which starts before the
|
|
56
|
+
* // first child of that element and ends after the last child of that element.
|
|
57
|
+
* const selection = writer.createSelection( paragraph, 'in' );
|
|
59
58
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
59
|
+
* // Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends
|
|
60
|
+
* // just after the item.
|
|
61
|
+
* const selection = writer.createSelection( paragraph, 'on' );
|
|
62
|
+
* ```
|
|
63
63
|
*
|
|
64
64
|
* Selection's constructor allow passing additional options (`'backward'`) as the last argument.
|
|
65
65
|
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
66
|
+
* ```ts
|
|
67
|
+
* // Creates backward selection.
|
|
68
|
+
* const selection = writer.createSelection( range, { backward: true } );
|
|
69
|
+
* ```
|
|
68
70
|
*
|
|
69
|
-
* @
|
|
70
|
-
* @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.
|
|
71
|
-
* @param {Object} [options]
|
|
72
|
-
* @param {Boolean} [options.backward] Sets this selection instance to be backward.
|
|
71
|
+
* @internal
|
|
73
72
|
*/
|
|
74
73
|
constructor(...args) {
|
|
75
74
|
super();
|
|
76
75
|
/**
|
|
77
76
|
* Specifies whether the last added range was added as a backward or forward range.
|
|
78
|
-
*
|
|
79
|
-
* @private
|
|
80
|
-
* @type {Boolean}
|
|
81
77
|
*/
|
|
82
78
|
this._lastRangeBackward = false;
|
|
83
|
-
/**
|
|
84
|
-
* Stores selection ranges.
|
|
85
|
-
*
|
|
86
|
-
* @protected
|
|
87
|
-
* @type {Array.<module:engine/model/range~Range>}
|
|
88
|
-
*/
|
|
89
|
-
this._ranges = [];
|
|
90
79
|
/**
|
|
91
80
|
* List of attributes set on current selection.
|
|
92
|
-
*
|
|
93
|
-
* @protected
|
|
94
|
-
* @type {Map.<String,*>}
|
|
95
81
|
*/
|
|
96
82
|
this._attrs = new Map();
|
|
83
|
+
/** @internal */
|
|
84
|
+
this._ranges = [];
|
|
97
85
|
if (args.length) {
|
|
98
86
|
this.setTo(...args);
|
|
99
87
|
}
|
|
@@ -112,8 +100,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
112
100
|
* May be set to `null` if there are no ranges in the selection.
|
|
113
101
|
*
|
|
114
102
|
* @see #focus
|
|
115
|
-
* @readonly
|
|
116
|
-
* @type {module:engine/model/position~Position|null}
|
|
117
103
|
*/
|
|
118
104
|
get anchor() {
|
|
119
105
|
if (this._ranges.length > 0) {
|
|
@@ -129,8 +115,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
129
115
|
* May be set to `null` if there are no ranges in the selection.
|
|
130
116
|
*
|
|
131
117
|
* @see #anchor
|
|
132
|
-
* @readonly
|
|
133
|
-
* @type {module:engine/model/position~Position|null}
|
|
134
118
|
*/
|
|
135
119
|
get focus() {
|
|
136
120
|
if (this._ranges.length > 0) {
|
|
@@ -142,9 +126,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
142
126
|
/**
|
|
143
127
|
* Whether the selection is collapsed. Selection is collapsed when there is exactly one range in it
|
|
144
128
|
* and it is collapsed.
|
|
145
|
-
*
|
|
146
|
-
* @readonly
|
|
147
|
-
* @type {Boolean}
|
|
148
129
|
*/
|
|
149
130
|
get isCollapsed() {
|
|
150
131
|
const length = this._ranges.length;
|
|
@@ -157,18 +138,12 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
157
138
|
}
|
|
158
139
|
/**
|
|
159
140
|
* Returns the number of ranges in the selection.
|
|
160
|
-
*
|
|
161
|
-
* @readonly
|
|
162
|
-
* @type {Number}
|
|
163
141
|
*/
|
|
164
142
|
get rangeCount() {
|
|
165
143
|
return this._ranges.length;
|
|
166
144
|
}
|
|
167
145
|
/**
|
|
168
146
|
* Specifies whether the selection's {@link #focus} precedes the selection's {@link #anchor}.
|
|
169
|
-
*
|
|
170
|
-
* @readonly
|
|
171
|
-
* @type {Boolean}
|
|
172
147
|
*/
|
|
173
148
|
get isBackward() {
|
|
174
149
|
return !this.isCollapsed && this._lastRangeBackward;
|
|
@@ -177,9 +152,8 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
177
152
|
* Checks whether this selection is equal to the given selection. Selections are equal if they have the same directions,
|
|
178
153
|
* the same number of ranges and all ranges from one selection equal to ranges from the another selection.
|
|
179
154
|
*
|
|
180
|
-
* @param
|
|
181
|
-
*
|
|
182
|
-
* @returns {Boolean} `true` if selections are equal, `false` otherwise.
|
|
155
|
+
* @param otherSelection Selection to compare with.
|
|
156
|
+
* @returns `true` if selections are equal, `false` otherwise.
|
|
183
157
|
*/
|
|
184
158
|
isEqual(otherSelection) {
|
|
185
159
|
if (this.rangeCount != otherSelection.rangeCount) {
|
|
@@ -207,8 +181,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
207
181
|
}
|
|
208
182
|
/**
|
|
209
183
|
* Returns an iterable object that iterates over copies of selection ranges.
|
|
210
|
-
*
|
|
211
|
-
* @returns {Iterable.<module:engine/model/range~Range>}
|
|
212
184
|
*/
|
|
213
185
|
*getRanges() {
|
|
214
186
|
for (const range of this._ranges) {
|
|
@@ -222,8 +194,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
222
194
|
* (not to confuse with the first range added to the selection).
|
|
223
195
|
*
|
|
224
196
|
* Returns `null` if there are no ranges in selection.
|
|
225
|
-
*
|
|
226
|
-
* @returns {module:engine/model/range~Range|null}
|
|
227
197
|
*/
|
|
228
198
|
getFirstRange() {
|
|
229
199
|
let first = null;
|
|
@@ -241,8 +211,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
241
211
|
* recently added to the selection).
|
|
242
212
|
*
|
|
243
213
|
* Returns `null` if there are no ranges in selection.
|
|
244
|
-
*
|
|
245
|
-
* @returns {module:engine/model/range~Range|null}
|
|
246
214
|
*/
|
|
247
215
|
getLastRange() {
|
|
248
216
|
let last = null;
|
|
@@ -259,8 +227,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
259
227
|
* any other position in the selection.
|
|
260
228
|
*
|
|
261
229
|
* Returns `null` if there are no ranges in selection.
|
|
262
|
-
*
|
|
263
|
-
* @returns {module:engine/model/position~Position|null}
|
|
264
230
|
*/
|
|
265
231
|
getFirstPosition() {
|
|
266
232
|
const first = this.getFirstRange();
|
|
@@ -272,8 +238,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
272
238
|
* any other position in the selection.
|
|
273
239
|
*
|
|
274
240
|
* Returns `null` if there are no ranges in selection.
|
|
275
|
-
*
|
|
276
|
-
* @returns {module:engine/model/position~Position|null}
|
|
277
241
|
*/
|
|
278
242
|
getLastPosition() {
|
|
279
243
|
const lastRange = this.getLastRange();
|
|
@@ -283,52 +247,55 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
283
247
|
* Sets this selection's ranges and direction to the specified location based on the given
|
|
284
248
|
* {@link module:engine/model/selection~Selectable selectable}.
|
|
285
249
|
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
250
|
+
* ```ts
|
|
251
|
+
* // Removes all selection's ranges.
|
|
252
|
+
* selection.setTo( null );
|
|
288
253
|
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
254
|
+
* // Sets selection to the given range.
|
|
255
|
+
* const range = writer.createRange( start, end );
|
|
256
|
+
* selection.setTo( range );
|
|
292
257
|
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
258
|
+
* // Sets selection to given ranges.
|
|
259
|
+
* const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
|
|
260
|
+
* selection.setTo( ranges );
|
|
296
261
|
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
262
|
+
* // Sets selection to other selection.
|
|
263
|
+
* // Note: It doesn't copy selection attributes.
|
|
264
|
+
* const otherSelection = writer.createSelection();
|
|
265
|
+
* selection.setTo( otherSelection );
|
|
301
266
|
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
*
|
|
267
|
+
* // Sets selection to the given document selection.
|
|
268
|
+
* // Note: It doesn't copy selection attributes.
|
|
269
|
+
* const documentSelection = new DocumentSelection( doc );
|
|
270
|
+
* selection.setTo( documentSelection );
|
|
306
271
|
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
272
|
+
* // Sets collapsed selection at the given position.
|
|
273
|
+
* const position = writer.createPositionFromPath( root, path );
|
|
274
|
+
* selection.setTo( position );
|
|
310
275
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
276
|
+
* // Sets collapsed selection at the position of the given node and an offset.
|
|
277
|
+
* selection.setTo( paragraph, offset );
|
|
278
|
+
* ```
|
|
313
279
|
*
|
|
314
280
|
* Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of
|
|
315
281
|
* that element and ends after the last child of that element.
|
|
316
282
|
*
|
|
317
|
-
*
|
|
283
|
+
* ```ts
|
|
284
|
+
* selection.setTo( paragraph, 'in' );
|
|
285
|
+
* ```
|
|
318
286
|
*
|
|
319
287
|
* Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.
|
|
320
288
|
*
|
|
321
|
-
*
|
|
289
|
+
* ```ts
|
|
290
|
+
* selection.setTo( paragraph, 'on' );
|
|
291
|
+
* ```
|
|
322
292
|
*
|
|
323
293
|
* `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.
|
|
324
294
|
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
* @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.
|
|
330
|
-
* @param {Object} [options]
|
|
331
|
-
* @param {Boolean} [options.backward] Sets this selection instance to be backward.
|
|
295
|
+
* ```ts
|
|
296
|
+
* // Sets backward selection.
|
|
297
|
+
* const selection = writer.createSelection( range, { backward: true } );
|
|
298
|
+
* ```
|
|
332
299
|
*/
|
|
333
300
|
setTo(...args) {
|
|
334
301
|
let [selectable, placeOrOffset, options] = args;
|
|
@@ -400,10 +367,9 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
400
367
|
* is treated like the last added range and is used to set {@link module:engine/model/selection~Selection#anchor} and
|
|
401
368
|
* {@link module:engine/model/selection~Selection#focus}. Accepts a flag describing in which direction the selection is made.
|
|
402
369
|
*
|
|
403
|
-
* @protected
|
|
404
370
|
* @fires change:range
|
|
405
|
-
* @param
|
|
406
|
-
* @param
|
|
371
|
+
* @param newRanges Ranges to set.
|
|
372
|
+
* @param isLastBackward Flag describing if last added range was selected forward - from start to end (`false`)
|
|
407
373
|
* or backward - from end to start (`true`).
|
|
408
374
|
*/
|
|
409
375
|
_setRanges(newRanges, isLastBackward = false) {
|
|
@@ -443,9 +409,7 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
443
409
|
* {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.
|
|
444
410
|
*
|
|
445
411
|
* @fires change:range
|
|
446
|
-
* @param {module:engine/model/item~Item
|
|
447
|
-
* @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
|
|
448
|
-
* first parameter is a {@link module:engine/model/item~Item model item}.
|
|
412
|
+
* @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/model/item~Item model item}.
|
|
449
413
|
*/
|
|
450
414
|
setFocus(itemOrPosition, offset) {
|
|
451
415
|
if (this.anchor === null) {
|
|
@@ -477,8 +441,8 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
477
441
|
/**
|
|
478
442
|
* Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.
|
|
479
443
|
*
|
|
480
|
-
* @param
|
|
481
|
-
* @returns
|
|
444
|
+
* @param key Key of attribute to look for.
|
|
445
|
+
* @returns Attribute value or `undefined`.
|
|
482
446
|
*/
|
|
483
447
|
getAttribute(key) {
|
|
484
448
|
return this._attrs.get(key);
|
|
@@ -488,16 +452,12 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
488
452
|
*
|
|
489
453
|
* Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
|
|
490
454
|
* This format is accepted by native `Map` object and also can be passed in `Node` constructor.
|
|
491
|
-
*
|
|
492
|
-
* @returns {Iterable.<*>}
|
|
493
455
|
*/
|
|
494
456
|
getAttributes() {
|
|
495
457
|
return this._attrs.entries();
|
|
496
458
|
}
|
|
497
459
|
/**
|
|
498
460
|
* Returns iterable that iterates over this selection's attribute keys.
|
|
499
|
-
*
|
|
500
|
-
* @returns {Iterable.<String>}
|
|
501
461
|
*/
|
|
502
462
|
getAttributeKeys() {
|
|
503
463
|
return this._attrs.keys();
|
|
@@ -505,8 +465,8 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
505
465
|
/**
|
|
506
466
|
* Checks if the selection has an attribute for given key.
|
|
507
467
|
*
|
|
508
|
-
* @param
|
|
509
|
-
* @returns
|
|
468
|
+
* @param key Key of attribute to check.
|
|
469
|
+
* @returns `true` if attribute with given key is set on selection, `false` otherwise.
|
|
510
470
|
*/
|
|
511
471
|
hasAttribute(key) {
|
|
512
472
|
return this._attrs.has(key);
|
|
@@ -518,7 +478,7 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
518
478
|
* removed attribute key.
|
|
519
479
|
*
|
|
520
480
|
* @fires change:attribute
|
|
521
|
-
* @param
|
|
481
|
+
* @param key Key of attribute to remove.
|
|
522
482
|
*/
|
|
523
483
|
removeAttribute(key) {
|
|
524
484
|
if (this.hasAttribute(key)) {
|
|
@@ -533,8 +493,8 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
533
493
|
* the attribute key.
|
|
534
494
|
*
|
|
535
495
|
* @fires change:attribute
|
|
536
|
-
* @param
|
|
537
|
-
* @param
|
|
496
|
+
* @param key Key of attribute to set.
|
|
497
|
+
* @param value Attribute value.
|
|
538
498
|
*/
|
|
539
499
|
setAttribute(key, value) {
|
|
540
500
|
if (this.getAttribute(key) !== value) {
|
|
@@ -546,8 +506,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
546
506
|
* Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only
|
|
547
507
|
* one range in the selection, and that range contains exactly one element.
|
|
548
508
|
* Returns `null` if there is no selected element.
|
|
549
|
-
*
|
|
550
|
-
* @returns {module:engine/model/element~Element|null}
|
|
551
509
|
*/
|
|
552
510
|
getSelectedElement() {
|
|
553
511
|
if (this.rangeCount !== 1) {
|
|
@@ -565,40 +523,48 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
565
523
|
*
|
|
566
524
|
* In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):
|
|
567
525
|
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
*
|
|
526
|
+
* ```xml
|
|
527
|
+
* <paragraph>[a</paragraph>
|
|
528
|
+
* <blockQuote>
|
|
529
|
+
* <paragraph>b</paragraph>
|
|
530
|
+
* </blockQuote>
|
|
531
|
+
* <paragraph>c]d</paragraph>
|
|
532
|
+
* ```
|
|
573
533
|
*
|
|
574
534
|
* In this case the paragraph will also be returned, despite the collapsed selection:
|
|
575
535
|
*
|
|
576
|
-
*
|
|
536
|
+
* ```xml
|
|
537
|
+
* <paragraph>[]a</paragraph>
|
|
538
|
+
* ```
|
|
577
539
|
*
|
|
578
540
|
* In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:
|
|
579
541
|
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
542
|
+
* ```xml
|
|
543
|
+
* [<blockA></blockA>
|
|
544
|
+
* <blockB>
|
|
545
|
+
* <blockC></blockC>
|
|
546
|
+
* <blockD></blockD>
|
|
547
|
+
* </blockB>
|
|
548
|
+
* <blockE></blockE>]
|
|
549
|
+
* ```
|
|
586
550
|
*
|
|
587
551
|
* If the selection is inside a block all the inner blocks (A & B) are returned:
|
|
588
552
|
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
553
|
+
* ```xml
|
|
554
|
+
* <block>
|
|
555
|
+
* <blockA>[a</blockA>
|
|
556
|
+
* <blockB>b]</blockB>
|
|
557
|
+
* </block>
|
|
558
|
+
* ```
|
|
593
559
|
*
|
|
594
560
|
* **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective
|
|
595
561
|
* this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.
|
|
596
562
|
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
563
|
+
* ```xml
|
|
564
|
+
* <paragraph>[a</paragraph>
|
|
565
|
+
* <paragraph>b</paragraph>
|
|
566
|
+
* <paragraph>]c</paragraph> // this block will not be returned
|
|
567
|
+
* ```
|
|
602
568
|
*/
|
|
603
569
|
*getSelectedBlocks() {
|
|
604
570
|
const visited = new WeakSet();
|
|
@@ -628,9 +594,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
628
594
|
*
|
|
629
595
|
* By default, this method will check whether the entire content of the selection's current root is selected.
|
|
630
596
|
* Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.
|
|
631
|
-
*
|
|
632
|
-
* @param {module:engine/model/element~Element} [element=this.anchor.root]
|
|
633
|
-
* @returns {Boolean}
|
|
634
597
|
*/
|
|
635
598
|
containsEntireContent(element = this.anchor.root) {
|
|
636
599
|
const limitStartPosition = Position._createAt(element, 0);
|
|
@@ -641,9 +604,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
641
604
|
/**
|
|
642
605
|
* Adds given range to internal {@link #_ranges ranges array}. Throws an error
|
|
643
606
|
* if given range is intersecting with any range that is already stored in this selection.
|
|
644
|
-
*
|
|
645
|
-
* @protected
|
|
646
|
-
* @param {module:engine/model/range~Range} range Range to add.
|
|
647
607
|
*/
|
|
648
608
|
_pushRange(range) {
|
|
649
609
|
this._checkRange(range);
|
|
@@ -651,9 +611,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
651
611
|
}
|
|
652
612
|
/**
|
|
653
613
|
* Checks if given range intersects with ranges that are already in the selection. Throws an error if it does.
|
|
654
|
-
*
|
|
655
|
-
* @protected
|
|
656
|
-
* @param {module:engine/model/range~Range} range Range to check.
|
|
657
614
|
*/
|
|
658
615
|
_checkRange(range) {
|
|
659
616
|
for (let i = 0; i < this._ranges.length; i++) {
|
|
@@ -662,8 +619,8 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
662
619
|
* Trying to add a range that intersects with another range in the selection.
|
|
663
620
|
*
|
|
664
621
|
* @error model-selection-range-intersects
|
|
665
|
-
* @param
|
|
666
|
-
* @param
|
|
622
|
+
* @param addedRange Range that was added to the selection.
|
|
623
|
+
* @param intersectingRange Range in the selection that intersects with `addedRange`.
|
|
667
624
|
*/
|
|
668
625
|
throw new CKEditorError('model-selection-range-intersects', [this, range], { addedRange: range, intersectingRange: this._ranges[i] });
|
|
669
626
|
}
|
|
@@ -672,9 +629,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
672
629
|
/**
|
|
673
630
|
* Replaces all the ranges by the given ones.
|
|
674
631
|
* Uses {@link #_popRange _popRange} and {@link #_pushRange _pushRange} to ensure proper ranges removal and addition.
|
|
675
|
-
*
|
|
676
|
-
* @param {Array.<module:engine/model/range~Range>} ranges
|
|
677
|
-
* @protected
|
|
678
632
|
*/
|
|
679
633
|
_replaceAllRanges(ranges) {
|
|
680
634
|
this._removeAllRanges();
|
|
@@ -685,8 +639,6 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
685
639
|
/**
|
|
686
640
|
* Deletes ranges from internal range array. Uses {@link #_popRange _popRange} to
|
|
687
641
|
* ensure proper ranges removal.
|
|
688
|
-
*
|
|
689
|
-
* @protected
|
|
690
642
|
*/
|
|
691
643
|
_removeAllRanges() {
|
|
692
644
|
while (this._ranges.length > 0) {
|
|
@@ -695,32 +647,20 @@ export default class Selection extends EmitterMixin(TypeCheckable) {
|
|
|
695
647
|
}
|
|
696
648
|
/**
|
|
697
649
|
* Removes most recently added range from the selection.
|
|
698
|
-
*
|
|
699
|
-
* @protected
|
|
700
650
|
*/
|
|
701
651
|
_popRange() {
|
|
702
652
|
this._ranges.pop();
|
|
703
653
|
}
|
|
704
654
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
*
|
|
708
|
-
* selection.is( 'selection' ); // -> true
|
|
709
|
-
* selection.is( 'model:selection' ); // -> true
|
|
710
|
-
*
|
|
711
|
-
* selection.is( 'view:selection' ); // -> false
|
|
712
|
-
* selection.is( 'range' ); // -> false
|
|
713
|
-
*
|
|
714
|
-
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
|
|
715
|
-
*
|
|
716
|
-
* @param {String} type
|
|
717
|
-
* @returns {Boolean}
|
|
718
|
-
*/
|
|
655
|
+
// The magic of type inference using `is` method is centralized in `TypeCheckable` class.
|
|
656
|
+
// Proper overload would interfere with that.
|
|
719
657
|
Selection.prototype.is = function (type) {
|
|
720
658
|
return type === 'selection' || type === 'model:selection';
|
|
721
659
|
};
|
|
722
|
-
|
|
723
|
-
|
|
660
|
+
/**
|
|
661
|
+
* Checks whether the given element extends $block in the schema and has a parent (is not a root).
|
|
662
|
+
* Marks it as already visited.
|
|
663
|
+
*/
|
|
724
664
|
function isUnvisitedBlock(element, visited) {
|
|
725
665
|
if (visited.has(element)) {
|
|
726
666
|
return false;
|
|
@@ -728,13 +668,17 @@ function isUnvisitedBlock(element, visited) {
|
|
|
728
668
|
visited.add(element);
|
|
729
669
|
return element.root.document.model.schema.isBlock(element) && !!element.parent;
|
|
730
670
|
}
|
|
731
|
-
|
|
671
|
+
/**
|
|
672
|
+
* Checks if the given element is a $block was not previously visited and is a top block in a range.
|
|
673
|
+
*/
|
|
732
674
|
function isUnvisitedTopBlock(element, visited, range) {
|
|
733
675
|
return isUnvisitedBlock(element, visited) && isTopBlockInRange(element, range);
|
|
734
676
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
677
|
+
/**
|
|
678
|
+
* Finds the lowest element in position's ancestors which is a block.
|
|
679
|
+
* It will search until first ancestor that is a limit element.
|
|
680
|
+
* Marks all ancestors as already visited to not include any of them later on.
|
|
681
|
+
*/
|
|
738
682
|
function getParentBlock(position, visited) {
|
|
739
683
|
const element = position.parent;
|
|
740
684
|
const schema = element.root.document.model.schema;
|
|
@@ -753,10 +697,9 @@ function getParentBlock(position, visited) {
|
|
|
753
697
|
ancestors.forEach(element => visited.add(element));
|
|
754
698
|
return block;
|
|
755
699
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
// @param {module:engine/model/range~Range} range Range to check.
|
|
700
|
+
/**
|
|
701
|
+
* Checks if the blocks is not nested in other block inside a range.
|
|
702
|
+
*/
|
|
760
703
|
function isTopBlockInRange(block, range) {
|
|
761
704
|
const parentBlock = findAncestorBlock(block);
|
|
762
705
|
if (!parentBlock) {
|
|
@@ -766,10 +709,9 @@ function isTopBlockInRange(block, range) {
|
|
|
766
709
|
const isParentInRange = range.containsRange(Range._createOn(parentBlock), true);
|
|
767
710
|
return !isParentInRange;
|
|
768
711
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
// @returns {module:engine/model/node~Node|undefined}
|
|
712
|
+
/**
|
|
713
|
+
* Returns first ancestor block of a node.
|
|
714
|
+
*/
|
|
773
715
|
function findAncestorBlock(node) {
|
|
774
716
|
const schema = node.root.document.model.schema;
|
|
775
717
|
let parent = node.parent;
|