@ckeditor/ckeditor5-engine 45.1.0 → 45.2.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.
- package/dist/index.js +72 -26
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/dataprocessor/htmldataprocessor.js +0 -1
- package/src/dataprocessor/xmldataprocessor.js +0 -1
- package/src/dev-utils/model.js +1 -1
- package/src/dev-utils/operationreplayer.js +0 -1
- package/src/dev-utils/utils.js +0 -1
- package/src/dev-utils/view.js +0 -1
- package/src/view/domconverter.js +2 -3
- package/src/view/observer/focusobserver.js +0 -1
- package/src/view/observer/inputobserver.js +39 -2
- package/src/view/observer/mutationobserver.js +0 -1
- package/src/view/observer/selectionobserver.js +3 -3
- package/src/view/renderer.d.ts +3 -3
- package/src/view/renderer.js +30 -20
package/dist/index.js
CHANGED
|
@@ -9012,15 +9012,25 @@ const validNodesToInsert = [
|
|
|
9012
9012
|
this._removeFakeSelection();
|
|
9013
9013
|
return;
|
|
9014
9014
|
}
|
|
9015
|
-
const
|
|
9016
|
-
// Do
|
|
9017
|
-
if (!this.isFocused || !
|
|
9015
|
+
const domEditable = this.domConverter.mapViewToDom(this.selection.editableElement);
|
|
9016
|
+
// Do not update DOM selection if there is no focus, or there is no DOM element corresponding to selection's editable element.
|
|
9017
|
+
if (!this.isFocused || !domEditable) {
|
|
9018
9018
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
9019
9019
|
// @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
|
|
9020
9020
|
// @if CK_DEBUG_TYPING // 'Skip updating DOM selection:',
|
|
9021
|
-
// @if CK_DEBUG_TYPING // `isFocused: ${ this.isFocused },
|
|
9021
|
+
// @if CK_DEBUG_TYPING // `isFocused: ${ this.isFocused }, hasDomEditable: ${ !!domEditable }`
|
|
9022
9022
|
// @if CK_DEBUG_TYPING // ) );
|
|
9023
9023
|
// @if CK_DEBUG_TYPING // }
|
|
9024
|
+
// But if there was a fake selection, and it is not fake anymore - remove it as it can map to no longer existing widget.
|
|
9025
|
+
// See https://github.com/ckeditor/ckeditor5/issues/18123.
|
|
9026
|
+
if (!this.selection.isFake && this._fakeSelectionContainer && this._fakeSelectionContainer.isConnected) {
|
|
9027
|
+
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
9028
|
+
// @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'Renderer',
|
|
9029
|
+
// @if CK_DEBUG_TYPING // 'Remove fake selection (not focused editable)'
|
|
9030
|
+
// @if CK_DEBUG_TYPING // ) );
|
|
9031
|
+
// @if CK_DEBUG_TYPING // }
|
|
9032
|
+
this._removeFakeSelection();
|
|
9033
|
+
}
|
|
9024
9034
|
return;
|
|
9025
9035
|
}
|
|
9026
9036
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
@@ -9030,31 +9040,31 @@ const validNodesToInsert = [
|
|
|
9030
9040
|
// @if CK_DEBUG_TYPING // }
|
|
9031
9041
|
// Render fake selection - create the fake selection container (if needed) and move DOM selection to it.
|
|
9032
9042
|
if (this.selection.isFake) {
|
|
9033
|
-
this._updateFakeSelection(
|
|
9043
|
+
this._updateFakeSelection(domEditable);
|
|
9034
9044
|
} else if (this._fakeSelectionContainer && this._fakeSelectionContainer.isConnected) {
|
|
9035
9045
|
this._removeFakeSelection();
|
|
9036
|
-
this._updateDomSelection(
|
|
9046
|
+
this._updateDomSelection(domEditable);
|
|
9037
9047
|
} else if (!(this.isComposing && env.isAndroid)) {
|
|
9038
|
-
this._updateDomSelection(
|
|
9048
|
+
this._updateDomSelection(domEditable);
|
|
9039
9049
|
}
|
|
9040
9050
|
}
|
|
9041
9051
|
/**
|
|
9042
9052
|
* Updates the fake selection.
|
|
9043
9053
|
*
|
|
9044
|
-
* @param
|
|
9045
|
-
*/ _updateFakeSelection(
|
|
9046
|
-
const domDocument =
|
|
9054
|
+
* @param domEditable A valid DOM editable where the fake selection container should be added.
|
|
9055
|
+
*/ _updateFakeSelection(domEditable) {
|
|
9056
|
+
const domDocument = domEditable.ownerDocument;
|
|
9047
9057
|
if (!this._fakeSelectionContainer) {
|
|
9048
9058
|
this._fakeSelectionContainer = createFakeSelectionContainer(domDocument);
|
|
9049
9059
|
}
|
|
9050
9060
|
const container = this._fakeSelectionContainer;
|
|
9051
9061
|
// Bind fake selection container with the current selection *position*.
|
|
9052
9062
|
this.domConverter.bindFakeSelection(container, this.selection);
|
|
9053
|
-
if (!this._fakeSelectionNeedsUpdate(
|
|
9063
|
+
if (!this._fakeSelectionNeedsUpdate(domEditable)) {
|
|
9054
9064
|
return;
|
|
9055
9065
|
}
|
|
9056
|
-
if (!container.parentElement || container.parentElement !=
|
|
9057
|
-
|
|
9066
|
+
if (!container.parentElement || container.parentElement != domEditable) {
|
|
9067
|
+
domEditable.appendChild(container);
|
|
9058
9068
|
}
|
|
9059
9069
|
container.textContent = this.selection.fakeSelectionLabel || '\u00A0';
|
|
9060
9070
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
@@ -9071,9 +9081,9 @@ const validNodesToInsert = [
|
|
|
9071
9081
|
/**
|
|
9072
9082
|
* Updates the DOM selection.
|
|
9073
9083
|
*
|
|
9074
|
-
* @param
|
|
9075
|
-
*/ _updateDomSelection(
|
|
9076
|
-
const domSelection =
|
|
9084
|
+
* @param domEditable A valid DOM editable where the DOM selection should be rendered.
|
|
9085
|
+
*/ _updateDomSelection(domEditable) {
|
|
9086
|
+
const domSelection = domEditable.ownerDocument.defaultView.getSelection();
|
|
9077
9087
|
// Let's check whether DOM selection needs updating at all.
|
|
9078
9088
|
if (!this._domSelectionNeedsUpdate(domSelection)) {
|
|
9079
9089
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
@@ -9128,13 +9138,13 @@ const validNodesToInsert = [
|
|
|
9128
9138
|
/**
|
|
9129
9139
|
* Checks whether the fake selection needs to be updated.
|
|
9130
9140
|
*
|
|
9131
|
-
* @param
|
|
9132
|
-
*/ _fakeSelectionNeedsUpdate(
|
|
9141
|
+
* @param domEditable A valid DOM editable where a new fake selection container should be added.
|
|
9142
|
+
*/ _fakeSelectionNeedsUpdate(domEditable) {
|
|
9133
9143
|
const container = this._fakeSelectionContainer;
|
|
9134
|
-
const domSelection =
|
|
9144
|
+
const domSelection = domEditable.ownerDocument.getSelection();
|
|
9135
9145
|
// Fake selection needs to be updated if there's no fake selection container, or the container currently sits
|
|
9136
9146
|
// in a different root.
|
|
9137
|
-
if (!container || container.parentElement !==
|
|
9147
|
+
if (!container || container.parentElement !== domEditable) {
|
|
9138
9148
|
return true;
|
|
9139
9149
|
}
|
|
9140
9150
|
// Make sure that the selection actually is within the fake selection.
|
|
@@ -10265,7 +10275,7 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
|
|
|
10265
10275
|
try {
|
|
10266
10276
|
range.setStart(selection.anchorNode, selection.anchorOffset);
|
|
10267
10277
|
range.setEnd(selection.focusNode, selection.focusOffset);
|
|
10268
|
-
} catch
|
|
10278
|
+
} catch {
|
|
10269
10279
|
// Safari sometimes gives us a selection that makes Range.set{Start,End} throw.
|
|
10270
10280
|
// See https://github.com/ckeditor/ckeditor5/issues/12375.
|
|
10271
10281
|
return false;
|
|
@@ -10853,7 +10863,7 @@ const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
|
|
|
10853
10863
|
const container = domSelection.getRangeAt(0).startContainer;
|
|
10854
10864
|
try {
|
|
10855
10865
|
Object.prototype.toString.call(container);
|
|
10856
|
-
} catch
|
|
10866
|
+
} catch {
|
|
10857
10867
|
return true;
|
|
10858
10868
|
}
|
|
10859
10869
|
return false;
|
|
@@ -11784,8 +11794,9 @@ function sameNodes(child1, child2) {
|
|
|
11784
11794
|
this.view.hasDomSelection = true;
|
|
11785
11795
|
// Mark the latest focus change as complete (we got new selection after the focus so the selection is in the focused element).
|
|
11786
11796
|
this.focusObserver.flush();
|
|
11787
|
-
// Ignore selection change as the editable is not focused.
|
|
11788
|
-
|
|
11797
|
+
// Ignore selection change as the editable is not focused. Note that in read-only mode, we have to update
|
|
11798
|
+
// the model selection as there won't be any focus change to flush the pending selection changes.
|
|
11799
|
+
if (!this.view.document.isFocused && !this.view.document.isReadOnly) {
|
|
11789
11800
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
11790
11801
|
// @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'SelectionObserver',
|
|
11791
11802
|
// @if CK_DEBUG_TYPING // 'Ignore selection change while editable is not focused'
|
|
@@ -12068,7 +12079,8 @@ function getFiles(nativeDataTransfer) {
|
|
|
12068
12079
|
if (viewStart && startsWithFiller(domRange.startContainer) && domRange.startOffset < INLINE_FILLER_LENGTH) {
|
|
12069
12080
|
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
12070
12081
|
// @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'InputObserver',
|
|
12071
|
-
// @if CK_DEBUG_TYPING // '
|
|
12082
|
+
// @if CK_DEBUG_TYPING // '%cTarget range starts in an inline filler - adjusting it',
|
|
12083
|
+
// @if CK_DEBUG_TYPING // 'font-style: italic'
|
|
12072
12084
|
// @if CK_DEBUG_TYPING // ) );
|
|
12073
12085
|
// @if CK_DEBUG_TYPING // }
|
|
12074
12086
|
domEvent.preventDefault();
|
|
@@ -12088,6 +12100,16 @@ function getFiles(nativeDataTransfer) {
|
|
|
12088
12100
|
singleCharacters: true
|
|
12089
12101
|
});
|
|
12090
12102
|
}
|
|
12103
|
+
// Check if there is no an inline filler just after the target range.
|
|
12104
|
+
if (isFollowedByInlineFiller(domRange.endContainer, domRange.endOffset)) {
|
|
12105
|
+
// @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
|
|
12106
|
+
// @if CK_DEBUG_TYPING // console.info( ..._buildLogMessage( this, 'InputObserver',
|
|
12107
|
+
// @if CK_DEBUG_TYPING // '%cTarget range ends just before an inline filler - prevent default behavior',
|
|
12108
|
+
// @if CK_DEBUG_TYPING // 'font-style: italic'
|
|
12109
|
+
// @if CK_DEBUG_TYPING // ) );
|
|
12110
|
+
// @if CK_DEBUG_TYPING // }
|
|
12111
|
+
domEvent.preventDefault();
|
|
12112
|
+
}
|
|
12091
12113
|
if (viewStart) {
|
|
12092
12114
|
return view.createRange(viewStart, viewEnd);
|
|
12093
12115
|
} else if (viewEnd) {
|
|
@@ -12139,6 +12161,8 @@ function getFiles(nativeDataTransfer) {
|
|
|
12139
12161
|
// it to paragraphs as it is our default action for enter handling.
|
|
12140
12162
|
const parts = data.split(/\n{1,2}/g);
|
|
12141
12163
|
let partTargetRanges = targetRanges;
|
|
12164
|
+
// Handle all parts on our side as we rely on paragraph inserting and synchronously updated view selection.
|
|
12165
|
+
domEvent.preventDefault();
|
|
12142
12166
|
for(let i = 0; i < parts.length; i++){
|
|
12143
12167
|
const dataPart = parts[i];
|
|
12144
12168
|
if (dataPart != '') {
|
|
@@ -12183,6 +12207,28 @@ function getFiles(nativeDataTransfer) {
|
|
|
12183
12207
|
// @if CK_DEBUG_TYPING // }
|
|
12184
12208
|
}
|
|
12185
12209
|
}
|
|
12210
|
+
/**
|
|
12211
|
+
* Returns `true` if there is an inline filler just after the position in DOM.
|
|
12212
|
+
* It walks up the DOM tree if the offset is at the end of the node.
|
|
12213
|
+
*/ function isFollowedByInlineFiller(node, offset) {
|
|
12214
|
+
while(node.parentNode){
|
|
12215
|
+
if (isText(node)) {
|
|
12216
|
+
if (offset != node.data.length) {
|
|
12217
|
+
return false;
|
|
12218
|
+
}
|
|
12219
|
+
} else {
|
|
12220
|
+
if (offset != node.childNodes.length) {
|
|
12221
|
+
return false;
|
|
12222
|
+
}
|
|
12223
|
+
}
|
|
12224
|
+
offset = indexOf(node) + 1;
|
|
12225
|
+
node = node.parentNode;
|
|
12226
|
+
if (offset < node.childNodes.length && startsWithFiller(node.childNodes[offset])) {
|
|
12227
|
+
return true;
|
|
12228
|
+
}
|
|
12229
|
+
}
|
|
12230
|
+
return false;
|
|
12231
|
+
}
|
|
12186
12232
|
|
|
12187
12233
|
/**
|
|
12188
12234
|
* Arrow keys observer introduces the {@link module:engine/view/document~Document#event:arrowKey `Document#arrowKey`} event.
|
|
@@ -39192,7 +39238,7 @@ function convertToModelText() {
|
|
|
39192
39238
|
function parseAttributeValue(attribute) {
|
|
39193
39239
|
try {
|
|
39194
39240
|
return JSON.parse(attribute);
|
|
39195
|
-
} catch
|
|
39241
|
+
} catch {
|
|
39196
39242
|
return attribute;
|
|
39197
39243
|
}
|
|
39198
39244
|
}
|