@ckeditor/ckeditor5-engine 44.3.0-alpha.7 → 45.0.0-alpha.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 (93) hide show
  1. package/LICENSE.md +1 -1
  2. package/dist/index.js +304 -128
  3. package/dist/index.js.map +1 -1
  4. package/package.json +3 -3
  5. package/src/controller/datacontroller.js +40 -0
  6. package/src/controller/editingcontroller.js +16 -0
  7. package/src/conversion/conversion.js +6 -4
  8. package/src/conversion/conversionhelpers.js +1 -0
  9. package/src/conversion/downcastdispatcher.js +10 -0
  10. package/src/conversion/downcasthelpers.js +1 -1
  11. package/src/conversion/mapper.js +92 -95
  12. package/src/conversion/modelconsumable.js +13 -15
  13. package/src/conversion/upcastdispatcher.js +28 -24
  14. package/src/conversion/upcasthelpers.js +1 -1
  15. package/src/conversion/viewconsumable.js +19 -20
  16. package/src/dataprocessor/htmldataprocessor.js +13 -1
  17. package/src/dataprocessor/xmldataprocessor.js +21 -1
  18. package/src/dev-utils/model.js +1 -1
  19. package/src/dev-utils/operationreplayer.js +3 -0
  20. package/src/dev-utils/utils.js +35 -1
  21. package/src/dev-utils/view.js +13 -0
  22. package/src/model/batch.js +20 -0
  23. package/src/model/differ.js +92 -88
  24. package/src/model/document.d.ts +1 -3
  25. package/src/model/document.js +38 -1
  26. package/src/model/documentfragment.js +10 -10
  27. package/src/model/documentselection.js +44 -32
  28. package/src/model/element.js +8 -4
  29. package/src/model/history.js +31 -33
  30. package/src/model/markercollection.js +25 -7
  31. package/src/model/model.js +21 -0
  32. package/src/model/node.js +22 -18
  33. package/src/model/nodelist.js +12 -12
  34. package/src/model/operation/attributeoperation.js +25 -1
  35. package/src/model/operation/detachoperation.js +8 -0
  36. package/src/model/operation/insertoperation.js +18 -0
  37. package/src/model/operation/markeroperation.js +29 -0
  38. package/src/model/operation/mergeoperation.js +16 -0
  39. package/src/model/operation/moveoperation.js +12 -0
  40. package/src/model/operation/operation.js +19 -0
  41. package/src/model/operation/renameoperation.js +12 -0
  42. package/src/model/operation/rootattributeoperation.js +20 -0
  43. package/src/model/operation/rootoperation.js +16 -0
  44. package/src/model/operation/splitoperation.js +19 -0
  45. package/src/model/operation/transform.js +5 -0
  46. package/src/model/position.js +40 -0
  47. package/src/model/range.js +8 -0
  48. package/src/model/rootelement.js +18 -10
  49. package/src/model/schema.js +25 -23
  50. package/src/model/selection.js +10 -10
  51. package/src/model/text.js +6 -0
  52. package/src/model/textproxy.js +12 -0
  53. package/src/model/treewalker.js +49 -0
  54. package/src/model/utils/insertcontent.js +60 -25
  55. package/src/model/writer.js +8 -0
  56. package/src/view/attributeelement.js +23 -23
  57. package/src/view/datatransfer.js +8 -0
  58. package/src/view/document.js +21 -4
  59. package/src/view/documentfragment.js +13 -9
  60. package/src/view/documentselection.js +4 -0
  61. package/src/view/domconverter.d.ts +6 -1
  62. package/src/view/domconverter.js +109 -48
  63. package/src/view/downcastwriter.js +14 -10
  64. package/src/view/element.js +29 -17
  65. package/src/view/matcher.js +1 -1
  66. package/src/view/node.js +9 -1
  67. package/src/view/observer/bubblingeventinfo.js +12 -0
  68. package/src/view/observer/clickobserver.js +4 -7
  69. package/src/view/observer/compositionobserver.js +14 -12
  70. package/src/view/observer/domeventdata.js +17 -1
  71. package/src/view/observer/domeventobserver.js +10 -13
  72. package/src/view/observer/fakeselectionobserver.d.ts +1 -1
  73. package/src/view/observer/fakeselectionobserver.js +5 -1
  74. package/src/view/observer/focusobserver.js +65 -14
  75. package/src/view/observer/inputobserver.js +33 -26
  76. package/src/view/observer/keyobserver.js +4 -7
  77. package/src/view/observer/mouseobserver.js +4 -7
  78. package/src/view/observer/mutationobserver.js +23 -6
  79. package/src/view/observer/observer.js +12 -4
  80. package/src/view/observer/selectionobserver.d.ts +6 -1
  81. package/src/view/observer/selectionobserver.js +94 -17
  82. package/src/view/observer/touchobserver.js +4 -7
  83. package/src/view/position.js +8 -0
  84. package/src/view/range.js +8 -0
  85. package/src/view/renderer.js +142 -70
  86. package/src/view/selection.js +16 -0
  87. package/src/view/stylesmap.js +26 -11
  88. package/src/view/text.js +6 -0
  89. package/src/view/textproxy.js +12 -0
  90. package/src/view/tokenlist.js +4 -6
  91. package/src/view/treewalker.js +42 -0
  92. package/src/view/upcastwriter.js +5 -1
  93. package/src/view/view.js +51 -33
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
4
  */
5
5
  import { logWarning, EmitterMixin, CKEditorError, compareArrays, toArray, toMap, isIterable, ObservableMixin, count, EventInfo, Collection, keyCodes, isText, env, remove as remove$1, insertAt, diff, fastDiff, isNode, isComment, indexOf, global, isValidAttributeName, first, getAncestors, DomEmitterMixin, getCode, isArrowKeyCode, scrollViewportToShowTarget, uid, spliceArray, priorities, isInsideSurrogatePair, isInsideCombinedSymbol, isInsideEmojiSequence } from '@ckeditor/ckeditor5-utils/dist/index.js';
6
- import { clone, isObject, unset, get, merge, set, isPlainObject, extend, debounce, isEqualWith, cloneDeep, isEqual } from 'lodash-es';
6
+ import { clone, isObject, unset, get, merge, set, isPlainObject, extend, debounce, isEqualWith, cloneDeep, isEqual } from 'es-toolkit/compat';
7
7
 
8
8
  // Each document stores information about its placeholder elements and check functions.
9
9
  const documentPlaceholders = new WeakMap();
@@ -1923,10 +1923,10 @@ TextProxy$1.prototype.is = function(type) {
1923
1923
  return [];
1924
1924
  }
1925
1925
  if (expand) {
1926
- this._cachedExpandedStyleNames = this._cachedExpandedStyleNames || this._styleProcessor.getStyleNames(this._styles);
1926
+ this._cachedExpandedStyleNames ||= this._styleProcessor.getStyleNames(this._styles);
1927
1927
  return this._cachedExpandedStyleNames;
1928
1928
  }
