@ckeditor/ckeditor5-typing 37.0.1 → 38.0.0-rc.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/package.json +21 -21
- package/src/deletecommand.js +6 -0
- package/src/deleteobserver.js +45 -8
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/inserttextcommand.js +6 -0
- package/src/utils/findattributerange.d.ts +11 -0
- package/src/utils/findattributerange.js +2 -2
- package/src/utils/inlinehighlight.d.ts +0 -3
- package/src/utils/inlinehighlight.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-typing",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "38.0.0-rc.0",
|
|
4
4
|
"description": "Typing feature for CKEditor 5.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ckeditor",
|
|
@@ -12,29 +12,29 @@
|
|
|
12
12
|
],
|
|
13
13
|
"main": "src/index.js",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@ckeditor/ckeditor5-core": "^
|
|
16
|
-
"@ckeditor/ckeditor5-engine": "^
|
|
17
|
-
"@ckeditor/ckeditor5-utils": "^
|
|
15
|
+
"@ckeditor/ckeditor5-core": "^38.0.0-rc.0",
|
|
16
|
+
"@ckeditor/ckeditor5-engine": "^38.0.0-rc.0",
|
|
17
|
+
"@ckeditor/ckeditor5-utils": "^38.0.0-rc.0",
|
|
18
18
|
"lodash-es": "^4.17.15"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@ckeditor/ckeditor5-autoformat": "^
|
|
22
|
-
"@ckeditor/ckeditor5-basic-styles": "^
|
|
23
|
-
"@ckeditor/ckeditor5-block-quote": "^
|
|
24
|
-
"@ckeditor/ckeditor5-code-block": "^
|
|
25
|
-
"@ckeditor/ckeditor5-editor-classic": "^
|
|
26
|
-
"@ckeditor/ckeditor5-enter": "^
|
|
27
|
-
"@ckeditor/ckeditor5-essentials": "^
|
|
28
|
-
"@ckeditor/ckeditor5-heading": "^
|
|
29
|
-
"@ckeditor/ckeditor5-image": "^
|
|
30
|
-
"@ckeditor/ckeditor5-indent": "^
|
|
31
|
-
"@ckeditor/ckeditor5-link": "^
|
|
32
|
-
"@ckeditor/ckeditor5-list": "^
|
|
33
|
-
"@ckeditor/ckeditor5-media-embed": "^
|
|
34
|
-
"@ckeditor/ckeditor5-mention": "^
|
|
35
|
-
"@ckeditor/ckeditor5-paragraph": "^
|
|
36
|
-
"@ckeditor/ckeditor5-table": "^
|
|
37
|
-
"@ckeditor/ckeditor5-undo": "^
|
|
21
|
+
"@ckeditor/ckeditor5-autoformat": "^38.0.0-rc.0",
|
|
22
|
+
"@ckeditor/ckeditor5-basic-styles": "^38.0.0-rc.0",
|
|
23
|
+
"@ckeditor/ckeditor5-block-quote": "^38.0.0-rc.0",
|
|
24
|
+
"@ckeditor/ckeditor5-code-block": "^38.0.0-rc.0",
|
|
25
|
+
"@ckeditor/ckeditor5-editor-classic": "^38.0.0-rc.0",
|
|
26
|
+
"@ckeditor/ckeditor5-enter": "^38.0.0-rc.0",
|
|
27
|
+
"@ckeditor/ckeditor5-essentials": "^38.0.0-rc.0",
|
|
28
|
+
"@ckeditor/ckeditor5-heading": "^38.0.0-rc.0",
|
|
29
|
+
"@ckeditor/ckeditor5-image": "^38.0.0-rc.0",
|
|
30
|
+
"@ckeditor/ckeditor5-indent": "^38.0.0-rc.0",
|
|
31
|
+
"@ckeditor/ckeditor5-link": "^38.0.0-rc.0",
|
|
32
|
+
"@ckeditor/ckeditor5-list": "^38.0.0-rc.0",
|
|
33
|
+
"@ckeditor/ckeditor5-media-embed": "^38.0.0-rc.0",
|
|
34
|
+
"@ckeditor/ckeditor5-mention": "^38.0.0-rc.0",
|
|
35
|
+
"@ckeditor/ckeditor5-paragraph": "^38.0.0-rc.0",
|
|
36
|
+
"@ckeditor/ckeditor5-table": "^38.0.0-rc.0",
|
|
37
|
+
"@ckeditor/ckeditor5-undo": "^38.0.0-rc.0",
|
|
38
38
|
"typescript": "^4.8.4",
|
|
39
39
|
"webpack": "^5.58.1",
|
|
40
40
|
"webpack-cli": "^4.9.0"
|
package/src/deletecommand.js
CHANGED
|
@@ -23,6 +23,8 @@ export default class DeleteCommand extends Command {
|
|
|
23
23
|
super(editor);
|
|
24
24
|
this.direction = direction;
|
|
25
25
|
this._buffer = new ChangeBuffer(editor.model, editor.config.get('typing.undoStep'));
|
|
26
|
+
// Since this command may execute on different selectable than selection, it should be checked directly in execute block.
|
|
27
|
+
this._isEnabledBasedOnSelection = false;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* The current change buffer.
|
|
@@ -47,6 +49,10 @@ export default class DeleteCommand extends Command {
|
|
|
47
49
|
model.enqueueChange(this._buffer.batch, writer => {
|
|
48
50
|
this._buffer.lock();
|
|
49
51
|
const selection = writer.createSelection(options.selection || doc.selection);
|
|
52
|
+
// Don't execute command when selection is in non-editable place.
|
|
53
|
+
if (!model.canEditAt(selection)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
50
56
|
const sequence = options.sequence || 1;
|
|
51
57
|
// Do not replace the whole selected content if selection was collapsed.
|
|
52
58
|
// This prevents such situation:
|
package/src/deleteobserver.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @module typing/deleteobserver
|
|
7
7
|
*/
|
|
8
|
-
import { env, keyCodes } from '@ckeditor/ckeditor5-utils';
|
|
8
|
+
import { env, keyCodes, isInsideCombinedSymbol, isInsideEmojiSequence, isInsideSurrogatePair } from '@ckeditor/ckeditor5-utils';
|
|
9
9
|
import { BubblingEventInfo, DomEventData, Observer } from '@ckeditor/ckeditor5-engine';
|
|
10
10
|
const DELETE_CHARACTER = 'character';
|
|
11
11
|
const DELETE_WORD = 'word';
|
|
@@ -133,14 +133,14 @@ export default class DeleteObserver extends Observer {
|
|
|
133
133
|
deleteData.selectionToRemove = view.createSelection(targetRanges[0]);
|
|
134
134
|
}
|
|
135
135
|
// The default deletion unit for deleteContentBackward is a single code point
|
|
136
|
-
// but
|
|
137
|
-
|
|
138
|
-
if (env.isAndroid && inputType === 'deleteContentBackward') {
|
|
136
|
+
// but if the browser provides a wider target range then we should use it.
|
|
137
|
+
if (inputType === 'deleteContentBackward') {
|
|
139
138
|
// On Android, deleteContentBackward has sequence 1 by default.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
if (env.isAndroid) {
|
|
140
|
+
deleteData.sequence = 1;
|
|
141
|
+
}
|
|
142
|
+
// The beforeInput event wants more than a single character to be removed.
|
|
143
|
+
if (shouldUseTargetRanges(targetRanges)) {
|
|
144
144
|
deleteData.unit = DELETE_SELECTION;
|
|
145
145
|
deleteData.selectionToRemove = view.createSelection(targetRanges);
|
|
146
146
|
}
|
|
@@ -222,3 +222,40 @@ function enableChromeWorkaround(observer) {
|
|
|
222
222
|
return keyCode == keyCodes.backspace ? DELETE_BACKWARD : DELETE_FORWARD;
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Verifies whether the given target ranges cover more than a single character and should be used instead of a single code-point deletion.
|
|
227
|
+
*/
|
|
228
|
+
function shouldUseTargetRanges(targetRanges) {
|
|
229
|
+
// The collapsed target range could happen for example while deleting inside an inline filler
|
|
230
|
+
// (it's mapped to collapsed position before an inline filler).
|
|
231
|
+
if (targetRanges.length != 1 || targetRanges[0].isCollapsed) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
const walker = targetRanges[0].getWalker({
|
|
235
|
+
direction: 'backward',
|
|
236
|
+
singleCharacters: true,
|
|
237
|
+
ignoreElementEnd: true
|
|
238
|
+
});
|
|
239
|
+
let count = 0;
|
|
240
|
+
for (const { nextPosition } of walker) {
|
|
241
|
+
// There is some element in the range so count it as a single character.
|
|
242
|
+
if (!nextPosition.parent.is('$text')) {
|
|
243
|
+
count++;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
const data = nextPosition.parent.data;
|
|
247
|
+
const offset = nextPosition.offset;
|
|
248
|
+
// Count combined symbols and emoji sequences as a single character.
|
|
249
|
+
if (isInsideSurrogatePair(data, offset) ||
|
|
250
|
+
isInsideCombinedSymbol(data, offset) ||
|
|
251
|
+
isInsideEmojiSequence(data, offset)) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
count++;
|
|
255
|
+
}
|
|
256
|
+
if (count > 1) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
261
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { default as TextWatcher } from './textwatcher';
|
|
|
12
12
|
export { default as TwoStepCaretMovement } from './twostepcaretmovement';
|
|
13
13
|
export { default as TextTransformation } from './texttransformation';
|
|
14
14
|
export { default as inlineHighlight } from './utils/inlinehighlight';
|
|
15
|
-
export { default as findAttributeRange } from './utils/findattributerange';
|
|
15
|
+
export { default as findAttributeRange, findAttributeRangeBound } from './utils/findattributerange';
|
|
16
16
|
export { default as getLastTextLine, type LastTextLineData } from './utils/getlasttextline';
|
|
17
17
|
export { default as InsertTextCommand, type InsertTextCommandExecuteEvent } from './inserttextcommand';
|
|
18
18
|
export type { default as DeleteCommand } from './deletecommand';
|
package/src/index.js
CHANGED
|
@@ -12,7 +12,7 @@ export { default as TextWatcher } from './textwatcher';
|
|
|
12
12
|
export { default as TwoStepCaretMovement } from './twostepcaretmovement';
|
|
13
13
|
export { default as TextTransformation } from './texttransformation';
|
|
14
14
|
export { default as inlineHighlight } from './utils/inlinehighlight';
|
|
15
|
-
export { default as findAttributeRange } from './utils/findattributerange';
|
|
15
|
+
export { default as findAttributeRange, findAttributeRangeBound } from './utils/findattributerange';
|
|
16
16
|
export { default as getLastTextLine } from './utils/getlasttextline';
|
|
17
17
|
export { default as InsertTextCommand } from './inserttextcommand';
|
|
18
18
|
import './augmentation';
|
package/src/inserttextcommand.js
CHANGED
|
@@ -20,6 +20,8 @@ export default class InsertTextCommand extends Command {
|
|
|
20
20
|
constructor(editor, undoStepSize) {
|
|
21
21
|
super(editor);
|
|
22
22
|
this._buffer = new ChangeBuffer(editor.model, undoStepSize);
|
|
23
|
+
// Since this command may execute on different selectable than selection, it should be checked directly in execute block.
|
|
24
|
+
this._isEnabledBasedOnSelection = false;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
27
|
* The current change buffer.
|
|
@@ -54,6 +56,10 @@ export default class InsertTextCommand extends Command {
|
|
|
54
56
|
else if (options.range) {
|
|
55
57
|
selection = model.createSelection(options.range);
|
|
56
58
|
}
|
|
59
|
+
// Stop executing if selectable is in non-editable place.
|
|
60
|
+
if (!model.canEditAt(selection)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
57
63
|
const resultRange = options.resultRange;
|
|
58
64
|
model.enqueueChange(this._buffer.batch, writer => {
|
|
59
65
|
this._buffer.lock();
|
|
@@ -20,3 +20,14 @@ import type { Position, Model, Range } from '@ckeditor/ckeditor5-engine';
|
|
|
20
20
|
* @returns The link range.
|
|
21
21
|
*/
|
|
22
22
|
export default function findAttributeRange(position: Position, attributeName: string, value: unknown, model: Model): Range;
|
|
23
|
+
/**
|
|
24
|
+
* Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same attribute value
|
|
25
|
+
* and returns a position just before or after (depends on the `lookBack` flag) the last matched node.
|
|
26
|
+
*
|
|
27
|
+
* @param position The start position.
|
|
28
|
+
* @param attributeName The attribute name.
|
|
29
|
+
* @param value The attribute value.
|
|
30
|
+
* @param lookBack Whether the walk direction is forward (`false`) or backward (`true`).
|
|
31
|
+
* @returns The position just before the last matched node.
|
|
32
|
+
*/
|
|
33
|
+
export declare function findAttributeRangeBound(position: Position, attributeName: string, value: unknown, lookBack: boolean, model: Model): Position;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* @returns The link range.
|
|
17
17
|
*/
|
|
18
18
|
export default function findAttributeRange(position, attributeName, value, model) {
|
|
19
|
-
return model.createRange(
|
|
19
|
+
return model.createRange(findAttributeRangeBound(position, attributeName, value, true, model), findAttributeRangeBound(position, attributeName, value, false, model));
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same attribute value
|
|
@@ -28,7 +28,7 @@ export default function findAttributeRange(position, attributeName, value, model
|
|
|
28
28
|
* @param lookBack Whether the walk direction is forward (`false`) or backward (`true`).
|
|
29
29
|
* @returns The position just before the last matched node.
|
|
30
30
|
*/
|
|
31
|
-
function
|
|
31
|
+
export function findAttributeRangeBound(position, attributeName, value, lookBack, model) {
|
|
32
32
|
// Get node before or after position (depends on `lookBack` flag).
|
|
33
33
|
// When position is inside text node then start searching from text node.
|
|
34
34
|
let node = position.textNode || (lookBack ? position.nodeBefore : position.nodeAfter);
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
5
|
import type { Editor } from '@ckeditor/ckeditor5-core';
|
|
6
|
-
/**
|
|
7
|
-
* @module typing/utils/inlinehighlight
|
|
8
|
-
*/
|
|
9
6
|
/**
|
|
10
7
|
* Adds a visual highlight style to an attribute element in which the selection is anchored.
|
|
11
8
|
* Together with two-step caret movement, they indicate that the user is typing inside the element.
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
import findAttributeRange from './findattributerange';
|
|
6
5
|
/**
|
|
7
6
|
* @module typing/utils/inlinehighlight
|
|
8
7
|
*/
|
|
8
|
+
import findAttributeRange from './findattributerange';
|
|
9
9
|
/**
|
|
10
10
|
* Adds a visual highlight style to an attribute element in which the selection is anchored.
|
|
11
11
|
* Together with two-step caret movement, they indicate that the user is typing inside the element.
|