@ckeditor/ckeditor5-engine 35.4.0 → 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 +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 +1 -1
- 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
|
@@ -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
|
/**
|
|
@@ -35,33 +35,23 @@ const storePrefix = 'selection:';
|
|
|
35
35
|
* that are inside {@link module:engine/model/documentfragment~DocumentFragment document fragment}.
|
|
36
36
|
* If you need to represent a selection in document fragment,
|
|
37
37
|
* use {@link module:engine/model/selection~Selection Selection class} instead.
|
|
38
|
-
*
|
|
39
|
-
* @mixes module:utils/emittermixin~EmitterMixin
|
|
40
38
|
*/
|
|
41
39
|
export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
42
40
|
/**
|
|
43
41
|
* Creates an empty live selection for given {@link module:engine/model/document~Document}.
|
|
44
42
|
*
|
|
45
|
-
* @param
|
|
43
|
+
* @param doc Document which owns this selection.
|
|
46
44
|
*/
|
|
47
45
|
constructor(doc) {
|
|
48
46
|
super();
|
|
49
|
-
/**
|
|
50
|
-
* Selection used internally by that class (`DocumentSelection` is a proxy to that selection).
|
|
51
|
-
*
|
|
52
|
-
* @protected
|
|
53
|
-
*/
|
|
54
47
|
this._selection = new LiveSelection(doc);
|
|
55
48
|
this._selection.delegate('change:range').to(this);
|
|
56
49
|
this._selection.delegate('change:attribute').to(this);
|
|
57
50
|
this._selection.delegate('change:marker').to(this);
|
|
58
51
|
}
|
|
59
52
|
/**
|
|
60
|
-
*
|
|
53
|
+
* Describes whether the selection is collapsed. Selection is collapsed when there is exactly one range which is
|
|
61
54
|
* collapsed.
|
|
62
|
-
*
|
|
63
|
-
* @readonly
|
|
64
|
-
* @type {Boolean}
|
|
65
55
|
*/
|
|
66
56
|
get isCollapsed() {
|
|
67
57
|
return this._selection.isCollapsed;
|
|
@@ -75,8 +65,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
75
65
|
* Is set to `null` if there are no ranges in selection.
|
|
76
66
|
*
|
|
77
67
|
* @see #focus
|
|
78
|
-
* @readonly
|
|
79
|
-
* @type {module:engine/model/position~Position|null}
|
|
80
68
|
*/
|
|
81
69
|
get anchor() {
|
|
82
70
|
return this._selection.anchor;
|
|
@@ -87,17 +75,12 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
87
75
|
* Is set to `null` if there are no ranges in selection.
|
|
88
76
|
*
|
|
89
77
|
* @see #anchor
|
|
90
|
-
* @readonly
|
|
91
|
-
* @type {module:engine/model/position~Position|null}
|
|
92
78
|
*/
|
|
93
79
|
get focus() {
|
|
94
80
|
return this._selection.focus;
|
|
95
81
|
}
|
|
96
82
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* @readonly
|
|
100
|
-
* @type {Number}
|
|
83
|
+
* Number of ranges in selection.
|
|
101
84
|
*/
|
|
102
85
|
get rangeCount() {
|
|
103
86
|
return this._selection.rangeCount;
|
|
@@ -105,9 +88,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
105
88
|
/**
|
|
106
89
|
* Describes whether `Documentselection` has own range(s) set, or if it is defaulted to
|
|
107
90
|
* {@link module:engine/model/document~Document#_getDefaultRange document's default range}.
|
|
108
|
-
*
|
|
109
|
-
* @readonly
|
|
110
|
-
* @type {Boolean}
|
|
111
91
|
*/
|
|
112
92
|
get hasOwnRange() {
|
|
113
93
|
return this._selection.hasOwnRange;
|
|
@@ -126,9 +106,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
126
106
|
* Describes whether the gravity is overridden (using {@link module:engine/model/writer~Writer#overrideSelectionGravity}) or not.
|
|
127
107
|
*
|
|
128
108
|
* Note that the gravity remains overridden as long as will not be restored the same number of times as it was overridden.
|
|
129
|
-
*
|
|
130
|
-
* @readonly
|
|
131
|
-
* @returns {Boolean}
|
|
132
109
|
*/
|
|
133
110
|
get isGravityOverridden() {
|
|
134
111
|
return this._selection.isGravityOverridden;
|
|
@@ -138,9 +115,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
138
115
|
* Marker is a selection marker when selection range is inside the marker range.
|
|
139
116
|
*
|
|
140
117
|
* **Note**: Only markers from {@link ~DocumentSelection#observeMarkers observed markers groups} are collected.
|
|
141
|
-
*
|
|
142
|
-
* @readonly
|
|
143
|
-
* @type {module:utils/collection~Collection}
|
|
144
118
|
*/
|
|
145
119
|
get markers() {
|
|
146
120
|
return this._selection.markers;
|
|
@@ -149,15 +123,12 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
149
123
|
* Used for the compatibility with the {@link module:engine/model/selection~Selection#isEqual} method.
|
|
150
124
|
*
|
|
151
125
|
* @internal
|
|
152
|
-
* @protected
|
|
153
126
|
*/
|
|
154
127
|
get _ranges() {
|
|
155
128
|
return this._selection._ranges;
|
|
156
129
|
}
|
|
157
130
|
/**
|
|
158
131
|
* Returns an iterable that iterates over copies of selection ranges.
|
|
159
|
-
*
|
|
160
|
-
* @returns {Iterable.<module:engine/model/range~Range>}
|
|
161
132
|
*/
|
|
162
133
|
getRanges() {
|
|
163
134
|
return this._selection.getRanges();
|
|
@@ -168,8 +139,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
168
139
|
* any other position in the selection.
|
|
169
140
|
*
|
|
170
141
|
* Returns `null` if there are no ranges in selection.
|
|
171
|
-
*
|
|
172
|
-
* @returns {module:engine/model/position~Position|null}
|
|
173
142
|
*/
|
|
174
143
|
getFirstPosition() {
|
|
175
144
|
return this._selection.getFirstPosition();
|
|
@@ -180,8 +149,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
180
149
|
* any other position in the selection.
|
|
181
150
|
*
|
|
182
151
|
* Returns `null` if there are no ranges in selection.
|
|
183
|
-
*
|
|
184
|
-
* @returns {module:engine/model/position~Position|null}
|
|
185
152
|
*/
|
|
186
153
|
getLastPosition() {
|
|
187
154
|
return this._selection.getLastPosition();
|
|
@@ -193,8 +160,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
193
160
|
* (not to confuse with the first range added to the selection).
|
|
194
161
|
*
|
|
195
162
|
* Returns `null` if there are no ranges in selection.
|
|
196
|
-
*
|
|
197
|
-
* @returns {module:engine/model/range~Range|null}
|
|
198
163
|
*/
|
|
199
164
|
getFirstRange() {
|
|
200
165
|
return this._selection.getFirstRange();
|
|
@@ -206,8 +171,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
206
171
|
* recently added to the selection).
|
|
207
172
|
*
|
|
208
173
|
* Returns `null` if there are no ranges in selection.
|
|
209
|
-
*
|
|
210
|
-
* @returns {module:engine/model/range~Range|null}
|
|
211
174
|
*/
|
|
212
175
|
getLastRange() {
|
|
213
176
|
return this._selection.getLastRange();
|
|
@@ -222,40 +185,48 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
222
185
|
*
|
|
223
186
|
* In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):
|
|
224
187
|
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
188
|
+
* ```
|
|
189
|
+
* <paragraph>[a</paragraph>
|
|
190
|
+
* <blockQuote>
|
|
191
|
+
* <paragraph>b</paragraph>
|
|
192
|
+
* </blockQuote>
|
|
193
|
+
* <paragraph>c]d</paragraph>
|
|
194
|
+
* ```
|
|
230
195
|
*
|
|
231
196
|
* In this case the paragraph will also be returned, despite the collapsed selection:
|
|
232
197
|
*
|
|
233
|
-
*
|
|
198
|
+
* ```
|
|
199
|
+
* <paragraph>[]a</paragraph>
|
|
200
|
+
* ```
|
|
234
201
|
*
|
|
235
202
|
* In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:
|
|
236
203
|
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
204
|
+
* ```
|
|
205
|
+
* [<blockA></blockA>
|
|
206
|
+
* <blockB>
|
|
207
|
+
* <blockC></blockC>
|
|
208
|
+
* <blockD></blockD>
|
|
209
|
+
* </blockB>
|
|
210
|
+
* <blockE></blockE>]
|
|
211
|
+
* ```
|
|
243
212
|
*
|
|
244
213
|
* If the selection is inside a block all the inner blocks (A & B) are returned:
|
|
245
214
|
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
215
|
+
* ```
|
|
216
|
+
* <block>
|
|
217
|
+
* <blockA>[a</blockA>
|
|
218
|
+
* <blockB>b]</blockB>
|
|
219
|
+
* </block>
|
|
220
|
+
* ```
|
|
250
221
|
*
|
|
251
222
|
* **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective
|
|
252
223
|
* this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.
|
|
253
224
|
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
225
|
+
* ```
|
|
226
|
+
* <paragraph>[a</paragraph>
|
|
227
|
+
* <paragraph>b</paragraph>
|
|
228
|
+
* <paragraph>]c</paragraph> // this block will not be returned
|
|
229
|
+
* ```
|
|
259
230
|
*/
|
|
260
231
|
getSelectedBlocks() {
|
|
261
232
|
return this._selection.getSelectedBlocks();
|
|
@@ -264,8 +235,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
264
235
|
* Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only
|
|
265
236
|
* one range in the selection, and that range contains exactly one element.
|
|
266
237
|
* Returns `null` if there is no selected element.
|
|
267
|
-
*
|
|
268
|
-
* @returns {module:engine/model/element~Element|null}
|
|
269
238
|
*/
|
|
270
239
|
getSelectedElement() {
|
|
271
240
|
return this._selection.getSelectedElement();
|
|
@@ -277,9 +246,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
277
246
|
*
|
|
278
247
|
* By default, this method will check whether the entire content of the selection's current root is selected.
|
|
279
248
|
* Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.
|
|
280
|
-
*
|
|
281
|
-
* @param {module:engine/model/element~Element} [element=this.anchor.root]
|
|
282
|
-
* @returns {Boolean}
|
|
283
249
|
*/
|
|
284
250
|
containsEntireContent(element) {
|
|
285
251
|
return this._selection.containsEntireContent(element);
|
|
@@ -292,8 +258,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
292
258
|
}
|
|
293
259
|
/**
|
|
294
260
|
* Returns iterable that iterates over this selection's attribute keys.
|
|
295
|
-
*
|
|
296
|
-
* @returns {Iterable.<String>}
|
|
297
261
|
*/
|
|
298
262
|
getAttributeKeys() {
|
|
299
263
|
return this._selection.getAttributeKeys();
|
|
@@ -303,8 +267,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
303
267
|
*
|
|
304
268
|
* Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
|
|
305
269
|
* This format is accepted by native `Map` object and also can be passed in `Node` constructor.
|
|
306
|
-
*
|
|
307
|
-
* @returns {Iterable.<*>}
|
|
308
270
|
*/
|
|
309
271
|
getAttributes() {
|
|
310
272
|
return this._selection.getAttributes();
|
|
@@ -312,8 +274,8 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
312
274
|
/**
|
|
313
275
|
* Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.
|
|
314
276
|
*
|
|
315
|
-
* @param
|
|
316
|
-
* @returns
|
|
277
|
+
* @param key Key of attribute to look for.
|
|
278
|
+
* @returns Attribute value or `undefined`.
|
|
317
279
|
*/
|
|
318
280
|
getAttribute(key) {
|
|
319
281
|
return this._selection.getAttribute(key);
|
|
@@ -321,8 +283,8 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
321
283
|
/**
|
|
322
284
|
* Checks if the selection has an attribute for given key.
|
|
323
285
|
*
|
|
324
|
-
* @param
|
|
325
|
-
* @returns
|
|
286
|
+
* @param key Key of attribute to check.
|
|
287
|
+
* @returns `true` if attribute with given key is set on selection, `false` otherwise.
|
|
326
288
|
*/
|
|
327
289
|
hasAttribute(key) {
|
|
328
290
|
return this._selection.hasAttribute(key);
|
|
@@ -340,7 +302,7 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
340
302
|
*
|
|
341
303
|
* See also {@link module:engine/model/markercollection~MarkerCollection#getMarkersGroup `MarkerCollection#getMarkersGroup()`}.
|
|
342
304
|
*
|
|
343
|
-
* @param
|
|
305
|
+
* @param prefixOrName The marker group prefix or marker name.
|
|
344
306
|
*/
|
|
345
307
|
observeMarkers(prefixOrName) {
|
|
346
308
|
this._selection.observeMarkers(prefixOrName);
|
|
@@ -354,9 +316,7 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
354
316
|
*
|
|
355
317
|
* @see module:engine/model/writer~Writer#setSelectionFocus
|
|
356
318
|
* @internal
|
|
357
|
-
* @
|
|
358
|
-
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
|
|
359
|
-
* @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
|
|
319
|
+
* @param offset Offset or one of the flags. Used only when
|
|
360
320
|
* first parameter is a {@link module:engine/model/item~Item model item}.
|
|
361
321
|
*/
|
|
362
322
|
_setFocus(itemOrPosition, offset) {
|
|
@@ -369,11 +329,6 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
369
329
|
*
|
|
370
330
|
* @see module:engine/model/writer~Writer#setSelection
|
|
371
331
|
* @internal
|
|
372
|
-
* @protected
|
|
373
|
-
* @param {module:engine/model/selection~Selectable} selectable
|
|
374
|
-
* @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.
|
|
375
|
-
* @param {Object} [options]
|
|
376
|
-
* @param {Boolean} [options.backward] Sets this selection instance to be backward.
|
|
377
332
|
*/
|
|
378
333
|
_setTo(...args) {
|
|
379
334
|
this._selection.setTo(...args);
|
|
@@ -384,9 +339,8 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
384
339
|
*
|
|
385
340
|
* @see module:engine/model/writer~Writer#setSelectionAttribute
|
|
386
341
|
* @internal
|
|
387
|
-
* @
|
|
388
|
-
* @param
|
|
389
|
-
* @param {*} value Attribute value.
|
|
342
|
+
* @param key Key of the attribute to set.
|
|
343
|
+
* @param value Attribute value.
|
|
390
344
|
*/
|
|
391
345
|
_setAttribute(key, value) {
|
|
392
346
|
this._selection.setAttribute(key, value);
|
|
@@ -399,8 +353,7 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
399
353
|
*
|
|
400
354
|
* @see module:engine/model/writer~Writer#removeSelectionAttribute
|
|
401
355
|
* @internal
|
|
402
|
-
* @
|
|
403
|
-
* @param {String} key Key of the attribute to remove.
|
|
356
|
+
* @param key Key of the attribute to remove.
|
|
404
357
|
*/
|
|
405
358
|
_removeAttribute(key) {
|
|
406
359
|
this._selection.removeAttribute(key);
|
|
@@ -408,8 +361,7 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
408
361
|
/**
|
|
409
362
|
* Returns an iterable that iterates through all selection attributes stored in current selection's parent.
|
|
410
363
|
*
|
|
411
|
-
* @
|
|
412
|
-
* @returns {Iterable.<*>}
|
|
364
|
+
* @internal
|
|
413
365
|
*/
|
|
414
366
|
_getStoredAttributes() {
|
|
415
367
|
return this._selection.getStoredAttributes();
|
|
@@ -426,8 +378,7 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
426
378
|
*
|
|
427
379
|
* @see module:engine/model/writer~Writer#overrideSelectionGravity
|
|
428
380
|
* @internal
|
|
429
|
-
* @
|
|
430
|
-
* @returns {String} The unique id which allows restoring the gravity.
|
|
381
|
+
* @returns The unique id which allows restoring the gravity.
|
|
431
382
|
*/
|
|
432
383
|
_overrideGravity() {
|
|
433
384
|
return this._selection.overrideGravity();
|
|
@@ -441,8 +392,7 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
441
392
|
*
|
|
442
393
|
* @see module:engine/model/writer~Writer#restoreSelectionGravity
|
|
443
394
|
* @internal
|
|
444
|
-
* @
|
|
445
|
-
* @param {String} uid The unique id returned by {@link #_overrideGravity}.
|
|
395
|
+
* @param uid The unique id returned by {@link #_overrideGravity}.
|
|
446
396
|
*/
|
|
447
397
|
_restoreGravity(uid) {
|
|
448
398
|
this._selection.restoreGravity(uid);
|
|
@@ -451,9 +401,8 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
451
401
|
* Generates and returns an attribute key for selection attributes store, basing on original attribute key.
|
|
452
402
|
*
|
|
453
403
|
* @internal
|
|
454
|
-
* @
|
|
455
|
-
* @
|
|
456
|
-
* @returns {String} Converted attribute key, applicable for selection store.
|
|
404
|
+
* @param key Attribute key to convert.
|
|
405
|
+
* @returns Converted attribute key, applicable for selection store.
|
|
457
406
|
*/
|
|
458
407
|
static _getStoreAttributeKey(key) {
|
|
459
408
|
return storePrefix + key;
|
|
@@ -461,98 +410,74 @@ export default class DocumentSelection extends EmitterMixin(TypeCheckable) {
|
|
|
461
410
|
/**
|
|
462
411
|
* Checks whether the given attribute key is an attribute stored on an element.
|
|
463
412
|
*
|
|
464
|
-
* @
|
|
465
|
-
* @param {String} key
|
|
466
|
-
* @returns {Boolean}
|
|
413
|
+
* @internal
|
|
467
414
|
*/
|
|
468
415
|
static _isStoreAttributeKey(key) {
|
|
469
416
|
return key.startsWith(storePrefix);
|
|
470
417
|
}
|
|
471
418
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
*
|
|
475
|
-
* selection.is( 'selection' ); // -> true
|
|
476
|
-
* selection.is( 'documentSelection' ); // -> true
|
|
477
|
-
* selection.is( 'model:selection' ); // -> true
|
|
478
|
-
* selection.is( 'model:documentSelection' ); // -> true
|
|
479
|
-
*
|
|
480
|
-
* selection.is( 'view:selection' ); // -> false
|
|
481
|
-
* selection.is( 'element' ); // -> false
|
|
482
|
-
* selection.is( 'node' ); // -> false
|
|
483
|
-
*
|
|
484
|
-
* {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.
|
|
485
|
-
*
|
|
486
|
-
* @param {String} type
|
|
487
|
-
* @returns {Boolean}
|
|
488
|
-
*/
|
|
419
|
+
// The magic of type inference using `is` method is centralized in `TypeCheckable` class.
|
|
420
|
+
// Proper overload would interfere with that.
|
|
489
421
|
DocumentSelection.prototype.is = function (type) {
|
|
490
422
|
return type === 'selection' ||
|
|
491
423
|
type == 'model:selection' ||
|
|
492
424
|
type == 'documentSelection' ||
|
|
493
425
|
type == 'model:documentSelection';
|
|
494
426
|
};
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
//
|
|
427
|
+
/**
|
|
428
|
+
* `LiveSelection` is used internally by {@link module:engine/model/documentselection~DocumentSelection} and shouldn't be used directly.
|
|
429
|
+
*
|
|
430
|
+
* LiveSelection` is automatically updated upon changes in the {@link module:engine/model/document~Document document}
|
|
431
|
+
* to always contain valid ranges. Its attributes are inherited from the text unless set explicitly.
|
|
432
|
+
*
|
|
433
|
+
* Differences between {@link module:engine/model/selection~Selection} and `LiveSelection` are:
|
|
434
|
+
* * there is always a range in `LiveSelection` - even if no ranges were added there is a "default range"
|
|
435
|
+
* present in the selection,
|
|
436
|
+
* * ranges added to this selection updates automatically when the document changes,
|
|
437
|
+
* * attributes of `LiveSelection` are updated automatically according to selection ranges.
|
|
438
|
+
*/
|
|
508
439
|
class LiveSelection extends Selection {
|
|
509
|
-
|
|
510
|
-
|
|
440
|
+
/**
|
|
441
|
+
* Creates an empty live selection for given {@link module:engine/model/document~Document}.
|
|
442
|
+
*
|
|
443
|
+
* @param doc Document which owns this selection.
|
|
444
|
+
*/
|
|
511
445
|
constructor(doc) {
|
|
512
446
|
super();
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
447
|
+
/**
|
|
448
|
+
* List of selection markers.
|
|
449
|
+
* Marker is a selection marker when selection range is inside the marker range.
|
|
450
|
+
*/
|
|
517
451
|
this.markers = new Collection({ idProperty: 'name' });
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
// @protected
|
|
526
|
-
// @member {module:engine/model/document~Document}
|
|
527
|
-
this._document = doc;
|
|
528
|
-
// Keeps mapping of attribute name to priority with which the attribute got modified (added/changed/removed)
|
|
529
|
-
// last time. Possible values of priority are: `'low'` and `'normal'`.
|
|
530
|
-
//
|
|
531
|
-
// Priorities are used by internal `LiveSelection` mechanisms. All attributes set using `LiveSelection`
|
|
532
|
-
// attributes API are set with `'normal'` priority.
|
|
533
|
-
//
|
|
534
|
-
// @private
|
|
535
|
-
// @member {Map} module:engine/model/liveselection~LiveSelection#_attributePriority
|
|
452
|
+
/**
|
|
453
|
+
* Keeps mapping of attribute name to priority with which the attribute got modified (added/changed/removed)
|
|
454
|
+
* last time. Possible values of priority are: `'low'` and `'normal'`.
|
|
455
|
+
*
|
|
456
|
+
* Priorities are used by internal `LiveSelection` mechanisms. All attributes set using `LiveSelection`
|
|
457
|
+
* attributes API are set with `'normal'` priority.
|
|
458
|
+
*/
|
|
536
459
|
this._attributePriority = new Map();
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
460
|
+
/**
|
|
461
|
+
* Position to which the selection should be set if the last selection range was moved to the graveyard.
|
|
462
|
+
*/
|
|
540
463
|
this._selectionRestorePosition = null;
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
464
|
+
/**
|
|
465
|
+
* Flag that informs whether the selection ranges have changed. It is changed on true when `LiveRange#change:range` event is fired.
|
|
466
|
+
*/
|
|
544
467
|
this._hasChangedRange = false;
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
468
|
+
/**
|
|
469
|
+
* Each overriding gravity adds an UID to the set and each removal removes it.
|
|
470
|
+
* Gravity is overridden when there's at least one UID in the set.
|
|
471
|
+
* Gravity is restored when the set is empty.
|
|
472
|
+
* This is to prevent conflicts when gravity is overridden by more than one feature at the same time.
|
|
473
|
+
*/
|
|
551
474
|
this._overriddenGravityRegister = new Set();
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
475
|
+
/**
|
|
476
|
+
* Prefixes of marker names that should affect `LiveSelection#markers` collection.
|
|
477
|
+
*/
|
|
555
478
|
this._observedMarkers = new Set();
|
|
479
|
+
this._model = doc.model;
|
|
480
|
+
this._document = doc;
|
|
556
481
|
// Ensure selection is correct after each operation.
|
|
557
482
|
this.listenTo(this._model, 'applyOperation', (evt, args) => {
|
|
558
483
|
const operation = args[0];
|
|
@@ -597,23 +522,23 @@ class LiveSelection extends Selection {
|
|
|
597
522
|
get rangeCount() {
|
|
598
523
|
return this._ranges.length ? this._ranges.length : 1;
|
|
599
524
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
// @type {Boolean}
|
|
525
|
+
/**
|
|
526
|
+
* Describes whether `LiveSelection` has own range(s) set, or if it is defaulted to
|
|
527
|
+
* {@link module:engine/model/document~Document#_getDefaultRange document's default range}.
|
|
528
|
+
*/
|
|
605
529
|
get hasOwnRange() {
|
|
606
530
|
return this._ranges.length > 0;
|
|
607
531
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
// @type {Boolean}
|
|
532
|
+
/**
|
|
533
|
+
* When set to `true` then selection attributes on node before the caret won't be taken
|
|
534
|
+
* into consideration while updating selection attributes.
|
|
535
|
+
*/
|
|
613
536
|
get isGravityOverridden() {
|
|
614
537
|
return !!this._overriddenGravityRegister.size;
|
|
615
538
|
}
|
|
616
|
-
|
|
539
|
+
/**
|
|
540
|
+
* Unbinds all events previously bound by live selection.
|
|
541
|
+
*/
|
|
617
542
|
destroy() {
|
|
618
543
|
for (let i = 0; i < this._ranges.length; i++) {
|
|
619
544
|
this._ranges[i].detach();
|
|
@@ -675,7 +600,7 @@ class LiveSelection extends Selection {
|
|
|
675
600
|
* UID obtained from the {@link module:engine/model/writer~Writer#overrideSelectionGravity} to restore.
|
|
676
601
|
*
|
|
677
602
|
* @error document-selection-gravity-wrong-restore
|
|
678
|
-
* @param
|
|
603
|
+
* @param uid The unique identifier returned by
|
|
679
604
|
* {@link module:engine/model/documentselection~DocumentSelection#_overrideGravity}.
|
|
680
605
|
*/
|
|
681
606
|
throw new CKEditorError('document-selection-gravity-wrong-restore', this, { uid });
|
|
@@ -712,18 +637,17 @@ class LiveSelection extends Selection {
|
|
|
712
637
|
* starts or ends at incorrect position.
|
|
713
638
|
*
|
|
714
639
|
* @error document-selection-wrong-position
|
|
715
|
-
* @param
|
|
640
|
+
* @param range
|
|
716
641
|
*/
|
|
717
642
|
throw new CKEditorError('document-selection-wrong-position', this, { range });
|
|
718
643
|
}
|
|
719
644
|
}
|
|
720
645
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
// @param {module:engine/model/range~Range} range
|
|
646
|
+
/**
|
|
647
|
+
* Prepares given range to be added to selection. Checks if it is correct,
|
|
648
|
+
* converts it to {@link module:engine/model/liverange~LiveRange LiveRange}
|
|
649
|
+
* and sets listeners listening to the range's change event.
|
|
650
|
+
*/
|
|
727
651
|
_prepareRange(range) {
|
|
728
652
|
this._checkRange(range);
|
|
729
653
|
if (range.root == this._document.graveyard) {
|
|
@@ -814,11 +738,9 @@ class LiveSelection extends Selection {
|
|
|
814
738
|
this.fire('change:marker', { oldMarkers, directChange: false });
|
|
815
739
|
}
|
|
816
740
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
// @param {Boolean} clearAll
|
|
821
|
-
// @fires change:attribute
|
|
741
|
+
/**
|
|
742
|
+
* Updates this selection attributes according to its ranges and the {@link module:engine/model/document~Document model document}.
|
|
743
|
+
*/
|
|
822
744
|
_updateAttributes(clearAll) {
|
|
823
745
|
const newAttributes = toMap(this._getSurroundingAttributes());
|
|
824
746
|
const oldAttributes = toMap(this.getAttributes());
|
|
@@ -857,15 +779,10 @@ class LiveSelection extends Selection {
|
|
|
857
779
|
this.fire('change:attribute', { attributeKeys: changed, directChange: false });
|
|
858
780
|
}
|
|
859
781
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
// @param {String} key Attribute key.
|
|
865
|
-
// @param {*} value Attribute value.
|
|
866
|
-
// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change
|
|
867
|
-
// is caused by `Batch` API.
|
|
868
|
-
// @returns {Boolean} Whether value has changed.
|
|
782
|
+
/**
|
|
783
|
+
* Internal method for setting `LiveSelection` attribute. Supports attribute priorities (through `directChange`
|
|
784
|
+
* parameter).
|
|
785
|
+
*/
|
|
869
786
|
_setAttribute(key, value, directChange = true) {
|
|
870
787
|
const priority = directChange ? 'normal' : 'low';
|
|
871
788
|
if (priority == 'low' && this._attributePriority.get(key) == 'normal') {
|
|
@@ -882,18 +799,13 @@ class LiveSelection extends Selection {
|
|
|
882
799
|
this._attributePriority.set(key, priority);
|
|
883
800
|
return true;
|
|
884
801
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
// @param {String} key Attribute key.
|
|
893
|
-
// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change
|
|
894
|
-
// is caused by `Batch` API.
|
|
895
|
-
// @returns {Boolean} Whether attribute was removed. May not be true if such attributes didn't exist or the
|
|
896
|
-
// existing attribute had higher priority.
|
|
802
|
+
/**
|
|
803
|
+
* Internal method for removing `LiveSelection` attribute. Supports attribute priorities (through `directChange`
|
|
804
|
+
* parameter).
|
|
805
|
+
*
|
|
806
|
+
* NOTE: Even if attribute is not present in the selection but is provided to this method, it's priority will
|
|
807
|
+
* be changed according to `directChange` parameter.
|
|
808
|
+
*/
|
|
897
809
|
_removeAttribute(key, directChange = true) {
|
|
898
810
|
const priority = directChange ? 'normal' : 'low';
|
|
899
811
|
if (priority == 'low' && this._attributePriority.get(key) == 'normal') {
|
|
@@ -909,12 +821,10 @@ class LiveSelection extends Selection {
|
|
|
909
821
|
this._attrs.delete(key);
|
|
910
822
|
return true;
|
|
911
823
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
// @param {Map.<String,*>} attrs Iterable object containing attributes to be set.
|
|
917
|
-
// @returns {Set.<String>} Changed attribute keys.
|
|
824
|
+
/**
|
|
825
|
+
* Internal method for setting multiple `LiveSelection` attributes. Supports attribute priorities (through
|
|
826
|
+
* `directChange` parameter).
|
|
827
|
+
*/
|
|
918
828
|
_setAttributesTo(attrs) {
|
|
919
829
|
const changed = new Set();
|
|
920
830
|
for (const [oldKey, oldValue] of this.getAttributes()) {
|
|
@@ -934,10 +844,9 @@ class LiveSelection extends Selection {
|
|
|
934
844
|
}
|
|
935
845
|
return changed;
|
|
936
846
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
// @returns {Iterable.<*>}
|
|
847
|
+
/**
|
|
848
|
+
* Returns an iterable that iterates through all selection attributes stored in current selection's parent.
|
|
849
|
+
*/
|
|
941
850
|
*getStoredAttributes() {
|
|
942
851
|
const selectionParent = this.getFirstPosition().parent;
|
|
943
852
|
if (this.isCollapsed && selectionParent.isEmpty) {
|
|
@@ -949,12 +858,11 @@ class LiveSelection extends Selection {
|
|
|
949
858
|
}
|
|
950
859
|
}
|
|
951
860
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
// @returns {Iterable.<*>} Collection of attributes.
|
|
861
|
+
/**
|
|
862
|
+
* Checks model text nodes that are closest to the selection's first position and returns attributes of first
|
|
863
|
+
* found element. If there are no text nodes in selection's first position parent, it returns selection
|
|
864
|
+
* attributes stored in that parent.
|
|
865
|
+
*/
|
|
958
866
|
_getSurroundingAttributes() {
|
|
959
867
|
const position = this.getFirstPosition();
|
|
960
868
|
const schema = this._model.schema;
|
|
@@ -1011,10 +919,10 @@ class LiveSelection extends Selection {
|
|
|
1011
919
|
}
|
|
1012
920
|
return attrs;
|
|
1013
921
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
922
|
+
/**
|
|
923
|
+
* Fixes the selection after all its ranges got removed.
|
|
924
|
+
* @param deletionPosition Position where the deletion happened.
|
|
925
|
+
*/
|
|
1018
926
|
_fixGraveyardSelection(deletionPosition) {
|
|
1019
927
|
// Find a range that is a correct selection range and is closest to the position where the deletion happened.
|
|
1020
928
|
const selectionRange = this._model.schema.getNearestSelectionRange(deletionPosition);
|
|
@@ -1026,22 +934,20 @@ class LiveSelection extends Selection {
|
|
|
1026
934
|
// If nearest valid selection range cannot be found don't add any range. Selection will be set to the default range.
|
|
1027
935
|
}
|
|
1028
936
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
// @returns {Boolean}
|
|
937
|
+
/**
|
|
938
|
+
* Helper function for {@link module:engine/model/liveselection~LiveSelection#_updateAttributes}.
|
|
939
|
+
*
|
|
940
|
+
* It takes model item, checks whether it is a text node (or text proxy) and, if so, returns it's attributes. If not, returns `null`.
|
|
941
|
+
*/
|
|
1035
942
|
function getAttrsIfCharacter(node) {
|
|
1036
943
|
if (node instanceof TextProxy || node instanceof Text) {
|
|
1037
944
|
return node.getAttributes();
|
|
1038
945
|
}
|
|
1039
946
|
return null;
|
|
1040
947
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
// @param {module:engine/model/batch~Batch} batch
|
|
948
|
+
/**
|
|
949
|
+
* Removes selection attributes from element which is not empty anymore.
|
|
950
|
+
*/
|
|
1045
951
|
function clearAttributesStoredInElement(model, batch) {
|
|
1046
952
|
const differ = model.document.differ;
|
|
1047
953
|
for (const entry of differ.getChanges()) {
|