1929
- this._cachedStyleNames = this._cachedStyleNames || this.getStylesEntries().map(([key])=>key);
1929
+ this._cachedStyleNames ||= this.getStylesEntries().map(([key])=>key);
1930
1930
  return this._cachedStyleNames;
1931
1931
  }
1932
1932
  /**
@@ -8376,16 +8376,18 @@ const validNodesToInsert = [
8376
8376
  // and we should not do it because the difference between view and DOM could lead to position mapping problems.
8377
8377
  if (this.isComposing && !env.isAndroid) {
8378
8378
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8379
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Rendering aborted while isComposing.',
8380
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-style: italic'
8381
- // @if CK_DEBUG_TYPING // );
8379
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8380
+ // @if CK_DEBUG_TYPING // '%cRendering aborted while isComposing.',
8381
+ // @if CK_DEBUG_TYPING // 'font-style: italic'
8382
+ // @if CK_DEBUG_TYPING // ) );
8382
8383
  // @if CK_DEBUG_TYPING // }
8383
8384
  return;
8384
8385
  }
8385
8386
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8386
- // @if CK_DEBUG_TYPING // console.group( '%c[Renderer]%c Rendering',
8387
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold'
8388
- // @if CK_DEBUG_TYPING // );
8387
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'Renderer',
8388
+ // @if CK_DEBUG_TYPING // '%cRendering',
8389
+ // @if CK_DEBUG_TYPING // 'font-weight: bold'
8390
+ // @if CK_DEBUG_TYPING // ) );
8389
8391
  // @if CK_DEBUG_TYPING // }
8390
8392
  let inlineFillerPosition = null;
8391
8393
  const isInlineFillerRenderingPossible = env.isBlink && !env.isAndroid ? !this.isSelecting : true;
@@ -8662,9 +8664,10 @@ const validNodesToInsert = [
8662
8664
  expectedText = INLINE_FILLER + expectedText;
8663
8665
  }
8664
8666
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8665
- // @if CK_DEBUG_TYPING // console.group( '%c[Renderer]%c Update text',
8666
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: normal'
8667
- // @if CK_DEBUG_TYPING // );
8667
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'Renderer',
8668
+ // @if CK_DEBUG_TYPING // '%cUpdate text',
8669
+ // @if CK_DEBUG_TYPING // 'font-weight: normal'
8670
+ // @if CK_DEBUG_TYPING // ) );
8668
8671
  // @if CK_DEBUG_TYPING // }
8669
8672
  this._updateTextNode(domText, expectedText);
8670
8673
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
@@ -8719,9 +8722,10 @@ const validNodesToInsert = [
8719
8722
  return;
8720
8723
  }
8721
8724
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8722
- // @if CK_DEBUG_TYPING // console.group( '%c[Renderer]%c Update children',
8723
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: normal'
8724
- // @if CK_DEBUG_TYPING // );
8725
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'Renderer',
8726
+ // @if CK_DEBUG_TYPING // '%cUpdate children',
8727
+ // @if CK_DEBUG_TYPING // 'font-weight: normal'
8728
+ // @if CK_DEBUG_TYPING // ) );
8725
8729
  // @if CK_DEBUG_TYPING // }
8726
8730
  // IME on Android inserts a new text node while typing after a link
8727
8731
  // instead of updating an existing text node that follows the link.
@@ -8753,9 +8757,10 @@ const validNodesToInsert = [
8753
8757
  // The composition and different "language" browser extensions are fragile to text node being completely replaced.
8754
8758
  const actions = this._findUpdateActions(diff, actualDomChildren, expectedDomChildren, areTextNodes);
8755
8759
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping && actions.every( a => a == 'equal' ) ) {
8756
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Nothing to update.',
8757
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-style: italic'
8758
- // @if CK_DEBUG_TYPING // );
8760
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8761
+ // @if CK_DEBUG_TYPING // '%cNothing to update.',
8762
+ // @if CK_DEBUG_TYPING // 'font-style: italic'
8763
+ // @if CK_DEBUG_TYPING // ) );
8759
8764
  // @if CK_DEBUG_TYPING // }
8760
8765
  let i = 0;
8761
8766
  const nodesToUnbind = new Set();
@@ -8770,19 +8775,20 @@ const validNodesToInsert = [
8770
8775
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8771
8776
  // @if CK_DEBUG_TYPING // const node = actualDomChildren[ i ];
8772
8777
  // @if CK_DEBUG_TYPING // if ( isText( node ) ) {
8773
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Remove text node' +
8778
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8779
+ // @if CK_DEBUG_TYPING // '%cRemove text node' +
8774
8780
  // @if CK_DEBUG_TYPING // `${ this.isComposing ? ' while composing (may break composition)' : '' }: ` +
8775
8781
  // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( node.data ) }%c (${ node.data.length })`,
8776
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold',
8777
- // @if CK_DEBUG_TYPING // this.isComposing ? 'color: red; font-weight: bold' : '', 'color: blue', ''
8778
- // @if CK_DEBUG_TYPING // );
8782
+ // @if CK_DEBUG_TYPING // this.isComposing ? 'color: red; font-weight: bold' : '',
8783
+ // @if CK_DEBUG_TYPING // 'color: blue', ''
8784
+ // @if CK_DEBUG_TYPING // ) );
8779
8785
  // @if CK_DEBUG_TYPING // } else {
8780
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Remove element' +
8786
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8787
+ // @if CK_DEBUG_TYPING // '%cRemove element' +
8781
8788
  // @if CK_DEBUG_TYPING // `${ this.isComposing ? ' while composing (may break composition)' : '' }: `,
8782
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold',
8783
8789
  // @if CK_DEBUG_TYPING // this.isComposing ? 'color: red; font-weight: bold' : '',
8784
8790
  // @if CK_DEBUG_TYPING // node
8785
- // @if CK_DEBUG_TYPING // );
8791
+ // @if CK_DEBUG_TYPING // ) );
8786
8792
  // @if CK_DEBUG_TYPING // }
8787
8793
  // @if CK_DEBUG_TYPING // }
8788
8794
  nodesToUnbind.add(actualDomChildren[i]);
@@ -8797,18 +8803,20 @@ const validNodesToInsert = [
8797
8803
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8798
8804
  // @if CK_DEBUG_TYPING // const node = expectedDomChildren[ i ];
8799
8805
  // @if CK_DEBUG_TYPING // if ( isText( node ) ) {
8800
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Insert text node' +
8806
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8807
+ // @if CK_DEBUG_TYPING // '%cInsert text node' +
8801
8808
  // @if CK_DEBUG_TYPING // `${ this.isComposing ? ' while composing (may break composition)' : '' }: ` +
8802
8809
  // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( node.data ) }%c (${ node.data.length })`,
8803
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold',
8804
8810
  // @if CK_DEBUG_TYPING // this.isComposing ? 'color: red; font-weight: bold' : '',
8805
- // @if CK_DEBUG_TYPING // 'color: blue', ''
8806
- // @if CK_DEBUG_TYPING // );
8811
+ // @if CK_DEBUG_TYPING // 'color: blue',
8812
+ // @if CK_DEBUG_TYPING // ''
8813
+ // @if CK_DEBUG_TYPING // ) );
8807
8814
  // @if CK_DEBUG_TYPING // } else {
8808
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Insert element:',
8809
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: normal',
8815
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8816
+ // @if CK_DEBUG_TYPING // '%cInsert element:',
8817
+ // @if CK_DEBUG_TYPING // 'font-weight: normal',
8810
8818
  // @if CK_DEBUG_TYPING // node
8811
- // @if CK_DEBUG_TYPING // );
8819
+ // @if CK_DEBUG_TYPING // ) );
8812
8820
  // @if CK_DEBUG_TYPING // }
8813
8821
  // @if CK_DEBUG_TYPING // }
8814
8822
  insertAt(domElement, i, expectedDomChildren[i]);
@@ -8901,10 +8909,13 @@ const validNodesToInsert = [
8901
8909
  const actualText = domText.data;
8902
8910
  if (actualText == expectedText) {
8903
8911
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8904
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Text node does not need update:%c ' +
8912
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8913
+ // @if CK_DEBUG_TYPING // '%cText node does not need update:%c ' +
8905
8914
  // @if CK_DEBUG_TYPING // `${ _escapeTextNodeData( actualText ) }%c (${ actualText.length })`,
8906
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-style: italic', 'color: blue', ''
8907
- // @if CK_DEBUG_TYPING // );
8915
+ // @if CK_DEBUG_TYPING // 'font-style: italic',
8916
+ // @if CK_DEBUG_TYPING // 'color: blue',
8917
+ // @if CK_DEBUG_TYPING // ''
8918
+ // @if CK_DEBUG_TYPING // ) );
8908
8919
  // @if CK_DEBUG_TYPING // }
8909
8920
  return;
8910
8921
  }
@@ -8914,22 +8925,31 @@ const validNodesToInsert = [
8914
8925
  // See: https://github.com/ckeditor/ckeditor5/issues/13994.
8915
8926
  if (env.isAndroid && this.isComposing && actualText.replace(/\u00A0/g, ' ') == expectedText.replace(/\u00A0/g, ' ')) {
8916
8927
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8917
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Text node ignore NBSP changes while composing: ' +
8918
- // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( actualText ) }%c (${ actualText.length }) ->` +
8919
- // @if CK_DEBUG_TYPING // ` %c${ _escapeTextNodeData( expectedText ) }%c (${ expectedText.length })`,
8920
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-style: italic', 'color: blue', '', 'color: blue', ''
8921
- // @if CK_DEBUG_TYPING // );
8928
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8929
+ // @if CK_DEBUG_TYPING // '%cText node ignore NBSP changes while composing: ' +
8930
+ // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( actualText ) }%c (${ actualText.length }) -> ` +
8931
+ // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( expectedText ) }%c (${ expectedText.length })`,
8932
+ // @if CK_DEBUG_TYPING // 'font-style: italic',
8933
+ // @if CK_DEBUG_TYPING // 'color: blue',
8934
+ // @if CK_DEBUG_TYPING // '',
8935
+ // @if CK_DEBUG_TYPING // 'color: blue',
8936
+ // @if CK_DEBUG_TYPING // ''
8937
+ // @if CK_DEBUG_TYPING // ) );
8922
8938
  // @if CK_DEBUG_TYPING // }
8923
8939
  return;
8924
8940
  }
8925
8941
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8926
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Update text node' +
8942
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
8943
+ // @if CK_DEBUG_TYPING // '%cUpdate text node' +
8927
8944
  // @if CK_DEBUG_TYPING // `${ this.isComposing ? ' while composing (may break composition)' : '' }: ` +
8928
- // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( actualText ) }%c (${ actualText.length }) ->` +
8929
- // @if CK_DEBUG_TYPING // ` %c${ _escapeTextNodeData( expectedText ) }%c (${ expectedText.length })`,
8930
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', this.isComposing ? 'color: red; font-weight: bold' : '',
8931
- // @if CK_DEBUG_TYPING // 'color: blue', '', 'color: blue', ''
8932
- // @if CK_DEBUG_TYPING // );
8945
+ // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( actualText ) }%c (${ actualText.length }) -> ` +
8946
+ // @if CK_DEBUG_TYPING // `%c${ _escapeTextNodeData( expectedText ) }%c (${ expectedText.length })`,
8947
+ // @if CK_DEBUG_TYPING // this.isComposing ? 'color: red; font-weight: bold' : '',
8948
+ // @if CK_DEBUG_TYPING // 'color: blue',
8949
+ // @if CK_DEBUG_TYPING // '',
8950
+ // @if CK_DEBUG_TYPING // 'color: blue',
8951
+ // @if CK_DEBUG_TYPING // ''
8952
+ // @if CK_DEBUG_TYPING // ) );
8933
8953
  // @if CK_DEBUG_TYPING // }
8934
8954
  this._updateTextNodeInternal(domText, expectedText);
8935
8955
  }
@@ -8975,6 +8995,11 @@ const validNodesToInsert = [
8975
8995
  }
8976
8996
  // If there is no selection - remove DOM and fake selections.
8977
8997
  if (this.selection.rangeCount === 0) {
8998
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
8999
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
9000
+ // @if CK_DEBUG_TYPING // 'Update DOM selection: remove all ranges'
9001
+ // @if CK_DEBUG_TYPING // ) );
9002
+ // @if CK_DEBUG_TYPING // }
8978
9003
  this._removeDomSelection();
8979
9004
  this._removeFakeSelection();
8980
9005
  return;
@@ -8982,8 +9007,19 @@ const validNodesToInsert = [
8982
9007
  const domRoot = this.domConverter.mapViewToDom(this.selection.editableElement);
8983
9008
  // Do nothing if there is no focus, or there is no DOM element corresponding to selection's editable element.
8984
9009
  if (!this.isFocused || !domRoot) {
9010
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9011
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
9012
+ // @if CK_DEBUG_TYPING // 'Skip updating DOM selection:',
9013
+ // @if CK_DEBUG_TYPING // `isFocused: ${ this.isFocused }, hasDomRoot: ${ !!domRoot }`
9014
+ // @if CK_DEBUG_TYPING // ) );
9015
+ // @if CK_DEBUG_TYPING // }
8985
9016
  return;
8986
9017
  }
9018
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9019
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
9020
+ // @if CK_DEBUG_TYPING // 'Update DOM selection'
9021
+ // @if CK_DEBUG_TYPING // ) );
9022
+ // @if CK_DEBUG_TYPING // }
8987
9023
  // Render fake selection - create the fake selection container (if needed) and move DOM selection to it.
8988
9024
  if (this.selection.isFake) {
8989
9025
  this._updateFakeSelection(domRoot);
@@ -9013,6 +9049,11 @@ const validNodesToInsert = [
9013
9049
  domRoot.appendChild(container);
9014
9050
  }
9015
9051
  container.textContent = this.selection.fakeSelectionLabel || '\u00A0';
9052
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9053
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
9054
+ // @if CK_DEBUG_TYPING // 'Set DOM fake selection'
9055
+ // @if CK_DEBUG_TYPING // ) );
9056
+ // @if CK_DEBUG_TYPING // }
9016
9057
  const domSelection = domDocument.getSelection();
9017
9058
  const domRange = domDocument.createRange();
9018
9059
  domSelection.removeAllRanges();
@@ -9027,6 +9068,12 @@ const validNodesToInsert = [
9027
9068
  const domSelection = domRoot.ownerDocument.defaultView.getSelection();
9028
9069
  // Let's check whether DOM selection needs updating at all.
9029
9070
  if (!this._domSelectionNeedsUpdate(domSelection)) {
9071
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9072
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
9073
+ // @if CK_DEBUG_TYPING // '%cDOM selection is already correct',
9074
+ // @if CK_DEBUG_TYPING // 'font-style: italic;'
9075
+ // @if CK_DEBUG_TYPING // ) );
9076
+ // @if CK_DEBUG_TYPING // }
9030
9077
  return;
9031
9078
  }
9032
9079
  // Multi-range selection is not available in most browsers, and, at least in Chrome, trying to
@@ -9037,9 +9084,11 @@ const validNodesToInsert = [
9037
9084
  const anchor = this.domConverter.viewPositionToDom(this.selection.anchor);
9038
9085
  const focus = this.domConverter.viewPositionToDom(this.selection.focus);
9039
9086
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9040
- // @if CK_DEBUG_TYPING // console.info( '%c[Renderer]%c Update DOM selection:',
9041
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', '', anchor, focus
9042
- // @if CK_DEBUG_TYPING // );
9087
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
9088
+ // @if CK_DEBUG_TYPING // 'Update DOM selection:',
9089
+ // @if CK_DEBUG_TYPING // anchor,
9090
+ // @if CK_DEBUG_TYPING // focus
9091
+ // @if CK_DEBUG_TYPING // ) );
9043
9092
  // @if CK_DEBUG_TYPING // }
9044
9093
  domSelection.setBaseAndExtent(anchor.parent, anchor.offset, focus.parent, focus.offset);
9045
9094
  // Firefox–specific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).
@@ -9111,12 +9160,26 @@ const validNodesToInsert = [
9111
9160
  /**
9112
9161
  * Checks if focus needs to be updated and possibly updates it.
9113
9162
  */ _updateFocus() {
9163
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9164
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'Renderer',
9165
+ // @if CK_DEBUG_TYPING // `update focus: ${ this.isFocused ? 'focused' : 'not focused' }`
9166
+ // @if CK_DEBUG_TYPING // ) );
9167
+ // @if CK_DEBUG_TYPING // }
9114
9168
  if (this.isFocused) {
9115
9169
  const editable = this.selection.editableElement;
9170
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9171
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
9172
+ // @if CK_DEBUG_TYPING // 'focus editable:',
9173
+ // @if CK_DEBUG_TYPING // { editable }
9174
+ // @if CK_DEBUG_TYPING // ) );
9175
+ // @if CK_DEBUG_TYPING // }
9116
9176
  if (editable) {
9117
9177
  this.domConverter.focus(editable);
9118
9178
  }
9119
9179
  }
9180
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
9181
+ // @if CK_DEBUG_TYPING // console.groupEnd();
9182
+ // @if CK_DEBUG_TYPING // }
9120
9183
  }
