@ckeditor/ckeditor5-engine 31.0.0 → 33.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/LICENSE.md +2 -2
  2. package/package.json +25 -25
  3. package/src/controller/datacontroller.js +71 -80
  4. package/src/controller/editingcontroller.js +83 -6
  5. package/src/conversion/conversion.js +15 -14
  6. package/src/conversion/conversionhelpers.js +1 -1
  7. package/src/conversion/downcastdispatcher.js +298 -367
  8. package/src/conversion/downcasthelpers.js +771 -63
  9. package/src/conversion/mapper.js +105 -60
  10. package/src/conversion/modelconsumable.js +85 -35
  11. package/src/conversion/upcastdispatcher.js +3 -6
  12. package/src/conversion/upcasthelpers.js +4 -2
  13. package/src/conversion/viewconsumable.js +1 -1
  14. package/src/dataprocessor/basichtmlwriter.js +1 -1
  15. package/src/dataprocessor/dataprocessor.jsdoc +1 -1
  16. package/src/dataprocessor/htmldataprocessor.js +9 -31
  17. package/src/dataprocessor/htmlwriter.js +1 -1
  18. package/src/dataprocessor/xmldataprocessor.js +1 -1
  19. package/src/dev-utils/model.js +16 -14
  20. package/src/dev-utils/operationreplayer.js +1 -1
  21. package/src/dev-utils/utils.js +1 -1
  22. package/src/dev-utils/view.js +7 -7
  23. package/src/index.js +2 -1
  24. package/src/model/batch.js +77 -10
  25. package/src/model/differ.js +87 -59
  26. package/src/model/document.js +13 -4
  27. package/src/model/documentfragment.js +1 -1
  28. package/src/model/documentselection.js +1 -1
  29. package/src/model/element.js +1 -1
  30. package/src/model/history.js +1 -1
  31. package/src/model/item.jsdoc +1 -1
  32. package/src/model/liveposition.js +1 -1
  33. package/src/model/liverange.js +1 -1
  34. package/src/model/markercollection.js +29 -5
  35. package/src/model/model.js +18 -9
  36. package/src/model/node.js +1 -1
  37. package/src/model/nodelist.js +1 -1
  38. package/src/model/operation/attributeoperation.js +1 -1
  39. package/src/model/operation/detachoperation.js +1 -1
  40. package/src/model/operation/insertoperation.js +1 -1
  41. package/src/model/operation/markeroperation.js +1 -1
  42. package/src/model/operation/mergeoperation.js +1 -1
  43. package/src/model/operation/moveoperation.js +1 -1
  44. package/src/model/operation/nooperation.js +1 -1
  45. package/src/model/operation/operation.js +1 -1
  46. package/src/model/operation/operationfactory.js +1 -1
  47. package/src/model/operation/renameoperation.js +1 -1
  48. package/src/model/operation/rootattributeoperation.js +1 -1
  49. package/src/model/operation/splitoperation.js +1 -1
  50. package/src/model/operation/transform.js +1 -1
  51. package/src/model/operation/utils.js +1 -1
  52. package/src/model/position.js +1 -1
  53. package/src/model/range.js +1 -1
  54. package/src/model/rootelement.js +1 -1
  55. package/src/model/schema.js +1 -1
  56. package/src/model/selection.js +1 -1
  57. package/src/model/text.js +1 -1
  58. package/src/model/textproxy.js +1 -1
  59. package/src/model/treewalker.js +1 -1
  60. package/src/model/utils/autoparagraphing.js +1 -1
  61. package/src/model/utils/deletecontent.js +1 -1
  62. package/src/model/utils/getselectedcontent.js +1 -1
  63. package/src/model/utils/insertcontent.js +1 -1
  64. package/src/model/utils/modifyselection.js +15 -8
  65. package/src/model/utils/selection-post-fixer.js +37 -30
  66. package/src/model/writer.js +17 -27
  67. package/src/view/attributeelement.js +1 -1
  68. package/src/view/containerelement.js +1 -1
  69. package/src/view/document.js +3 -2
  70. package/src/view/documentfragment.js +1 -1
  71. package/src/view/documentselection.js +1 -1
  72. package/src/view/domconverter.js +169 -47
  73. package/src/view/downcastwriter.js +121 -5
  74. package/src/view/editableelement.js +1 -1
  75. package/src/view/element.js +29 -1
  76. package/src/view/elementdefinition.jsdoc +1 -1
  77. package/src/view/emptyelement.js +1 -1
  78. package/src/view/filler.js +1 -1
  79. package/src/view/item.jsdoc +1 -1
  80. package/src/view/matcher.js +15 -14
  81. package/src/view/node.js +1 -1
  82. package/src/view/observer/arrowkeysobserver.js +1 -1
  83. package/src/view/observer/bubblingemittermixin.js +1 -1
  84. package/src/view/observer/bubblingeventinfo.js +1 -1
  85. package/src/view/observer/clickobserver.js +1 -1
  86. package/src/view/observer/compositionobserver.js +1 -1
  87. package/src/view/observer/domeventdata.js +1 -1
  88. package/src/view/observer/domeventobserver.js +1 -1
  89. package/src/view/observer/fakeselectionobserver.js +1 -1
  90. package/src/view/observer/focusobserver.js +1 -1
  91. package/src/view/observer/inputobserver.js +1 -1
  92. package/src/view/observer/keyobserver.js +1 -1
  93. package/src/view/observer/mouseobserver.js +1 -1
  94. package/src/view/observer/mutationobserver.js +1 -1
  95. package/src/view/observer/observer.js +1 -1
  96. package/src/view/observer/selectionobserver.js +3 -3
  97. package/src/view/placeholder.js +1 -1
  98. package/src/view/position.js +1 -1
  99. package/src/view/range.js +1 -1
  100. package/src/view/rawelement.js +1 -1
  101. package/src/view/renderer.js +7 -17
  102. package/src/view/rooteditableelement.js +1 -1
  103. package/src/view/selection.js +1 -1
  104. package/src/view/styles/background.js +1 -1
  105. package/src/view/styles/border.js +1 -1
  106. package/src/view/styles/margin.js +1 -1
  107. package/src/view/styles/padding.js +1 -1
  108. package/src/view/styles/utils.js +1 -1
  109. package/src/view/stylesmap.js +1 -1
  110. package/src/view/text.js +1 -1
  111. package/src/view/textproxy.js +1 -1
  112. package/src/view/treewalker.js +1 -1
  113. package/src/view/uielement.js +1 -1
  114. package/src/view/upcastwriter.js +1 -1
  115. package/src/view/view.js +1 -1
  116. package/theme/placeholder.css +10 -1
  117. package/theme/renderer.css +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -106,6 +106,8 @@ export default class MarkerCollection {
106
106
  const oldMarker = this._markers.get( markerName );
107
107
 
108
108
  if ( oldMarker ) {
109
+ const oldMarkerData = oldMarker.getData();
110
+
109
111
  const oldRange = oldMarker.getRange();
110
112
  let hasChanged = false;
111
113
 
@@ -125,7 +127,7 @@ export default class MarkerCollection {
125
127
  }
126
128
 
127
129
  if ( hasChanged ) {
128
- this.fire( 'update:' + markerName, oldMarker, oldRange, range );
130
+ this.fire( 'update:' + markerName, oldMarker, oldRange, range, oldMarkerData );
129
131
  }
130
132
 
131
133
  return oldMarker;
@@ -135,7 +137,7 @@ export default class MarkerCollection {
135
137
  const marker = new Marker( markerName, liveRange, managedUsingOperations, affectsData );
136
138
 
137
139
  this._markers.set( markerName, marker );
138
- this.fire( 'update:' + markerName, marker, null, range );
140
+ this.fire( 'update:' + markerName, marker, null, range, { ...marker.getData(), range: null } );
139
141
 
140
142
  return marker;
141
143
  }
@@ -154,7 +156,7 @@ export default class MarkerCollection {
154
156
 
155
157
  if ( oldMarker ) {
156
158
  this._markers.delete( markerName );
157
- this.fire( 'update:' + markerName, oldMarker, oldMarker.getRange(), null );
159
+ this.fire( 'update:' + markerName, oldMarker, oldMarker.getRange(), null, oldMarker.getData() );
158
160
 
159
161
  this._destroyMarker( oldMarker );
160
162
 
@@ -188,7 +190,7 @@ export default class MarkerCollection {
188
190
 
189
191
  const range = marker.getRange();
190
192
 
191
- this.fire( 'update:' + markerName, marker, range, range, marker.managedUsingOperations, marker.affectsData );
193
+ this.fire( 'update:' + markerName, marker, range, range, marker.getData() );
192
194
  }
193
195
 
194
196
  /**
@@ -273,11 +275,20 @@ export default class MarkerCollection {
273
275
  * means that marker is just added.
274
276
  * @param {module:engine/model/range~Range|null} newRange Marker range after update. When is not defined it
275
277
  * means that marker is just removed.
278
+ * @param {module:engine/model/markercollection~MarkerData} oldMarkerData Data of the marker before the change.
276
279
  */
277
280
  }
278
281
 
279
282
  mix( MarkerCollection, EmitterMixin );
280
283
 
284
+ /**
285
+ * @typedef {Object} module:engine/model/markercollection~MarkerData
286
+ *
287
+ * @property {module:engine/model/range~Range|null} range Marker range. `null` if the marker was removed.
288
+ * @property {Boolean} affectsData A property defining if the marker affects data.
289
+ * @property {Boolean} managedUsingOperations A property defining if the marker is managed using operations.
290
+ */
291
+
281
292
  /**
282
293
  * `Marker` is a continuous parts of model (like a range), is named and represent some kind of information about marked
283
294
  * part of model document. In contrary to {@link module:engine/model/node~Node nodes}, which are building blocks of
@@ -418,6 +429,19 @@ class Marker {
418
429
  return this._affectsData;
419
430
  }
420
431
 
432
+ /**
433
+ * Returns the marker data (properties defining the marker).
434
+ *
435
+ * @returns {module:engine/model/markercollection~MarkerData}
436
+ */
437
+ getData() {
438
+ return {
439
+ range: this.getRange(),
440
+ affectsData: this.affectsData,
441
+ managedUsingOperations: this.managedUsingOperations
442
+ };
443
+ }
444
+
421
445
  /**
422
446
  * Returns current marker start position.
423
447
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -214,8 +214,13 @@ export default class Model {
214
214
  * done in the outer `change()` block.
215
215
  *
216
216
  * Second, it lets you define the {@link module:engine/model/batch~Batch} into which you want to add your changes.
217
- * By default, a new batch is created. In the sample above, `change` and `enqueueChange` blocks use a different
218
- * batch (and different {@link module:engine/model/writer~Writer} since each of them operates on the separate batch).
217
+ * By default, a new batch with the default {@link module:engine/model/batch~Batch#constructor batch type} is created.
218
+ * In the sample above, the `change` and `enqueueChange` blocks will use a different batch (and a different
219
+ * {@link module:engine/model/writer~Writer} instance since each of them operates on a separate batch).
220
+ *
221
+ * model.enqueueChange( { isUndoable: false }, writer => {
222
+ * writer.insertText( 'foo', paragraph, 'end' );
223
+ * } );
219
224
  *
220
225
  * When using the `enqueueChange()` block you can also add some changes to the batch you used before.
221
226
  *
@@ -226,17 +231,20 @@ export default class Model {
226
231
  * In order to make a nested `enqueueChange()` create a single undo step together with the changes done in the outer `change()`
227
232
  * block, you can obtain the batch instance from the {@link module:engine/model/writer~Writer#batch writer} of the outer block.
228
233
  *
229
- * @param {module:engine/model/batch~Batch|'transparent'|'default'} batchOrType Batch or batch type should be used in the callback.
230
- * If not defined, a new batch will be created.
234
+ * @param {module:engine/model/batch~Batch|Object} [batchOrType] A batch or a
235
+ * {@link module:engine/model/batch~Batch#constructor batch type} that should be used in the callback. If not defined, a new batch with
236
+ * the default type will be created.
231
237
  * @param {Function} callback Callback function which may modify the model.
232
238
  */
233
239
  enqueueChange( batchOrType, callback ) {
234
240
  try {
235
- if ( typeof batchOrType === 'string' ) {
236
- batchOrType = new Batch( batchOrType );
237
- } else if ( typeof batchOrType == 'function' ) {
241
+ if ( !batchOrType ) {
242
+ batchOrType = new Batch();
243
+ } else if ( typeof batchOrType === 'function' ) {
238
244
  callback = batchOrType;
239
245
  batchOrType = new Batch();
246
+ } else if ( !( batchOrType instanceof Batch ) ) {
247
+ batchOrType = new Batch( batchOrType );
240
248
  }
241
249
 
242
250
  this._pendingChanges.push( { batch: batchOrType, callback } );
@@ -508,6 +516,7 @@ export default class Model {
508
516
  * @param {Object} [options]
509
517
  * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.
510
518
  * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.
519
+ * @param {Boolean} [options.treatEmojiAsSingleUnit=false] Whether multi-characer emoji sequences should be handled as single unit.
511
520
  */
512
521
  modifySelection( selection, options ) {
513
522
  modifySelection( this, selection, options );
@@ -791,7 +800,7 @@ export default class Model {
791
800
  * * {@link #change `change()`},
792
801
  * * {@link #enqueueChange `enqueueChange()`}.
793
802
  *
794
- * @param {'transparent'|'default'} [type='default'] The type of the batch.
803
+ * @param {Object} [type] {@link module:engine/model/batch~Batch#constructor The type} of the batch.
795
804
  * @returns {module:engine/model/batch~Batch}
796
805
  */
797
806
  createBatch( type ) {
package/src/model/node.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
package/src/model/text.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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 @@
10
10
  import Position from '../position';
11
11
  import TreeWalker from '../treewalker';
12
12
  import Range from '../range';
13
- import { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';
13
+ import { isInsideSurrogatePair, isInsideCombinedSymbol, isInsideEmojiSequence } from '@ckeditor/ckeditor5-utils/src/unicode';
14
14
  import DocumentSelection from '../documentselection';
15
15
 
16
16
  const wordBoundaryCharacters = ' ,.?!:;"-()';
@@ -49,11 +49,13 @@ const wordBoundaryCharacters = ' ,.?!:;"-()';
49
49
  * @param {Object} [options]
50
50
  * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.
51
51
  * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.
52
+ * @param {Boolean} [options.treatEmojiAsSingleUnit=false] Whether multi-characer emoji sequences should be handled as single unit.
52
53
  */
53
54
  export default function modifySelection( model, selection, options = {} ) {
54
55
  const schema = model.schema;
55
56
  const isForward = options.direction != 'backward';
56
57
  const unit = options.unit ? options.unit : 'character';
58
+ const treatEmojiAsSingleUnit = !!options.treatEmojiAsSingleUnit;
57
59
 
58
60
  const focus = selection.focus;
59
61
 
@@ -63,7 +65,7 @@ export default function modifySelection( model, selection, options = {} ) {
63
65
  direction: isForward ? 'forward' : 'backward'
64
66
  } );
65
67
 
66
- const data = { walker, schema, isForward, unit };
68
+ const data = { walker, schema, isForward, unit, treatEmojiAsSingleUnit };
67
69
 
68
70
  let next;
69
71
 
@@ -89,10 +91,10 @@ export default function modifySelection( model, selection, options = {} ) {
89
91
  }
90
92
 
91
93
  // Checks whether the selection can be extended to the the walker's next value (next position).
92
- // @param {{ walker, unit, isForward, schema }} data
94
+ // @param {{ walker, unit, isForward, schema, treatEmojiAsSingleUnit }} data
93
95
  // @param {module:engine/view/treewalker~TreeWalkerValue} value
94
96
  function tryExtendingTo( data, value ) {
95
- const { isForward, walker, unit, schema } = data;
97
+ const { isForward, walker, unit, schema, treatEmojiAsSingleUnit } = data;
96
98
  const { type, item, nextPosition } = value;
97
99
 
98
100
  // If found text, we can certainly put the focus in it. Let's just find a correct position
@@ -102,7 +104,7 @@ function tryExtendingTo( data, value ) {
102
104
  return getCorrectWordBreakPosition( walker, isForward );
103
105
  }
104
106
 
105
- return getCorrectPosition( walker, unit, isForward );
107
+ return getCorrectPosition( walker, unit, treatEmojiAsSingleUnit );
106
108
  }
107
109
 
108
110
  // Entering an element.
@@ -139,14 +141,19 @@ function tryExtendingTo( data, value ) {
139
141
  //
140
142
  // @param {module:engine/model/treewalker~TreeWalker} walker
141
143
  // @param {String} unit The unit by which selection should be modified.
142
- function getCorrectPosition( walker, unit ) {
144
+ // @param {Boolean} treatEmojiAsSingleUnit
145
+ function getCorrectPosition( walker, unit, treatEmojiAsSingleUnit ) {
143
146
  const textNode = walker.position.textNode;
144
147
 
145
148
  if ( textNode ) {
146
149
  const data = textNode.data;
147
150
  let offset = walker.position.offset - textNode.startOffset;
148
151
 
149
- while ( isInsideSurrogatePair( data, offset ) || ( unit == 'character' && isInsideCombinedSymbol( data, offset ) ) ) {
152
+ while (
153
+ isInsideSurrogatePair( data, offset ) ||
154
+ ( unit == 'character' && isInsideCombinedSymbol( data, offset ) ) ||
155
+ ( treatEmojiAsSingleUnit && isInsideEmojiSequence( data, offset ) )
156
+ ) {
150
157
  walker.next();
151
158
 
152
159
  offset = walker.position.offset - textNode.startOffset;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
2
+ * @license Copyright (c) 2003-2022, 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
 
@@ -128,10 +128,10 @@ function tryFixingCollapsedRange( range, schema ) {
128
128
 
129
129
  const nearestSelectionRange = schema.getNearestSelectionRange( originalPosition );
130
130
 
131
- // This might be null ie when editor data is empty or the selection is inside limit element
131
+ // This might be null, i.e. when the editor data is empty or the selection is inside a limit element
132
132
  // that doesn't allow text inside.
133
- // In the first case there is no need to fix the selection range.
134
- // In the second let's go up to the outer selectable element
133
+ // In the first case, there is no need to fix the selection range.
134
+ // In the second, let's go up to the outer selectable element
135
135
  if ( !nearestSelectionRange ) {
136
136
  const ancestorObject = originalPosition.getAncestors().reverse().find( item => schema.isObject( item ) );
137
137
 
@@ -263,35 +263,42 @@ function checkSelectionOnNonLimitElements( start, end, schema ) {
263
263
  return startIsOnBlock || endIsOnBlock;
264
264
  }
265
265
 
266
- // Returns a minimal non-intersecting array of ranges.
267
- //
268
- // @param {Array.<module:engine/model/range~Range>} ranges
269
- // @returns {Array.<module:engine/model/range~Range>}
270
- function mergeIntersectingRanges( ranges ) {
271
- const nonIntersectingRanges = [];
272
-
273
- // First range will always be fine.
274
- nonIntersectingRanges.push( ranges.shift() );
275
-
276
- for ( const range of ranges ) {
277
- const previousRange = nonIntersectingRanges.pop();
278
-
279
- if ( range.isEqual( previousRange ) ) {
280
- // Use only one of two identical ranges.
281
- nonIntersectingRanges.push( previousRange );
282
- } else if ( range.isIntersecting( previousRange ) ) {
283
- // Get the sum of two ranges.
284
- const start = previousRange.start.isAfter( range.start ) ? range.start : previousRange.start;
285
- const end = previousRange.end.isAfter( range.end ) ? previousRange.end : range.end;
286
-
287
- const merged = new Range( start, end );
288
- nonIntersectingRanges.push( merged );
289
- } else {
290
- nonIntersectingRanges.push( previousRange );
291
- nonIntersectingRanges.push( range );
266
+ /**
267
+ * Returns a minimal non-intersecting array of ranges without duplicates.
268
+ *
269
+ * @param {Array.<module:engine/model/range~Range>} Ranges to merge.
270
+ * @returns {Array.<module:engine/model/range~Range>} Array of unique and nonIntersecting ranges.
271
+ */
272
+ export function mergeIntersectingRanges( ranges ) {
273
+ const rangesToMerge = [ ...ranges ];
274
+ const rangeIndexesToRemove = new Set();
275
+ let currentRangeIndex = 1;
276
+
277
+ while ( currentRangeIndex < rangesToMerge.length ) {
278
+ const currentRange = rangesToMerge[ currentRangeIndex ];
279
+ const previousRanges = rangesToMerge.slice( 0, currentRangeIndex );
280
+
281
+ for ( const [ previousRangeIndex, previousRange ] of previousRanges.entries() ) {
282
+ if ( rangeIndexesToRemove.has( previousRangeIndex ) ) {
283
+ continue;
284
+ }
285
+
286
+ if ( currentRange.isEqual( previousRange ) ) {
287
+ rangeIndexesToRemove.add( previousRangeIndex );
288
+ } else if ( currentRange.isIntersecting( previousRange ) ) {
289
+ rangeIndexesToRemove.add( previousRangeIndex );
290
+ rangeIndexesToRemove.add( currentRangeIndex );
291
+
292
+ const mergedRange = currentRange.getJoined( previousRange );
293
+ rangesToMerge.push( mergedRange );
294
+ }
292
295
  }
296
+
297
+ currentRangeIndex++;
293
298
  }
294
299
 
300
+ const nonIntersectingRanges = rangesToMerge.filter( ( _, index ) => !rangeIndexesToRemove.has( index ) );
301
+
295
302
  return nonIntersectingRanges;
296
303
  }
297
304