@ckeditor/ckeditor5-engine 42.0.2 → 43.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -820
- package/dist/dev-utils/model.d.ts +2 -0
- package/dist/dev-utils/view.d.ts +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +466 -271
- package/dist/index.js.map +1 -1
- package/dist/model/schema.d.ts +149 -51
- package/dist/view/observer/focusobserver.d.ts +12 -0
- package/dist/view/observer/mutationobserver.d.ts +34 -5
- package/dist/view/observer/selectionobserver.d.ts +1 -2
- package/dist/view/renderer.d.ts +12 -0
- package/dist/view/view.d.ts +1 -4
- package/package.json +2 -2
- package/src/conversion/upcasthelpers.js +0 -7
- package/src/dev-utils/model.d.ts +2 -0
- package/src/dev-utils/model.js +4 -2
- package/src/dev-utils/utils.js +7 -0
- package/src/dev-utils/view.d.ts +1 -0
- package/src/dev-utils/view.js +3 -0
- package/src/index.d.ts +3 -1
- package/src/index.js +2 -0
- package/src/model/model.js +1 -5
- package/src/model/schema.d.ts +149 -51
- package/src/model/schema.js +200 -70
- package/src/model/utils/insertcontent.js +21 -65
- package/src/view/domconverter.js +13 -9
- package/src/view/observer/compositionobserver.js +2 -0
- package/src/view/observer/focusobserver.d.ts +12 -0
- package/src/view/observer/focusobserver.js +55 -25
- package/src/view/observer/inputobserver.js +7 -5
- package/src/view/observer/mutationobserver.d.ts +34 -5
- package/src/view/observer/mutationobserver.js +8 -11
- package/src/view/observer/selectionobserver.d.ts +1 -2
- package/src/view/observer/selectionobserver.js +27 -9
- package/src/view/renderer.d.ts +12 -0
- package/src/view/renderer.js +111 -63
- package/src/view/view.d.ts +1 -4
- package/src/view/view.js +9 -0
|
@@ -21,6 +21,10 @@ export default class FocusObserver extends DomEventObserver {
|
|
|
21
21
|
*/
|
|
22
22
|
constructor(view) {
|
|
23
23
|
super(view);
|
|
24
|
+
/**
|
|
25
|
+
* Identifier of the timeout currently used by focus listener to delay rendering execution.
|
|
26
|
+
*/
|
|
27
|
+
this._renderTimeoutId = null;
|
|
24
28
|
/**
|
|
25
29
|
* Set to `true` if the document is in the process of setting the focus.
|
|
26
30
|
*
|
|
@@ -33,31 +37,17 @@ export default class FocusObserver extends DomEventObserver {
|
|
|
33
37
|
this.domEventType = ['focus', 'blur'];
|
|
34
38
|
this.useCapture = true;
|
|
35
39
|
const document = this.document;
|
|
36
|
-
document.on('focus', () =>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// in a situation where `selectionchange` already caused selection change.
|
|
46
|
-
this._renderTimeoutId = setTimeout(() => {
|
|
47
|
-
this.flush();
|
|
48
|
-
view.change(() => { });
|
|
49
|
-
}, 50);
|
|
50
|
-
});
|
|
51
|
-
document.on('blur', (evt, data) => {
|
|
52
|
-
const selectedEditable = document.selection.editableElement;
|
|
53
|
-
if (selectedEditable === null || selectedEditable === data.target) {
|
|
54
|
-
document.isFocused = false;
|
|
55
|
-
this._isFocusChanging = false;
|
|
56
|
-
// Re-render the document to update view elements
|
|
57
|
-
// (changing document.isFocused already marked view as changed since last rendering).
|
|
58
|
-
view.change(() => { });
|
|
40
|
+
document.on('focus', () => this._handleFocus());
|
|
41
|
+
document.on('blur', (evt, data) => this._handleBlur(data));
|
|
42
|
+
// Focus the editor in cases where browser dispatches `beforeinput` event to a not-focused editable element.
|
|
43
|
+
// This is flushed by the beforeinput listener in the `InsertTextObserver`.
|
|
44
|
+
// Note that focus is set only if the document is not focused yet.
|
|
45
|
+
// See https://github.com/ckeditor/ckeditor5/issues/14702.
|
|
46
|
+
document.on('beforeinput', () => {
|
|
47
|
+
if (!document.isFocused) {
|
|
48
|
+
this._handleFocus();
|
|
59
49
|
}
|
|
60
|
-
});
|
|
50
|
+
}, { priority: 'highest' });
|
|
61
51
|
}
|
|
62
52
|
/**
|
|
63
53
|
* Finishes setting the document focus state.
|
|
@@ -78,9 +68,49 @@ export default class FocusObserver extends DomEventObserver {
|
|
|
78
68
|
* @inheritDoc
|
|
79
69
|
*/
|
|
80
70
|
destroy() {
|
|
71
|
+
this._clearTimeout();
|
|
72
|
+
super.destroy();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The `focus` event handler.
|
|
76
|
+
*/
|
|
77
|
+
_handleFocus() {
|
|
78
|
+
this._clearTimeout();
|
|
79
|
+
this._isFocusChanging = true;
|
|
80
|
+
// Unfortunately native `selectionchange` event is fired asynchronously.
|
|
81
|
+
// We need to wait until `SelectionObserver` handle the event and then render. Otherwise rendering will
|
|
82
|
+
// overwrite new DOM selection with selection from the view.
|
|
83
|
+
// See https://github.com/ckeditor/ckeditor5-engine/issues/795 for more details.
|
|
84
|
+
// Long timeout is needed to solve #676 and https://github.com/ckeditor/ckeditor5-engine/issues/1157 issues.
|
|
85
|
+
//
|
|
86
|
+
// Using `view.change()` instead of `view.forceRender()` to prevent double rendering
|
|
87
|
+
// in a situation where `selectionchange` already caused selection change.
|
|
88
|
+
this._renderTimeoutId = setTimeout(() => {
|
|
89
|
+
this._renderTimeoutId = null;
|
|
90
|
+
this.flush();
|
|
91
|
+
this.view.change(() => { });
|
|
92
|
+
}, 50);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The `blur` event handler.
|
|
96
|
+
*/
|
|
97
|
+
_handleBlur(data) {
|
|
98
|
+
const selectedEditable = this.document.selection.editableElement;
|
|
99
|
+
if (selectedEditable === null || selectedEditable === data.target) {
|
|
100
|
+
this.document.isFocused = false;
|
|
101
|
+
this._isFocusChanging = false;
|
|
102
|
+
// Re-render the document to update view elements
|
|
103
|
+
// (changing document.isFocused already marked view as changed since last rendering).
|
|
104
|
+
this.view.change(() => { });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Clears timeout.
|
|
109
|
+
*/
|
|
110
|
+
_clearTimeout() {
|
|
81
111
|
if (this._renderTimeoutId) {
|
|
82
112
|
clearTimeout(this._renderTimeoutId);
|
|
113
|
+
this._renderTimeoutId = null;
|
|
83
114
|
}
|
|
84
|
-
super.destroy();
|
|
85
115
|
}
|
|
86
116
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import DomEventObserver from './domeventobserver.js';
|
|
9
9
|
import DataTransfer from '../datatransfer.js';
|
|
10
10
|
import { env } from '@ckeditor/ckeditor5-utils';
|
|
11
|
+
// @if CK_DEBUG_TYPING // const { _debouncedLine } = require( '../../dev-utils/utils.js' );
|
|
11
12
|
/**
|
|
12
13
|
* Observer for events connected with data input.
|
|
13
14
|
*
|
|
@@ -27,6 +28,7 @@ export default class InputObserver extends DomEventObserver {
|
|
|
27
28
|
*/
|
|
28
29
|
onDomEvent(domEvent) {
|
|
29
30
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
31
|
+
// @if CK_DEBUG_TYPING // _debouncedLine();
|
|
30
32
|
// @if CK_DEBUG_TYPING // console.group( `%c[InputObserver]%c ${ domEvent.type }: ${ domEvent.inputType }`,
|
|
31
33
|
// @if CK_DEBUG_TYPING // 'color: green', 'color: default'
|
|
32
34
|
// @if CK_DEBUG_TYPING // );
|
|
@@ -44,7 +46,7 @@ export default class InputObserver extends DomEventObserver {
|
|
|
44
46
|
data = domEvent.data;
|
|
45
47
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
46
48
|
// @if CK_DEBUG_TYPING // console.info( `%c[InputObserver]%c event data: %c${ JSON.stringify( data ) }`,
|
|
47
|
-
// @if CK_DEBUG_TYPING // 'color: green;font-weight: bold', 'font-weight:bold', 'color: blue;'
|
|
49
|
+
// @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', 'color: blue;'
|
|
48
50
|
// @if CK_DEBUG_TYPING // );
|
|
49
51
|
// @if CK_DEBUG_TYPING // }
|
|
50
52
|
}
|
|
@@ -52,7 +54,7 @@ export default class InputObserver extends DomEventObserver {
|
|
|
52
54
|
data = dataTransfer.getData('text/plain');
|
|
53
55
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
54
56
|
// @if CK_DEBUG_TYPING // console.info( `%c[InputObserver]%c event data transfer: %c${ JSON.stringify( data ) }`,
|
|
55
|
-
// @if CK_DEBUG_TYPING // 'color: green;font-weight: bold', 'font-weight:bold', 'color: blue;'
|
|
57
|
+
// @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', 'color: blue;'
|
|
56
58
|
// @if CK_DEBUG_TYPING // );
|
|
57
59
|
// @if CK_DEBUG_TYPING // }
|
|
58
60
|
}
|
|
@@ -63,7 +65,7 @@ export default class InputObserver extends DomEventObserver {
|
|
|
63
65
|
targetRanges = Array.from(viewDocument.selection.getRanges());
|
|
64
66
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
65
67
|
// @if CK_DEBUG_TYPING // console.info( '%c[InputObserver]%c using fake selection:',
|
|
66
|
-
// @if CK_DEBUG_TYPING // 'color: green;font-weight: bold', 'font-weight:bold', targetRanges,
|
|
68
|
+
// @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', targetRanges,
|
|
67
69
|
// @if CK_DEBUG_TYPING // viewDocument.selection.isFake ? 'fake view selection' : 'fake DOM parent'
|
|
68
70
|
// @if CK_DEBUG_TYPING // );
|
|
69
71
|
// @if CK_DEBUG_TYPING // }
|
|
@@ -85,7 +87,7 @@ export default class InputObserver extends DomEventObserver {
|
|
|
85
87
|
}).filter((range) => !!range);
|
|
86
88
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
87
89
|
// @if CK_DEBUG_TYPING // console.info( '%c[InputObserver]%c using target ranges:',
|
|
88
|
-
// @if CK_DEBUG_TYPING // 'color: green;font-weight: bold', 'font-weight:bold', targetRanges
|
|
90
|
+
// @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', targetRanges
|
|
89
91
|
// @if CK_DEBUG_TYPING // );
|
|
90
92
|
// @if CK_DEBUG_TYPING // }
|
|
91
93
|
}
|
|
@@ -96,7 +98,7 @@ export default class InputObserver extends DomEventObserver {
|
|
|
96
98
|
targetRanges = Array.from(view.domConverter.domSelectionToView(domSelection).getRanges());
|
|
97
99
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
98
100
|
// @if CK_DEBUG_TYPING // console.info( '%c[InputObserver]%c using selection ranges:',
|
|
99
|
-
// @if CK_DEBUG_TYPING // 'color: green;font-weight: bold', 'font-weight:bold', targetRanges
|
|
101
|
+
// @if CK_DEBUG_TYPING // 'color: green; font-weight: bold', 'font-weight: bold', targetRanges
|
|
100
102
|
// @if CK_DEBUG_TYPING // );
|
|
101
103
|
// @if CK_DEBUG_TYPING // }
|
|
102
104
|
}
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import Observer from './observer.js';
|
|
9
9
|
import type DomConverter from '../domconverter.js';
|
|
10
|
-
import type Renderer from '../renderer.js';
|
|
11
10
|
import type View from '../view.js';
|
|
11
|
+
import type ViewNode from '../node.js';
|
|
12
|
+
import type { ChangeType } from '../document.js';
|
|
12
13
|
/**
|
|
13
14
|
* Mutation observer's role is to watch for any DOM changes inside the editor that weren't
|
|
14
15
|
* done by the editor's {@link module:engine/view/renderer~Renderer} itself and reverting these changes.
|
|
@@ -25,10 +26,6 @@ export default class MutationObserver extends Observer {
|
|
|
25
26
|
* Reference to the {@link module:engine/view/view~View#domConverter}.
|
|
26
27
|
*/
|
|
27
28
|
readonly domConverter: DomConverter;
|
|
28
|
-
/**
|
|
29
|
-
* Reference to the {@link module:engine/view/view~View#_renderer}.
|
|
30
|
-
*/
|
|
31
|
-
readonly renderer: Renderer;
|
|
32
29
|
/**
|
|
33
30
|
* Native mutation observer config.
|
|
34
31
|
*/
|
|
@@ -84,3 +81,35 @@ export default class MutationObserver extends Observer {
|
|
|
84
81
|
*/
|
|
85
82
|
private _isBogusBrMutation;
|
|
86
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Event fired on DOM mutations detected.
|
|
86
|
+
*
|
|
87
|
+
* This event is introduced by {@link module:engine/view/observer/mutationobserver~MutationObserver} and available
|
|
88
|
+
* by default in all editor instances (attached by {@link module:engine/view/view~View}).
|
|
89
|
+
*
|
|
90
|
+
* @eventName module:engine/view/document~Document#mutations
|
|
91
|
+
* @param data Event data containing detailed information about the event.
|
|
92
|
+
*/
|
|
93
|
+
export type ViewDocumentMutationsEvent = {
|
|
94
|
+
name: 'mutations';
|
|
95
|
+
args: [data: MutationsEventData];
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* The value of {@link ~ViewDocumentMutationsEvent}.
|
|
99
|
+
*/
|
|
100
|
+
export type MutationsEventData = {
|
|
101
|
+
mutations: Array<MutationData>;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* A single entry in {@link ~MutationsEventData} mutations array.
|
|
105
|
+
*/
|
|
106
|
+
export type MutationData = {
|
|
107
|
+
/**
|
|
108
|
+
* Type of mutation detected.
|
|
109
|
+
*/
|
|
110
|
+
type: ChangeType;
|
|
111
|
+
/**
|
|
112
|
+
* The view node related to the detected mutation.
|
|
113
|
+
*/
|
|
114
|
+
node: ViewNode;
|
|
115
|
+
};
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import Observer from './observer.js';
|
|
10
10
|
import { startsWithFiller } from '../filler.js';
|
|
11
11
|
import { isEqualWith } from 'lodash-es';
|
|
12
|
+
// @if CK_DEBUG_TYPING // const { _debouncedLine } = require( '../../dev-utils/utils.js' );
|
|
12
13
|
/**
|
|
13
14
|
* Mutation observer's role is to watch for any DOM changes inside the editor that weren't
|
|
14
15
|
* done by the editor's {@link module:engine/view/renderer~Renderer} itself and reverting these changes.
|
|
@@ -32,7 +33,6 @@ export default class MutationObserver extends Observer {
|
|
|
32
33
|
subtree: true
|
|
33
34
|
};
|
|
34
35
|
this.domConverter = view.domConverter;
|
|
35
|
-
this.renderer = view._renderer;
|
|
36
36
|
this._domElements = new Set();
|
|
37
37
|
this._mutationObserver = new window.MutationObserver(this._onMutations.bind(this));
|
|
38
38
|
}
|
|
@@ -139,10 +139,9 @@ export default class MutationObserver extends Observer {
|
|
|
139
139
|
}
|
|
140
140
|
// Now we build the list of mutations to mark elements. We did not do it earlier to avoid marking the
|
|
141
141
|
// same node multiple times in case of duplication.
|
|
142
|
-
|
|
142
|
+
const mutations = [];
|
|
143
143
|
for (const textNode of mutatedTextNodes) {
|
|
144
|
-
|
|
145
|
-
this.renderer.markToSync('text', textNode);
|
|
144
|
+
mutations.push({ type: 'text', node: textNode });
|
|
146
145
|
}
|
|
147
146
|
for (const viewElement of elementsWithMutatedChildren) {
|
|
148
147
|
const domElement = domConverter.mapViewToDom(viewElement);
|
|
@@ -151,20 +150,18 @@ export default class MutationObserver extends Observer {
|
|
|
151
150
|
// It may happen that as a result of many changes (sth was inserted and then removed),
|
|
152
151
|
// both elements haven't really changed. #1031
|
|
153
152
|
if (!isEqualWith(viewChildren, newViewChildren, sameNodes)) {
|
|
154
|
-
|
|
155
|
-
this.renderer.markToSync('children', viewElement);
|
|
153
|
+
mutations.push({ type: 'children', node: viewElement });
|
|
156
154
|
}
|
|
157
155
|
}
|
|
158
156
|
// In case only non-relevant mutations were recorded it skips the event and force render (#5600).
|
|
159
|
-
if (
|
|
157
|
+
if (mutations.length) {
|
|
160
158
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
159
|
+
// @if CK_DEBUG_TYPING // _debouncedLine();
|
|
161
160
|
// @if CK_DEBUG_TYPING // console.group( '%c[MutationObserver]%c Mutations detected',
|
|
162
|
-
// @if CK_DEBUG_TYPING // 'font-weight:bold;color:green', ''
|
|
161
|
+
// @if CK_DEBUG_TYPING // 'font-weight: bold; color: green', 'font-weight: bold'
|
|
163
162
|
// @if CK_DEBUG_TYPING // );
|
|
164
163
|
// @if CK_DEBUG_TYPING // }
|
|
165
|
-
|
|
166
|
-
// In order to "reset DOM" we render the view again.
|
|
167
|
-
this.view.forceRender();
|
|
164
|
+
this.document.fire('mutations', { mutations });
|
|
168
165
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
169
166
|
// @if CK_DEBUG_TYPING // console.groupEnd();
|
|
170
167
|
// @if CK_DEBUG_TYPING // }
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import Observer from './observer.js';
|
|
9
9
|
import MutationObserver from './mutationobserver.js';
|
|
10
|
+
import FocusObserver from './focusobserver.js';
|
|
10
11
|
import type View from '../view.js';
|
|
11
12
|
import type DocumentSelection from '../documentselection.js';
|
|
12
13
|
import type DomConverter from '../domconverter.js';
|
|
13
14
|
import type Selection from '../selection.js';
|
|
14
|
-
import FocusObserver from './focusobserver.js';
|
|
15
15
|
type DomSelection = globalThis.Selection;
|
|
16
16
|
/**
|
|
17
17
|
* Selection observer class observes selection changes in the document. If a selection changes on the document this
|
|
@@ -88,7 +88,6 @@ export default class SelectionObserver extends Observer {
|
|
|
88
88
|
* a selection changes and fires {@link module:engine/view/document~Document#event:selectionChange} event on every change
|
|
89
89
|
* and {@link module:engine/view/document~Document#event:selectionChangeDone} when a selection stop changing.
|
|
90
90
|
*
|
|
91
|
-
* @param domEvent DOM event.
|
|
92
91
|
* @param domDocument DOM document.
|
|
93
92
|
*/
|
|
94
93
|
private _handleSelectionChange;
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
/* global setInterval, clearInterval */
|
|
9
9
|
import Observer from './observer.js';
|
|
10
10
|
import MutationObserver from './mutationobserver.js';
|
|
11
|
+
import FocusObserver from './focusobserver.js';
|
|
11
12
|
import { env } from '@ckeditor/ckeditor5-utils';
|
|
12
13
|
import { debounce } from 'lodash-es';
|
|
13
|
-
import FocusObserver from './focusobserver.js';
|
|
14
14
|
/**
|
|
15
15
|
* Selection observer class observes selection changes in the document. If a selection changes on the document this
|
|
16
16
|
* observer checks if the DOM selection is different from the {@link module:engine/view/document~Document#selection view selection}.
|
|
@@ -52,7 +52,7 @@ export default class SelectionObserver extends Observer {
|
|
|
52
52
|
}
|
|
53
53
|
// Make sure that model selection is up-to-date at the end of selecting process.
|
|
54
54
|
// Sometimes `selectionchange` events could arrive after the `mouseup` event and that selection could be already outdated.
|
|
55
|
-
this._handleSelectionChange(
|
|
55
|
+
this._handleSelectionChange(domDocument);
|
|
56
56
|
this.document.isSelecting = false;
|
|
57
57
|
// The safety timeout can be canceled when the document leaves the "is selecting" state.
|
|
58
58
|
this._documentIsSelectingInactivityTimeoutDebounced.cancel();
|
|
@@ -72,10 +72,11 @@ export default class SelectionObserver extends Observer {
|
|
|
72
72
|
this.listenTo(domDocument, 'mouseup', endDocumentIsSelecting, { priority: 'highest', useCapture: true });
|
|
73
73
|
this.listenTo(domDocument, 'selectionchange', (evt, domEvent) => {
|
|
74
74
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
75
|
+
// @if CK_DEBUG_TYPING // _debouncedLine();
|
|
75
76
|
// @if CK_DEBUG_TYPING // const domSelection = domDocument.defaultView!.getSelection();
|
|
76
|
-
// @if CK_DEBUG_TYPING // console.group( '%c[SelectionObserver]%c selectionchange', 'color:green', ''
|
|
77
|
+
// @if CK_DEBUG_TYPING // console.group( '%c[SelectionObserver]%c selectionchange', 'color: green', ''
|
|
77
78
|
// @if CK_DEBUG_TYPING // );
|
|
78
|
-
// @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c DOM Selection:', 'font-weight:bold;color:green', '',
|
|
79
|
+
// @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c DOM Selection:', 'font-weight: bold; color: green', '',
|
|
79
80
|
// @if CK_DEBUG_TYPING // { node: domSelection!.anchorNode, offset: domSelection!.anchorOffset },
|
|
80
81
|
// @if CK_DEBUG_TYPING // { node: domSelection!.focusNode, offset: domSelection!.focusOffset }
|
|
81
82
|
// @if CK_DEBUG_TYPING // );
|
|
@@ -85,13 +86,13 @@ export default class SelectionObserver extends Observer {
|
|
|
85
86
|
if (this.document.isComposing && !env.isAndroid) {
|
|
86
87
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
87
88
|
// @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c Selection change ignored (isComposing)',
|
|
88
|
-
// @if CK_DEBUG_TYPING // 'font-weight:bold;color:green', ''
|
|
89
|
+
// @if CK_DEBUG_TYPING // 'font-weight: bold; color: green', ''
|
|
89
90
|
// @if CK_DEBUG_TYPING // );
|
|
90
91
|
// @if CK_DEBUG_TYPING // console.groupEnd();
|
|
91
92
|
// @if CK_DEBUG_TYPING // }
|
|
92
93
|
return;
|
|
93
94
|
}
|
|
94
|
-
this._handleSelectionChange(
|
|
95
|
+
this._handleSelectionChange(domDocument);
|
|
95
96
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
96
97
|
// @if CK_DEBUG_TYPING // console.groupEnd();
|
|
97
98
|
// @if CK_DEBUG_TYPING // }
|
|
@@ -99,6 +100,24 @@ export default class SelectionObserver extends Observer {
|
|
|
99
100
|
// using their mouse).
|
|
100
101
|
this._documentIsSelectingInactivityTimeoutDebounced();
|
|
101
102
|
});
|
|
103
|
+
// Update the model DocumentSelection just after the Renderer and the SelectionObserver are locked.
|
|
104
|
+
// We do this synchronously (without waiting for the `selectionchange` DOM event) as browser updates
|
|
105
|
+
// the DOM selection (but not visually) to span the text that is under composition and could be replaced.
|
|
106
|
+
this.listenTo(this.view.document, 'compositionstart', () => {
|
|
107
|
+
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
108
|
+
// @if CK_DEBUG_TYPING // const domSelection = domDocument.defaultView!.getSelection();
|
|
109
|
+
// @if CK_DEBUG_TYPING // console.group( '%c[SelectionObserver]%c update selection on compositionstart', 'color: green', ''
|
|
110
|
+
// @if CK_DEBUG_TYPING // );
|
|
111
|
+
// @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c DOM Selection:', 'font-weight: bold; color: green', '',
|
|
112
|
+
// @if CK_DEBUG_TYPING // { node: domSelection!.anchorNode, offset: domSelection!.anchorOffset },
|
|
113
|
+
// @if CK_DEBUG_TYPING // { node: domSelection!.focusNode, offset: domSelection!.focusOffset }
|
|
114
|
+
// @if CK_DEBUG_TYPING // );
|
|
115
|
+
// @if CK_DEBUG_TYPING // }
|
|
116
|
+
this._handleSelectionChange(domDocument);
|
|
117
|
+
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
118
|
+
// @if CK_DEBUG_TYPING // console.groupEnd();
|
|
119
|
+
// @if CK_DEBUG_TYPING // }
|
|
120
|
+
}, { priority: 'lowest' });
|
|
102
121
|
this._documents.add(domDocument);
|
|
103
122
|
}
|
|
104
123
|
/**
|
|
@@ -128,10 +147,9 @@ export default class SelectionObserver extends Observer {
|
|
|
128
147
|
* a selection changes and fires {@link module:engine/view/document~Document#event:selectionChange} event on every change
|
|
129
148
|
* and {@link module:engine/view/document~Document#event:selectionChangeDone} when a selection stop changing.
|
|
130
149
|
*
|
|
131
|
-
* @param domEvent DOM event.
|
|
132
150
|
* @param domDocument DOM document.
|
|
133
151
|
*/
|
|
134
|
-
_handleSelectionChange(
|
|
152
|
+
_handleSelectionChange(domDocument) {
|
|
135
153
|
if (!this.isEnabled) {
|
|
136
154
|
return;
|
|
137
155
|
}
|
|
@@ -180,7 +198,7 @@ export default class SelectionObserver extends Observer {
|
|
|
180
198
|
};
|
|
181
199
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
182
200
|
// @if CK_DEBUG_TYPING // console.info( '%c[SelectionObserver]%c Fire selection change:',
|
|
183
|
-
// @if CK_DEBUG_TYPING // 'font-weight:bold;color:green', '',
|
|
201
|
+
// @if CK_DEBUG_TYPING // 'font-weight: bold; color: green', '',
|
|
184
202
|
// @if CK_DEBUG_TYPING // newViewSelection.getFirstRange()
|
|
185
203
|
// @if CK_DEBUG_TYPING // );
|
|
186
204
|
// @if CK_DEBUG_TYPING // }
|
package/src/view/renderer.d.ts
CHANGED
|
@@ -213,6 +213,18 @@ export default class Renderer extends /* #__PURE__ */ Renderer_base {
|
|
|
213
213
|
* @returns Actions array modified with the `update` actions.
|
|
214
214
|
*/
|
|
215
215
|
private _findUpdateActions;
|
|
216
|
+
/**
|
|
217
|
+
* Checks if text needs to be updated and possibly updates it by removing and inserting only parts
|
|
218
|
+
* of the data from the existing text node to reduce impact on the IME composition.
|
|
219
|
+
*
|
|
220
|
+
* @param domText DOM text node to update.
|
|
221
|
+
* @param expectedText The expected data of a text node.
|
|
222
|
+
*/
|
|
223
|
+
private _updateTextNode;
|
|
224
|
+
/**
|
|
225
|
+
* Part of the `_updateTextNode` method extracted for easier testing.
|
|
226
|
+
*/
|
|
227
|
+
private _updateTextNodeInternal;
|
|
216
228
|
/**
|
|
217
229
|
* Marks text nodes to be synchronized.
|
|
218
230
|
*
|