@ckeditor/ckeditor5-typing 47.6.1 → 48.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.
- package/LICENSE.md +1 -1
- package/ckeditor5-metadata.json +1 -1
- package/dist/index.css +3 -0
- package/dist/index.css.map +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/{src → dist}/texttransformation.d.ts +3 -1
- package/package.json +22 -41
- package/src/augmentation.js +0 -5
- package/src/delete.js +0 -122
- package/src/deletecommand.js +0 -212
- package/src/deleteobserver.js +0 -262
- package/src/index.js +0 -21
- package/src/input.js +0 -486
- package/src/inserttextcommand.js +0 -87
- package/src/inserttextobserver.js +0 -112
- package/src/texttransformation.js +0 -237
- package/src/textwatcher.js +0 -123
- package/src/twostepcaretmovement.js +0 -661
- package/src/typing.js +0 -33
- package/src/typingconfig.js +0 -5
- package/src/utils/changebuffer.js +0 -148
- package/src/utils/findattributerange.js +0 -41
- package/src/utils/getlasttextline.js +0 -43
- package/src/utils/inlinehighlight.js +0 -74
- /package/{src → dist}/augmentation.d.ts +0 -0
- /package/{src → dist}/delete.d.ts +0 -0
- /package/{src → dist}/deletecommand.d.ts +0 -0
- /package/{src → dist}/deleteobserver.d.ts +0 -0
- /package/{src → dist}/index.d.ts +0 -0
- /package/{src → dist}/input.d.ts +0 -0
- /package/{src → dist}/inserttextcommand.d.ts +0 -0
- /package/{src → dist}/inserttextobserver.d.ts +0 -0
- /package/{src → dist}/textwatcher.d.ts +0 -0
- /package/{src → dist}/twostepcaretmovement.d.ts +0 -0
- /package/{src → dist}/typing.d.ts +0 -0
- /package/{src → dist}/typingconfig.d.ts +0 -0
- /package/{src → dist}/utils/changebuffer.d.ts +0 -0
- /package/{src → dist}/utils/findattributerange.d.ts +0 -0
- /package/{src → dist}/utils/getlasttextline.d.ts +0 -0
- /package/{src → dist}/utils/inlinehighlight.d.ts +0 -0
package/src/typingconfig.js
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Change buffer allows to group atomic changes (like characters that have been typed) into
|
|
7
|
-
* {@link module:engine/model/batch~Batch batches}.
|
|
8
|
-
*
|
|
9
|
-
* Batches represent single undo steps, hence changes added to one single batch are undone together.
|
|
10
|
-
*
|
|
11
|
-
* The buffer has a configurable limit of atomic changes that it can accommodate. After the limit was
|
|
12
|
-
* exceeded (see {@link ~TypingChangeBuffer#input}), a new batch is created in {@link ~TypingChangeBuffer#batch}.
|
|
13
|
-
*
|
|
14
|
-
* To use the change buffer you need to let it know about the number of changes that were added to the batch:
|
|
15
|
-
*
|
|
16
|
-
* ```ts
|
|
17
|
-
* const buffer = new ChangeBuffer( model, LIMIT );
|
|
18
|
-
*
|
|
19
|
-
* // Later on in your feature:
|
|
20
|
-
* buffer.batch.insert( pos, insertedCharacters );
|
|
21
|
-
* buffer.input( insertedCharacters.length );
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export class TypingChangeBuffer {
|
|
25
|
-
/**
|
|
26
|
-
* The model instance.
|
|
27
|
-
*/
|
|
28
|
-
model;
|
|
29
|
-
/**
|
|
30
|
-
* The maximum number of atomic changes which can be contained in one batch.
|
|
31
|
-
*/
|
|
32
|
-
limit;
|
|
33
|
-
/**
|
|
34
|
-
* Whether the buffer is locked. A locked buffer cannot be reset unless it gets unlocked.
|
|
35
|
-
*/
|
|
36
|
-
_isLocked;
|
|
37
|
-
/**
|
|
38
|
-
* The number of atomic changes in the buffer. Once it exceeds the {@link #limit},
|
|
39
|
-
* the {@link #batch batch} is set to a new one.
|
|
40
|
-
*/
|
|
41
|
-
_size;
|
|
42
|
-
/**
|
|
43
|
-
* The current batch instance.
|
|
44
|
-
*/
|
|
45
|
-
_batch = null;
|
|
46
|
-
/**
|
|
47
|
-
* The callback to document the change event which later needs to be removed.
|
|
48
|
-
*/
|
|
49
|
-
_changeCallback;
|
|
50
|
-
/**
|
|
51
|
-
* The callback to document selection `change:attribute` and `change:range` events which resets the buffer.
|
|
52
|
-
*/
|
|
53
|
-
_selectionChangeCallback;
|
|
54
|
-
/**
|
|
55
|
-
* Creates a new instance of the change buffer.
|
|
56
|
-
*
|
|
57
|
-
* @param limit The maximum number of atomic changes which can be contained in one batch.
|
|
58
|
-
*/
|
|
59
|
-
constructor(model, limit = 20) {
|
|
60
|
-
this.model = model;
|
|
61
|
-
this._size = 0;
|
|
62
|
-
this.limit = limit;
|
|
63
|
-
this._isLocked = false;
|
|
64
|
-
// The function to be called in order to notify the buffer about batches which appeared in the document.
|
|
65
|
-
// The callback will check whether it is a new batch and in that case the buffer will be flushed.
|
|
66
|
-
//
|
|
67
|
-
// The reason why the buffer needs to be flushed whenever a new batch appears is that the changes added afterwards
|
|
68
|
-
// should be added to a new batch. For instance, when the user types, then inserts an image, and then types again,
|
|
69
|
-
// the characters typed after inserting the image should be added to a different batch than the characters typed before.
|
|
70
|
-
this._changeCallback = (evt, batch) => {
|
|
71
|
-
if (batch.isLocal && batch.isUndoable && batch !== this._batch) {
|
|
72
|
-
this._reset(true);
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
this._selectionChangeCallback = () => {
|
|
76
|
-
this._reset();
|
|
77
|
-
};
|
|
78
|
-
this.model.document.on('change', this._changeCallback);
|
|
79
|
-
this.model.document.selection.on('change:range', this._selectionChangeCallback);
|
|
80
|
-
this.model.document.selection.on('change:attribute', this._selectionChangeCallback);
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* The current batch to which a feature should add its operations. Once the {@link #size}
|
|
84
|
-
* is reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.
|
|
85
|
-
*/
|
|
86
|
-
get batch() {
|
|
87
|
-
if (!this._batch) {
|
|
88
|
-
this._batch = this.model.createBatch({ isTyping: true });
|
|
89
|
-
}
|
|
90
|
-
return this._batch;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* The number of atomic changes in the buffer. Once it exceeds the {@link #limit},
|
|
94
|
-
* the {@link #batch batch} is set to a new one.
|
|
95
|
-
*/
|
|
96
|
-
get size() {
|
|
97
|
-
return this._size;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* The input number of changes into the buffer. Once the {@link #size} is
|
|
101
|
-
* reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.
|
|
102
|
-
*
|
|
103
|
-
* @param changeCount The number of atomic changes to input.
|
|
104
|
-
*/
|
|
105
|
-
input(changeCount) {
|
|
106
|
-
this._size += changeCount;
|
|
107
|
-
if (this._size >= this.limit) {
|
|
108
|
-
this._reset(true);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Whether the buffer is locked. A locked buffer cannot be reset unless it gets unlocked.
|
|
113
|
-
*/
|
|
114
|
-
get isLocked() {
|
|
115
|
-
return this._isLocked;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Locks the buffer.
|
|
119
|
-
*/
|
|
120
|
-
lock() {
|
|
121
|
-
this._isLocked = true;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Unlocks the buffer.
|
|
125
|
-
*/
|
|
126
|
-
unlock() {
|
|
127
|
-
this._isLocked = false;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Destroys the buffer.
|
|
131
|
-
*/
|
|
132
|
-
destroy() {
|
|
133
|
-
this.model.document.off('change', this._changeCallback);
|
|
134
|
-
this.model.document.selection.off('change:range', this._selectionChangeCallback);
|
|
135
|
-
this.model.document.selection.off('change:attribute', this._selectionChangeCallback);
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Resets the change buffer.
|
|
139
|
-
*
|
|
140
|
-
* @param ignoreLock Whether internal lock {@link #isLocked} should be ignored.
|
|
141
|
-
*/
|
|
142
|
-
_reset(ignoreLock = false) {
|
|
143
|
-
if (!this.isLocked || ignoreLock) {
|
|
144
|
-
this._batch = null;
|
|
145
|
-
this._size = 0;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Returns a model range that covers all consecutive nodes with the same `attributeName` and its `value`
|
|
7
|
-
* that intersect the given `position`.
|
|
8
|
-
*
|
|
9
|
-
* It can be used e.g. to get the entire range on which the `linkHref` attribute needs to be changed when having a
|
|
10
|
-
* selection inside a link.
|
|
11
|
-
*
|
|
12
|
-
* @param position The start position.
|
|
13
|
-
* @param attributeName The attribute name.
|
|
14
|
-
* @param value The attribute value.
|
|
15
|
-
* @param model The model instance.
|
|
16
|
-
* @returns The link range.
|
|
17
|
-
*/
|
|
18
|
-
export function findAttributeRange(position, attributeName, value, model) {
|
|
19
|
-
return model.createRange(findAttributeRangeBound(position, attributeName, value, true, model), findAttributeRangeBound(position, attributeName, value, false, model));
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same attribute value
|
|
23
|
-
* and returns a position just before or after (depends on the `lookBack` flag) the last matched node.
|
|
24
|
-
*
|
|
25
|
-
* @param position The start position.
|
|
26
|
-
* @param attributeName The attribute name.
|
|
27
|
-
* @param value The attribute value.
|
|
28
|
-
* @param lookBack Whether the walk direction is forward (`false`) or backward (`true`).
|
|
29
|
-
* @returns The position just before the last matched node.
|
|
30
|
-
*/
|
|
31
|
-
export function findAttributeRangeBound(position, attributeName, value, lookBack, model) {
|
|
32
|
-
// Get node before or after position (depends on `lookBack` flag).
|
|
33
|
-
// When position is inside text node then start searching from text node.
|
|
34
|
-
let node = position.textNode || (lookBack ? position.nodeBefore : position.nodeAfter);
|
|
35
|
-
let lastNode = null;
|
|
36
|
-
while (node && node.getAttribute(attributeName) == value) {
|
|
37
|
-
lastNode = node;
|
|
38
|
-
node = lookBack ? node.previousSibling : node.nextSibling;
|
|
39
|
-
}
|
|
40
|
-
return lastNode ? model.createPositionAt(lastNode, lookBack ? 'before' : 'after') : position;
|
|
41
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Returns the last text line from the given range.
|
|
7
|
-
*
|
|
8
|
-
* "The last text line" is understood as text (from one or more text nodes) which is limited either by a parent block
|
|
9
|
-
* or by inline elements (e.g. `<softBreak>`).
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* const rangeToCheck = model.createRange(
|
|
13
|
-
* model.createPositionAt( paragraph, 0 ),
|
|
14
|
-
* model.createPositionAt( paragraph, 'end' )
|
|
15
|
-
* );
|
|
16
|
-
*
|
|
17
|
-
* const { text, range } = getLastTextLine( rangeToCheck, model );
|
|
18
|
-
* ```
|
|
19
|
-
*
|
|
20
|
-
* For model below, the returned `text` will be "Foo bar baz" and `range` will be set on whole `<paragraph>` content:
|
|
21
|
-
*
|
|
22
|
-
* ```xml
|
|
23
|
-
* <paragraph>Foo bar baz<paragraph>
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* However, in below case, `text` will be set to "baz" and `range` will be set only on "baz".
|
|
27
|
-
*
|
|
28
|
-
* ```xml
|
|
29
|
-
* <paragraph>Foo<softBreak></softBreak>bar<softBreak></softBreak>baz<paragraph>
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export function getLastTextLine(range, model) {
|
|
33
|
-
let start = range.start;
|
|
34
|
-
const text = Array.from(range.getWalker({ ignoreElementEnd: false })).reduce((rangeText, { item }) => {
|
|
35
|
-
// Trim text to a last occurrence of an inline element and update range start.
|
|
36
|
-
if (!(item.is('$text') || item.is('$textProxy'))) {
|
|
37
|
-
start = model.createPositionAfter(item);
|
|
38
|
-
return '';
|
|
39
|
-
}
|
|
40
|
-
return rangeText + item.data;
|
|
41
|
-
}, '');
|
|
42
|
-
return { text, range: model.createRange(start, range.end) };
|
|
43
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
-
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* @module typing/utils/inlinehighlight
|
|
7
|
-
*/
|
|
8
|
-
import { findAttributeRange } from './findattributerange.js';
|
|
9
|
-
/**
|
|
10
|
-
* Adds a visual highlight style to an attribute element in which the selection is anchored.
|
|
11
|
-
* Together with two-step caret movement, they indicate that the user is typing inside the element.
|
|
12
|
-
*
|
|
13
|
-
* Highlight is turned on by adding the given class to the attribute element in the view:
|
|
14
|
-
*
|
|
15
|
-
* * The class is removed before the conversion has started, as callbacks added with the `'highest'` priority
|
|
16
|
-
* to {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} events.
|
|
17
|
-
* * The class is added in the view post fixer, after other changes in the model tree were converted to the view.
|
|
18
|
-
*
|
|
19
|
-
* This way, adding and removing the highlight does not interfere with conversion.
|
|
20
|
-
*
|
|
21
|
-
* Usage:
|
|
22
|
-
*
|
|
23
|
-
* ```ts
|
|
24
|
-
* import { inlineHighlight } from '@ckeditor/ckeditor5-typing/src/utils/inlinehighlight';
|
|
25
|
-
*
|
|
26
|
-
* // Make `ck-link_selected` class be applied on an `a` element
|
|
27
|
-
* // whenever the corresponding `linkHref` attribute element is selected.
|
|
28
|
-
* inlineHighlight( editor, 'linkHref', 'a', 'ck-link_selected' );
|
|
29
|
-
* ```
|
|
30
|
-
*
|
|
31
|
-
* @param editor The editor instance.
|
|
32
|
-
* @param attributeName The attribute name to check.
|
|
33
|
-
* @param tagName The tagName of a view item.
|
|
34
|
-
* @param className The class name to apply in the view.
|
|
35
|
-
*/
|
|
36
|
-
export function inlineHighlight(editor, attributeName, tagName, className) {
|
|
37
|
-
const view = editor.editing.view;
|
|
38
|
-
const highlightedElements = new Set();
|
|
39
|
-
// Adding the class.
|
|
40
|
-
view.document.registerPostFixer(writer => {
|
|
41
|
-
const selection = editor.model.document.selection;
|
|
42
|
-
let changed = false;
|
|
43
|
-
if (selection.hasAttribute(attributeName)) {
|
|
44
|
-
const modelRange = findAttributeRange(selection.getFirstPosition(), attributeName, selection.getAttribute(attributeName), editor.model);
|
|
45
|
-
const viewRange = editor.editing.mapper.toViewRange(modelRange);
|
|
46
|
-
// There might be multiple view elements in the `viewRange`, for example, when the `a` element is
|
|
47
|
-
// broken by a UIElement.
|
|
48
|
-
for (const item of viewRange.getItems()) {
|
|
49
|
-
if (item.is('element', tagName) && !item.hasClass(className)) {
|
|
50
|
-
writer.addClass(className, item);
|
|
51
|
-
highlightedElements.add(item);
|
|
52
|
-
changed = true;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return changed;
|
|
57
|
-
});
|
|
58
|
-
// Removing the class.
|
|
59
|
-
editor.conversion.for('editingDowncast').add(dispatcher => {
|
|
60
|
-
// Make sure the highlight is removed on every possible event, before conversion is started.
|
|
61
|
-
dispatcher.on('insert', removeHighlight, { priority: 'highest' });
|
|
62
|
-
dispatcher.on('remove', removeHighlight, { priority: 'highest' });
|
|
63
|
-
dispatcher.on('attribute', removeHighlight, { priority: 'highest' });
|
|
64
|
-
dispatcher.on('selection', removeHighlight, { priority: 'highest' });
|
|
65
|
-
function removeHighlight() {
|
|
66
|
-
view.change(writer => {
|
|
67
|
-
for (const item of highlightedElements.values()) {
|
|
68
|
-
writer.removeClass(className, item);
|
|
69
|
-
highlightedElements.delete(item);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{src → dist}/index.d.ts
RENAMED
|
File without changes
|
/package/{src → dist}/input.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|