9121
9184
  }
9122
9185
  /**
@@ -9298,7 +9361,7 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
9298
9361
  * `<span data-ck-unsafe-element="[element name]"></span>` while rendering in the editing mode.
9299
9362
  */ unsafeElements;
9300
9363
  /**
9301
- * The DOM Document used to create DOM nodes.
9364
+ * The DOM Document used by `DomConverter` to create DOM nodes.
9302
9365
  */ _domDocument;
9303
9366
  /**
9304
9367
  * The DOM-to-view mapping.
@@ -9403,6 +9466,11 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
9403
9466
  ];
9404
9467
  this._domDocument = this.renderingMode === 'editing' ? global.document : global.document.implementation.createHTMLDocument('');
9405
9468
  }
9469
+ /**
9470
+ * The DOM Document used by `DomConverter` to create DOM nodes.
9471
+ */ get domDocument() {
9472
+ return this._domDocument;
9473
+ }
9406
9474
  /**
9407
9475
  * Binds a given DOM element that represents fake selection to a **position** of a
9408
9476
  * {@link module:engine/view/documentselection~DocumentSelection document selection}.
@@ -10075,33 +10143,46 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
10075
10143
  * Focuses DOM editable that is corresponding to provided {@link module:engine/view/editableelement~EditableElement}.
10076
10144
  */ focus(viewEditable) {
10077
10145
  const domEditable = this.mapViewToDom(viewEditable);
10078
- if (domEditable && domEditable.ownerDocument.activeElement !== domEditable) {
10079
- // Save the scrollX and scrollY positions before the focus.
10080
- const { scrollX, scrollY } = global.window;
10081
- const scrollPositions = [];
10082
- // Save all scrollLeft and scrollTop values starting from domEditable up to
10083
- // document#documentElement.
10084
- forEachDomElementAncestor(domEditable, (node)=>{
10085
- const { scrollLeft, scrollTop } = node;
10086
- scrollPositions.push([
10087
- scrollLeft,
10088
- scrollTop
10089
- ]);
10090
- });
10091
- domEditable.focus();
10092
- // Restore scrollLeft and scrollTop values starting from domEditable up to
10093
- // document#documentElement.
10094
- // https://github.com/ckeditor/ckeditor5-engine/issues/951
10095
- // https://github.com/ckeditor/ckeditor5-engine/issues/957
10096
- forEachDomElementAncestor(domEditable, (node)=>{
10097
- const [scrollLeft, scrollTop] = scrollPositions.shift();
10098
- node.scrollLeft = scrollLeft;
10099
- node.scrollTop = scrollTop;
10100
- });
10101
- // Restore the scrollX and scrollY positions after the focus.
10102
- // https://github.com/ckeditor/ckeditor5-engine/issues/951
10103
- global.window.scrollTo(scrollX, scrollY);
10146
+ if (!domEditable || domEditable.ownerDocument.activeElement === domEditable) {
10147
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
10148
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'DomConverter',
10149
+ // @if CK_DEBUG_TYPING // '%cDOM editable is already active or does not exist',
10150
+ // @if CK_DEBUG_TYPING // 'font-style: italic'
10151
+ // @if CK_DEBUG_TYPING // ) );
10152
+ // @if CK_DEBUG_TYPING // }
10153
+ return;
10104
10154
  }
10155
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
10156
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'DomConverter',
10157
+ // @if CK_DEBUG_TYPING // 'Focus DOM editable:',
10158
+ // @if CK_DEBUG_TYPING // { domEditable }
10159
+ // @if CK_DEBUG_TYPING // ) );
10160
+ // @if CK_DEBUG_TYPING // }
10161
+ // Save the scrollX and scrollY positions before the focus.
10162
+ const { scrollX, scrollY } = global.window;
10163
+ const scrollPositions = [];
10164
+ // Save all scrollLeft and scrollTop values starting from domEditable up to
10165
+ // document#documentElement.
10166
+ forEachDomElementAncestor(domEditable, (node)=>{
10167
+ const { scrollLeft, scrollTop } = node;
10168
+ scrollPositions.push([
10169
+ scrollLeft,
10170
+ scrollTop
10171
+ ]);
10172
+ });
10173
+ domEditable.focus();
10174
+ // Restore scrollLeft and scrollTop values starting from domEditable up to
10175
+ // document#documentElement.
10176
+ // https://github.com/ckeditor/ckeditor5-engine/issues/951
10177
+ // https://github.com/ckeditor/ckeditor5-engine/issues/957
10178
+ forEachDomElementAncestor(domEditable, (node)=>{
10179
+ const [scrollLeft, scrollTop] = scrollPositions.shift();
10180
+ node.scrollLeft = scrollLeft;
10181
+ node.scrollTop = scrollTop;
10182
+ });
10183
+ // Restore the scrollX and scrollY positions after the focus.
10184
+ // https://github.com/ckeditor/ckeditor5-engine/issues/951
10185
+ global.window.scrollTo(scrollX, scrollY);
10105
10186
  }
10106
10187
  /**
10107
10188
  * Remove DOM selection from blurred editable, so it won't interfere with clicking on dropdowns (especially on iOS).
@@ -11042,7 +11123,7 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
11042
11123
  * {@link module:engine/view/observer/selectionobserver~SelectionObserver SelectionObserver}.
11043
11124
  */ class FakeSelectionObserver extends Observer {
11044
11125
  /**
11045
- * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.
11126
+ * Fires debounced event `selectionChangeDone`. It uses `es-toolkit#debounce` method to delay function call.
11046
11127
  */ _fireSelectionChangeDoneDebounced;
11047
11128
  /**
11048
11129
  * Creates new FakeSelectionObserver instance.
@@ -11119,7 +11200,7 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
11119
11200
  }
11120
11201
  }
11121
11202
 
11122
- // @if CK_DEBUG_TYPING // const { _debouncedLine } = require( '../../dev-utils/utils.js' );
11203
+ // @if CK_DEBUG_TYPING // const { _debouncedLine, _buildLogMessage } = require( '../../dev-utils/utils.js' );
11123
11204
  /**
11124
11205
  * Mutation observer's role is to watch for any DOM changes inside the editor that weren't
11125
11206
  * done by the editor's {@link module:engine/view/renderer~Renderer} itself and reverting these changes.
@@ -11274,9 +11355,10 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
11274
11355
  if (mutations.length) {
11275
11356
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11276
11357
  // @if CK_DEBUG_TYPING // _debouncedLine();
11277
- // @if CK_DEBUG_TYPING // console.group( '%c[MutationObserver]%c Mutations detected',
11278
- // @if CK_DEBUG_TYPING // 'font-weight: bold; color: green', 'font-weight: bold'
11279
- // @if CK_DEBUG_TYPING // );
11358
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'MutationObserver',
11359
+ // @if CK_DEBUG_TYPING // '%cMutations detected',
11360
+ // @if CK_DEBUG_TYPING // 'font-weight: bold'
11361
+ // @if CK_DEBUG_TYPING // ) );
11280
11362
  // @if CK_DEBUG_TYPING // }
11281
11363
  this.document.fire('mutations', {
11282
11364
  mutations
@@ -11304,7 +11386,7 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
11304
11386
  }
11305
11387
  }
11306
11388
  function sameNodes(child1, child2) {
11307
- // First level of comparison (array of children vs array of children) – use the Lodash's default behavior.
11389
+ // First level of comparison (array of children vs array of children) – use the es-toolkit's default behavior.
11308
11390
  if (Array.isArray(child1)) {
11309
11391
  return;
11310
11392
  }
@@ -11318,6 +11400,7 @@ function sameNodes(child1, child2) {
11318
11400
  return false;
11319
11401
  }
11320
11402
 
11403
+ // @if CK_DEBUG_TYPING // const { _debouncedLine, _buildLogMessage } = require( '../../dev-utils/utils.js' );
11321
11404
  /**
11322
11405
  * {@link module:engine/view/document~Document#event:focus Focus}
11323
11406
  * and {@link module:engine/view/document~Document#event:blur blur} events observer.
@@ -11364,14 +11447,42 @@ function sameNodes(child1, child2) {
11364
11447
  * Finishes setting the document focus state.
11365
11448
  */ flush() {
11366
11449
  if (this._isFocusChanging) {
11450
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11451
+ // @if CK_DEBUG_TYPING // _debouncedLine();
11452
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'FocusObserver',
11453
+ // @if CK_DEBUG_TYPING // 'flush focus'
11454
+ // @if CK_DEBUG_TYPING // ) );
11455
+ // @if CK_DEBUG_TYPING // }
11367
11456
  this._isFocusChanging = false;
11368
11457
  this.document.isFocused = true;
11458
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11459
+ // @if CK_DEBUG_TYPING // console.groupEnd();
11460
+ // @if CK_DEBUG_TYPING // }
11369
11461
  }
11370
11462
  }
11371
11463
  /**
11372
11464
  * @inheritDoc
11373
11465
  */ onDomEvent(domEvent) {
11466
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11467
+ // @if CK_DEBUG_TYPING // _debouncedLine();
11468
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'FocusObserver',
11469
+ // @if CK_DEBUG_TYPING // `${ domEvent.type } event`
11470
+ // @if CK_DEBUG_TYPING // ) );
11471
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'FocusObserver',
11472
+ // @if CK_DEBUG_TYPING // 'DOM target:',
11473
+ // @if CK_DEBUG_TYPING // { target: domEvent.target, relatedTarget: domEvent.relatedTarget }
11474
+ // @if CK_DEBUG_TYPING // ) );
11475
+ // @if CK_DEBUG_TYPING // const domSelection = window.getSelection();
11476
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'FocusObserver',
11477
+ // @if CK_DEBUG_TYPING // 'DOM Selection:',
11478
+ // @if CK_DEBUG_TYPING // { node: domSelection!.anchorNode, offset: domSelection!.anchorOffset },
11479
+ // @if CK_DEBUG_TYPING // { node: domSelection!.focusNode, offset: domSelection!.focusOffset }
11480
+ // @if CK_DEBUG_TYPING // ) );
11481
+ // @if CK_DEBUG_TYPING // }
11374
11482
  this.fire(domEvent.type, domEvent);
11483
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11484
+ // @if CK_DEBUG_TYPING // console.groupEnd();
11485
+ // @if CK_DEBUG_TYPING // }
11375
11486
  }
11376
11487
  /**
11377
11488
  * @inheritDoc
@@ -11394,20 +11505,42 @@ function sameNodes(child1, child2) {
11394
11505
  // in a situation where `selectionchange` already caused selection change.
11395
11506
  this._renderTimeoutId = setTimeout(()=>{
11396
11507
  this._renderTimeoutId = null;
11508
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11509
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'FocusObserver',
11510
+ // @if CK_DEBUG_TYPING // 'flush on timeout'
11511
+ // @if CK_DEBUG_TYPING // ) );
11512
+ // @if CK_DEBUG_TYPING // }
11397
11513
  this.flush();
11398
11514
  this.view.change(()=>{});
11515
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11516
+ // @if CK_DEBUG_TYPING // console.groupEnd();
11517
+ // @if CK_DEBUG_TYPING // }
11399
11518
  }, 50);
11400
11519
  }
11401
11520
  /**
11402
11521
  * The `blur` event handler.
11403
11522
  */ _handleBlur(data) {
11404
11523
  const selectedEditable = this.document.selection.editableElement;
11524
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11525
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'FocusObserver',
11526
+ // @if CK_DEBUG_TYPING // 'selectedEditable:',
11527
+ // @if CK_DEBUG_TYPING // { selectedEditable }
11528
+ // @if CK_DEBUG_TYPING // ) );
11529
+ // @if CK_DEBUG_TYPING // }
11405
11530
  if (selectedEditable === null || selectedEditable === data.target) {
11531
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11532
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'FocusObserver',
11533
+ // @if CK_DEBUG_TYPING // 'document no longer focused'
11534
+ // @if CK_DEBUG_TYPING // ) );
11535
+ // @if CK_DEBUG_TYPING // }
11406
11536
  this.document.isFocused = false;
11407
11537
  this._isFocusChanging = false;
11408
11538
  // Re-render the document to update view elements
11409
11539
  // (changing document.isFocused already marked view as changed since last rendering).
11410
11540
  this.view.change(()=>{});
11541
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11542
+ // @if CK_DEBUG_TYPING // console.groupEnd();
11543
+ // @if CK_DEBUG_TYPING // }
11411
11544
  }
11412
11545
  }
11413
11546
  /**
@@ -11449,9 +11582,9 @@ function sameNodes(child1, child2) {
11449
11582
  /**
11450
11583
  * A set of documents which have added `selectionchange` listener to avoid adding a listener twice to the same
11451
11584
  * document.
11452
- */ _documents;
11585
+ */ _documents = new WeakSet();
11453
11586
  /**
11454
- * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.
11587
+ * Fires debounced event `selectionChangeDone`. It uses `es-toolkit#debounce` method to delay function call.
11455
11588
  */ _fireSelectionChangeDoneDebounced;
11456
11589
  /**
11457
11590
  * When called, starts clearing the {@link #_loopbackCounter} counter in time intervals. When the number of selection
@@ -11465,20 +11598,36 @@ function sameNodes(child1, child2) {
11465
11598
  */ _documentIsSelectingInactivityTimeoutDebounced;
11466
11599
  /**
11467
11600
  * Private property to check if the code does not enter infinite loop.
11468
- */ _loopbackCounter;
11601
+ */ _loopbackCounter = 0;
11602
+ /**
11603
+ * A set of DOM documents that have a pending selection change.
11604
+ * Pending selection change is recorded while selection change event is detected on non focused editable.
11605
+ */ _pendingSelectionChange = new Set();
11469
11606
  constructor(view){
11470
11607
  super(view);
11471
11608
  this.mutationObserver = view.getObserver(MutationObserver);
11472
11609
  this.focusObserver = view.getObserver(FocusObserver);
11473
11610
  this.selection = this.document.selection;
11474
11611
  this.domConverter = view.domConverter;
11475
- this._documents = new WeakSet();
11476
11612
  this._fireSelectionChangeDoneDebounced = debounce((data)=>{
11477
11613
  this.document.fire('selectionChangeDone', data);
11478
11614
  }, 200);
11479
11615
  this._clearInfiniteLoopInterval = setInterval(()=>this._clearInfiniteLoop(), 1000);
11480
11616
  this._documentIsSelectingInactivityTimeoutDebounced = debounce(()=>this.document.isSelecting = false, 5000);
11481
- this._loopbackCounter = 0;
11617
+ this.view.document.on('change:isFocused', (evt, name, isFocused)=>{
11618
+ if (isFocused && this._pendingSelectionChange.size) {
11619
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11620
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'SelectionObserver',
11621
+ // @if CK_DEBUG_TYPING // 'Flush pending selection change'
11622
+ // @if CK_DEBUG_TYPING // ) );
11623
+ // @if CK_DEBUG_TYPING // }
11624
+ // Iterate over a copy of set because it is modified in selection change handler.
11625
+ for (const domDocument of Array.from(this._pendingSelectionChange)){
11626
+ this._handleSelectionChange(domDocument);
11627
+ }
11628
+ this._pendingSelectionChange.clear();
11629
+ }
11630
+ });
11482
11631
  }
11483
11632
  /**
11484
11633
  * @inheritDoc
@@ -11528,20 +11677,22 @@ function sameNodes(child1, child2) {
11528
11677
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11529
11678
  // @if CK_DEBUG_TYPING // _debouncedLine();
11530
11679
  // @if CK_DEBUG_TYPING // const domSelection = domDocument.defaultView!.getSelection();
11531
- // @if CK_DEBUG_TYPING // console.group( '%c[SelectionObserver]%c selectionchange', 'color: green', ''
11532
- // @if CK_DEBUG_TYPING // );
11533
- // @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c DOM Selection:', 'font-weight: bold; color: green', '',
11680
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'SelectionObserver',
11681
+ // @if CK_DEBUG_TYPING // 'selectionchange'
11682
+ // @if CK_DEBUG_TYPING // ) );
11683
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'SelectionObserver',
11684
+ // @if CK_DEBUG_TYPING // 'DOM Selection:',
11534
11685
  // @if CK_DEBUG_TYPING // { node: domSelection!.anchorNode, offset: domSelection!.anchorOffset },
11535
11686
  // @if CK_DEBUG_TYPING // { node: domSelection!.focusNode, offset: domSelection!.focusOffset }
11536
- // @if CK_DEBUG_TYPING // );
11687
+ // @if CK_DEBUG_TYPING // ) );
11537
11688
  // @if CK_DEBUG_TYPING // }
11538
11689
  // The Renderer is disabled while composing on non-android browsers, so we can't update the view selection
11539
11690
  // because the DOM and view tree drifted apart. Position mapping could fail because of it.
11540
11691
  if (this.document.isComposing && !env.isAndroid) {
11541
11692
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11542
- // @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c Selection change ignored (isComposing)',
11543
- // @if CK_DEBUG_TYPING // 'font-weight: bold; color: green', ''
11544
- // @if CK_DEBUG_TYPING // );
11693
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'SelectionObserver',
11694
+ // @if CK_DEBUG_TYPING // 'Selection change ignored (isComposing)'
11695
+ // @if CK_DEBUG_TYPING // ) );
11545
11696
  // @if CK_DEBUG_TYPING // console.groupEnd();
11546
11697
  // @if CK_DEBUG_TYPING // }
11547
11698
  return;
@@ -11560,12 +11711,14 @@ function sameNodes(child1, child2) {
11560
11711
  this.listenTo(this.view.document, 'compositionstart', ()=>{
11561
11712
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11562
11713
  // @if CK_DEBUG_TYPING // const domSelection = domDocument.defaultView!.getSelection();
11563
- // @if CK_DEBUG_TYPING // console.group( '%c[SelectionObserver]%c update selection on compositionstart', 'color: green', ''
11564
- // @if CK_DEBUG_TYPING // );
11565
- // @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c DOM Selection:', 'font-weight: bold; color: green', '',
11714
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'SelectionObserver',
11715
+ // @if CK_DEBUG_TYPING // 'update selection on compositionstart'
11716
+ // @if CK_DEBUG_TYPING // ) );
11717
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'SelectionObserver',
11718
+ // @if CK_DEBUG_TYPING // 'DOM Selection:',
11566
11719
  // @if CK_DEBUG_TYPING // { node: domSelection!.anchorNode, offset: domSelection!.anchorOffset },
11567
11720
  // @if CK_DEBUG_TYPING // { node: domSelection!.focusNode, offset: domSelection!.focusOffset }
11568
- // @if CK_DEBUG_TYPING // );
11721
+ // @if CK_DEBUG_TYPING // ) );
11569
11722
  // @if CK_DEBUG_TYPING // }
11570
11723
  this._handleSelectionChange(domDocument);
11571
11724
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
@@ -11623,6 +11776,17 @@ function sameNodes(child1, child2) {
11623
11776
  this.view.hasDomSelection = true;
11624
11777
  // Mark the latest focus change as complete (we got new selection after the focus so the selection is in the focused element).
11625
11778
  this.focusObserver.flush();
11779
+ // Ignore selection change as the editable is not focused.
11780
+ if (!this.view.document.isFocused) {
11781
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11782
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'SelectionObserver',
11783
+ // @if CK_DEBUG_TYPING // 'Ignore selection change while editable is not focused'
11784
+ // @if CK_DEBUG_TYPING // ) );
11785
+ // @if CK_DEBUG_TYPING // }
11786
+ this._pendingSelectionChange.add(domDocument);
11787
+ return;
11788
+ }
11789
+ this._pendingSelectionChange.delete(domDocument);
11626
11790
  if (this.selection.isEqual(newViewSelection) && this.domConverter.isDomSelectionCorrect(domSelection)) {
11627
11791
  return;
11628
11792
  }
@@ -11648,10 +11812,10 @@ function sameNodes(child1, child2) {
11648
11812
  domSelection
11649
11813
  };
11650
11814
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11651
- // @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c Fire selection change:',
11652
- // @if CK_DEBUG_TYPING // 'font-weight: bold; color: green', '',
11815
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'SelectionObserver',
11816
+ // @if CK_DEBUG_TYPING // 'Fire selection change:',
11653
11817
  // @if CK_DEBUG_TYPING // newViewSelection.getFirstRange()
11654
- // @if CK_DEBUG_TYPING // );
11818
+ // @if CK_DEBUG_TYPING // ) );
11655
11819
  // @if CK_DEBUG_TYPING // }
11656
11820
  // Prepare data for new selection and fire appropriate events.
11657
11821
  this.document.fire('selectionChange', data);
@@ -11669,7 +11833,7 @@ function sameNodes(child1, child2) {
11669
11833
  }
11670
11834
  }
11671
11835
 
11672
- // @if CK_DEBUG_TYPING // const { _debouncedLine } = require( '../../dev-utils/utils.js' );
11836
+ // @if CK_DEBUG_TYPING // const { _debouncedLine, _buildLogMessage } = require( '../../dev-utils/utils.js' );
11673
11837
  /**
11674
11838
  * {@link module:engine/view/document~Document#event:compositionstart Compositionstart},
11675
11839
  * {@link module:engine/view/document~Document#event:compositionupdate compositionupdate} and
@@ -11691,10 +11855,10 @@ function sameNodes(child1, child2) {
11691
11855
  const document = this.document;
11692
11856
  document.on('compositionstart', ()=>{
11693
11857
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11694
- // @if CK_DEBUG_TYPING // console.log( '%c[CompositionObserver] ' +
11695
- // @if CK_DEBUG_TYPING // '┌───────────────────────────── isComposing = true ─────────────────────────────┐',
11858
+ // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'CompositionObserver',
11859
+ // @if CK_DEBUG_TYPING // '%c┌───────────────────────────── isComposing = true ─────────────────────────────┐',
11696
11860
  // @if CK_DEBUG_TYPING // 'font-weight: bold; color: green'
11697
- // @if CK_DEBUG_TYPING // );
11861
+ // @if CK_DEBUG_TYPING // ) );
11698
11862
  // @if CK_DEBUG_TYPING // }
11699
11863
  document.isComposing = true;
11700
11864
  }, {
@@ -11702,10 +11866,10 @@ function sameNodes(child1, child2) {
11702
11866
  });
11703
11867
  document.on('compositionend', ()=>{
11704
11868
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11705
- // @if CK_DEBUG_TYPING // console.log( '%c[CompositionObserver] ' +
11706
- // @if CK_DEBUG_TYPING // '└───────────────────────────── isComposing = false ─────────────────────────────┘',
11869
+ // @if CK_DEBUG_TYPING // console.log( ..._buildLogMessage( this, 'CompositionObserver',
11870
+ // @if CK_DEBUG_TYPING // '%c└───────────────────────────── isComposing = false ─────────────────────────────┘',
11707
11871
  // @if CK_DEBUG_TYPING // 'font-weight: bold; color: green'
11708
- // @if CK_DEBUG_TYPING // );
11872
+ // @if CK_DEBUG_TYPING // ) );
11709
11873
  // @if CK_DEBUG_TYPING // }
11710
11874
  document.isComposing = false;
11711
11875
  }, {
@@ -11717,7 +11881,9 @@ function sameNodes(child1, child2) {
11717
11881
  */ onDomEvent(domEvent) {
11718
11882
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11719
11883
  // @if CK_DEBUG_TYPING // _debouncedLine();
11720
- // @if CK_DEBUG_TYPING // console.group( `%c[CompositionObserver]%c ${ domEvent.type }`, 'color: green', '' );
11884
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'CompositionObserver',
11885
+ // @if CK_DEBUG_TYPING // `${ domEvent.type }`
11886
+ // @if CK_DEBUG_TYPING // ) );
11721
11887
  // @if CK_DEBUG_TYPING // }
11722
11888
  this.fire(domEvent.type, domEvent, {
11723
11889
  data: domEvent.data
@@ -11822,7 +11988,7 @@ function getFiles(nativeDataTransfer) {
11822
11988
  return items.filter((item)=>item.kind === 'file').map((item)=>item.getAsFile());
11823
11989
  }
11824
11990
 
11825
- // @if CK_DEBUG_TYPING // const { _debouncedLine } = require( '../../dev-utils/utils.js' );
11991
+ // @if CK_DEBUG_TYPING // const { _debouncedLine, _buildLogMessage } = require( '../../dev-utils/utils.js' );
11826
11992
  /**
11827
11993
  * Observer for events connected with data input.
11828
11994
  *
@@ -11837,9 +12003,9 @@ function getFiles(nativeDataTransfer) {
11837
12003
  */ onDomEvent(domEvent) {
11838
12004
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11839
12005
  // @if CK_DEBUG_TYPING // _debouncedLine();
11840
- // @if CK_DEBUG_TYPING // console.group( `%c[InputObserver]%c ${ domEvent.type }: ${ domEvent.inputType }`,
11841
- // @if CK_DEBUG_TYPING // 'color: green', 'color: default'
11842
- // @if CK_DEBUG_TYPING // );
12006
+ // @if CK_DEBUG_TYPING // console.group( ..._buildLogMessage( this, 'InputObserver',
12007
+ // @if CK_DEBUG_TYPING // `${ domEvent.type }: ${ domEvent.inputType }`
12008
+ // @if CK_DEBUG_TYPING // ) );
11843
12009
  // @if CK_DEBUG_TYPING // }
11844
12010
  const domTargetRanges = domEvent.getTargetRanges();
11845
12011
  const view = this.view;
@@ -11853,16 +12019,20 @@ function getFiles(nativeDataTransfer) {
11853
12019
  if (domEvent.data !== null) {
11854
12020
  data = domEvent.data;
11855
12021
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11856
- // @if CK_DEBUG_TYPING // console.info( `%c[InputObserver]%c event data: %c${ JSON.stringify( data ) }`,
11857
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', 'color: blue;'
11858
- // @if CK_DEBUG_TYPING // );
12022
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'InputObserver',
12023
+ // @if CK_DEBUG_TYPING // `%cevent data: %c${ JSON.stringify( data ) }`,
12024
+ // @if CK_DEBUG_TYPING // 'font-weight: bold',
12025
+ // @if CK_DEBUG_TYPING // 'color: blue;'
12026
+ // @if CK_DEBUG_TYPING // ) );
11859
12027
  // @if CK_DEBUG_TYPING // }
11860
12028
  } else if (dataTransfer) {
11861
12029
  data = dataTransfer.getData('text/plain');
11862
12030
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11863
- // @if CK_DEBUG_TYPING // console.info( `%c[InputObserver]%c event data transfer: %c${ JSON.stringify( data ) }`,
11864
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', 'color: blue;'
11865
- // @if CK_DEBUG_TYPING // );
12031
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'InputObserver',
12032
+ // @if CK_DEBUG_TYPING // `%cevent data transfer: %c${ JSON.stringify( data ) }`,
12033
+ // @if CK_DEBUG_TYPING // 'font-weight: bold',
12034
+ // @if CK_DEBUG_TYPING // 'color: blue;'
12035
+ // @if CK_DEBUG_TYPING // ) );
11866
12036
  // @if CK_DEBUG_TYPING // }
11867
12037
  }
11868
12038
  // If the editor selection is fake (an object is selected), the DOM range does not make sense because it is anchored
@@ -11871,10 +12041,12 @@ function getFiles(nativeDataTransfer) {
11871
12041
  // Future-proof: in case of multi-range fake selections being possible.
11872
12042
  targetRanges = Array.from(viewDocument.selection.getRanges());
11873
12043
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11874
- // @if CK_DEBUG_TYPING // console.info( '%c[InputObserver]%c using fake selection:',
11875
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', targetRanges,
12044
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'InputObserver',
12045
+ // @if CK_DEBUG_TYPING // '%cusing fake selection:',
12046
+ // @if CK_DEBUG_TYPING // 'font-weight: bold',
12047
+ // @if CK_DEBUG_TYPING // targetRanges,
11876
12048
  // @if CK_DEBUG_TYPING // viewDocument.selection.isFake ? 'fake view selection' : 'fake DOM parent'
11877
- // @if CK_DEBUG_TYPING // );
12049
+ // @if CK_DEBUG_TYPING // ) );
11878
12050
  // @if CK_DEBUG_TYPING // }
11879
12051
  } else if (domTargetRanges.length) {
11880
12052
  targetRanges = domTargetRanges.map((domRange)=>{
@@ -11891,17 +12063,21 @@ function getFiles(nativeDataTransfer) {
11891
12063
  }
11892
12064
  }).filter((range)=>!!range);
11893
12065
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11894
- // @if CK_DEBUG_TYPING // console.info( '%c[InputObserver]%c using target ranges:',
11895
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', targetRanges
11896
- // @if CK_DEBUG_TYPING // );
12066
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'InputObserver',
12067
+ // @if CK_DEBUG_TYPING // '%cusing target ranges:',
12068
+ // @if CK_DEBUG_TYPING // 'font-weight: bold',
12069
+ // @if CK_DEBUG_TYPING // targetRanges
12070
+ // @if CK_DEBUG_TYPING // ) );
11897
12071
  // @if CK_DEBUG_TYPING // }
11898
12072
  } else if (env.isAndroid) {
11899
12073
  const domSelection = domEvent.target.ownerDocument.defaultView.getSelection();
11900
12074
  targetRanges = Array.from(view.domConverter.domSelectionToView(domSelection).getRanges());
11901
12075
  // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
11902
- // @if CK_DEBUG_TYPING // console.info( '%c[InputObserver]%c using selection ranges:',
11903
- // @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', targetRanges
11904
- // @if CK_DEBUG_TYPING // );
12076
+ // @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'InputObserver',
12077
+ // @if CK_DEBUG_TYPING // '%cusing selection ranges:',
12078
+ // @if CK_DEBUG_TYPING // 'font-weight: bold',
12079
+ // @if CK_DEBUG_TYPING // targetRanges
12080
+ // @if CK_DEBUG_TYPING // ) );
11905
12081
  // @if CK_DEBUG_TYPING // }
11906
12082
  }
11907
12083
  // Android sometimes fires insertCompositionText with a new-line character at the end of the data