@ckeditor/ckeditor5-typing 40.0.0 → 40.2.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.
@@ -1,80 +1,83 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
- /**
6
- * @module typing/inserttextcommand
7
- */
8
- import { Command } from '@ckeditor/ckeditor5-core';
9
- import ChangeBuffer from './utils/changebuffer';
10
- /**
11
- * The insert text command. Used by the {@link module:typing/input~Input input feature} to handle typing.
12
- */
13
- export default class InsertTextCommand extends Command {
14
- /**
15
- * Creates an instance of the command.
16
- *
17
- * @param undoStepSize The maximum number of atomic changes
18
- * which can be contained in one batch in the command buffer.
19
- */
20
- constructor(editor, undoStepSize) {
21
- super(editor);
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;
25
- }
26
- /**
27
- * The current change buffer.
28
- */
29
- get buffer() {
30
- return this._buffer;
31
- }
32
- /**
33
- * @inheritDoc
34
- */
35
- destroy() {
36
- super.destroy();
37
- this._buffer.destroy();
38
- }
39
- /**
40
- * Executes the input command. It replaces the content within the given range with the given text.
41
- * Replacing is a two step process, first the content within the range is removed and then the new text is inserted
42
- * at the beginning of the range (which after the removal is a collapsed range).
43
- *
44
- * @fires execute
45
- * @param options The command options.
46
- */
47
- execute(options = {}) {
48
- const model = this.editor.model;
49
- const doc = model.document;
50
- const text = options.text || '';
51
- const textInsertions = text.length;
52
- let selection = doc.selection;
53
- if (options.selection) {
54
- selection = options.selection;
55
- }
56
- else if (options.range) {
57
- selection = model.createSelection(options.range);
58
- }
59
- // Stop executing if selectable is in non-editable place.
60
- if (!model.canEditAt(selection)) {
61
- return;
62
- }
63
- const resultRange = options.resultRange;
64
- model.enqueueChange(this._buffer.batch, writer => {
65
- this._buffer.lock();
66
- model.deleteContent(selection);
67
- if (text) {
68
- model.insertContent(writer.createText(text, doc.selection.getAttributes()), selection);
69
- }
70
- if (resultRange) {
71
- writer.setSelection(resultRange);
72
- }
73
- else if (!selection.is('documentSelection')) {
74
- writer.setSelection(selection);
75
- }
76
- this._buffer.unlock();
77
- this._buffer.input(textInsertions);
78
- });
79
- }
80
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module typing/inserttextcommand
7
+ */
8
+ import { Command } from '@ckeditor/ckeditor5-core';
9
+ import ChangeBuffer from './utils/changebuffer';
10
+ /**
11
+ * The insert text command. Used by the {@link module:typing/input~Input input feature} to handle typing.
12
+ */
13
+ export default class InsertTextCommand extends Command {
14
+ /**
15
+ * Creates an instance of the command.
16
+ *
17
+ * @param undoStepSize The maximum number of atomic changes
18
+ * which can be contained in one batch in the command buffer.
19
+ */
20
+ constructor(editor, undoStepSize) {
21
+ super(editor);
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;
25
+ }
26
+ /**
27
+ * The current change buffer.
28
+ */
29
+ get buffer() {
30
+ return this._buffer;
31
+ }
32
+ /**
33
+ * @inheritDoc
34
+ */
35
+ destroy() {
36
+ super.destroy();
37
+ this._buffer.destroy();
38
+ }
39
+ /**
40
+ * Executes the input command. It replaces the content within the given range with the given text.
41
+ * Replacing is a two step process, first the content within the range is removed and then the new text is inserted
42
+ * at the beginning of the range (which after the removal is a collapsed range).
43
+ *
44
+ * @fires execute
45
+ * @param options The command options.
46
+ */
47
+ execute(options = {}) {
48
+ const model = this.editor.model;
49
+ const doc = model.document;
50
+ const text = options.text || '';
51
+ const textInsertions = text.length;
52
+ let selection = doc.selection;
53
+ if (options.selection) {
54
+ selection = options.selection;
55
+ }
56
+ else if (options.range) {
57
+ selection = model.createSelection(options.range);
58
+ }
59
+ // Stop executing if selectable is in non-editable place.
60
+ if (!model.canEditAt(selection)) {
61
+ return;
62
+ }
63
+ const resultRange = options.resultRange;
64
+ model.enqueueChange(this._buffer.batch, writer => {
65
+ this._buffer.lock();
66
+ // Store selection attributes before deleting old content to preserve formatting and link.
67
+ // This unifies the behavior between DocumentSelection and Selection provided as input option.
68
+ const selectionAttributes = Array.from(doc.selection.getAttributes());
69
+ model.deleteContent(selection);
70
+ if (text) {
71
+ model.insertContent(writer.createText(text, selectionAttributes), selection);
72
+ }
73
+ if (resultRange) {
74
+ writer.setSelection(resultRange);
75
+ }
76
+ else if (!selection.is('documentSelection')) {
77
+ writer.setSelection(selection);
78
+ }
79
+ this._buffer.unlock();
80
+ this._buffer.input(textInsertions);
81
+ });
82
+ }
83
+ }
@@ -1,59 +1,59 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
- import { DomEventData, Observer, FocusObserver, type View, type ViewDocumentSelection, type ViewRange, type ViewSelection } from '@ckeditor/ckeditor5-engine';
6
- /**
7
- * Text insertion observer introduces the {@link module:engine/view/document~Document#event:insertText} event.
8
- */
9
- export default class InsertTextObserver extends Observer {
10
- /**
11
- * Instance of the focus observer. Insert text observer calls
12
- * {@link module:engine/view/observer/focusobserver~FocusObserver#flush} to mark the latest focus change as complete.
13
- */
14
- readonly focusObserver: FocusObserver;
15
- /**
16
- * @inheritDoc
17
- */
18
- constructor(view: View);
19
- /**
20
- * @inheritDoc
21
- */
22
- observe(): void;
23
- /**
24
- * @inheritDoc
25
- */
26
- stopObserving(): void;
27
- }
28
- /**
29
- * Event fired when the user types text, for instance presses <kbd>A</kbd> or <kbd>?</kbd> in the
30
- * editing view document.
31
- *
32
- * **Note**: This event will **not** fire for keystrokes such as <kbd>Delete</kbd> or <kbd>Enter</kbd>.
33
- * They have dedicated events, see {@link module:engine/view/document~Document#event:delete} and
34
- * {@link module:engine/view/document~Document#event:enter} to learn more.
35
- *
36
- * **Note**: This event is fired by the {@link module:typing/inserttextobserver~InsertTextObserver input feature}.
37
- *
38
- * @eventName module:engine/view/document~Document#insertText
39
- * @param data The event data.
40
- */
41
- export type ViewDocumentInsertTextEvent = {
42
- name: 'insertText';
43
- args: [data: InsertTextEventData];
44
- };
45
- export interface InsertTextEventData extends DomEventData {
46
- /**
47
- * The text to be inserted.
48
- */
49
- text: string;
50
- /**
51
- * The selection into which the text should be inserted.
52
- * If not specified, the insertion should occur at the current view selection.
53
- */
54
- selection: ViewSelection | ViewDocumentSelection;
55
- /**
56
- * The range that view selection should be set to after insertion.
57
- */
58
- resultRange?: ViewRange;
59
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import { DomEventData, Observer, FocusObserver, type View, type ViewDocumentSelection, type ViewRange, type ViewSelection } from '@ckeditor/ckeditor5-engine';
6
+ /**
7
+ * Text insertion observer introduces the {@link module:engine/view/document~Document#event:insertText} event.
8
+ */
9
+ export default class InsertTextObserver extends Observer {
10
+ /**
11
+ * Instance of the focus observer. Insert text observer calls
12
+ * {@link module:engine/view/observer/focusobserver~FocusObserver#flush} to mark the latest focus change as complete.
13
+ */
14
+ readonly focusObserver: FocusObserver;
15
+ /**
16
+ * @inheritDoc
17
+ */
18
+ constructor(view: View);
19
+ /**
20
+ * @inheritDoc
21
+ */
22
+ observe(): void;
23
+ /**
24
+ * @inheritDoc
25
+ */
26
+ stopObserving(): void;
27
+ }
28
+ /**
29
+ * Event fired when the user types text, for instance presses <kbd>A</kbd> or <kbd>?</kbd> in the
30
+ * editing view document.
31
+ *
32
+ * **Note**: This event will **not** fire for keystrokes such as <kbd>Delete</kbd> or <kbd>Enter</kbd>.
33
+ * They have dedicated events, see {@link module:engine/view/document~Document#event:delete} and
34
+ * {@link module:engine/view/document~Document#event:enter} to learn more.
35
+ *
36
+ * **Note**: This event is fired by the {@link module:typing/inserttextobserver~InsertTextObserver input feature}.
37
+ *
38
+ * @eventName module:engine/view/document~Document#insertText
39
+ * @param data The event data.
40
+ */
41
+ export type ViewDocumentInsertTextEvent = {
42
+ name: 'insertText';
43
+ args: [data: InsertTextEventData];
44
+ };
45
+ export interface InsertTextEventData extends DomEventData {
46
+ /**
47
+ * The text to be inserted.
48
+ */
49
+ text: string;
50
+ /**
51
+ * The selection into which the text should be inserted.
52
+ * If not specified, the insertion should occur at the current view selection.
53
+ */
54
+ selection: ViewSelection | ViewDocumentSelection;
55
+ /**
56
+ * The range that view selection should be set to after insertion.
57
+ */
58
+ resultRange?: ViewRange;
59
+ }
@@ -1,108 +1,108 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
- /**
6
- * @module typing/inserttextobserver
7
- */
8
- import { env, EventInfo } from '@ckeditor/ckeditor5-utils';
9
- import { DomEventData, Observer, FocusObserver } from '@ckeditor/ckeditor5-engine';
10
- const TYPING_INPUT_TYPES = [
11
- // For collapsed range:
12
- // - This one is a regular typing (all browsers, all systems).
13
- // - This one is used by Chrome when typing accented letter – 2nd step when the user selects the accent (Mac).
14
- // For non-collapsed range:
15
- // - This one is used by Chrome when typing accented letter – when the selection box first appears (Mac).
16
- // - This one is used by Safari when accepting spell check suggestions from the context menu (Mac).
17
- 'insertText',
18
- // This one is used by Safari when typing accented letter (Mac).
19
- // This one is used by Safari when accepting spell check suggestions from the autocorrection pop-up (Mac).
20
- 'insertReplacementText'
21
- ];
22
- /**
23
- * Text insertion observer introduces the {@link module:engine/view/document~Document#event:insertText} event.
24
- */
25
- export default class InsertTextObserver extends Observer {
26
- /**
27
- * @inheritDoc
28
- */
29
- constructor(view) {
30
- super(view);
31
- this.focusObserver = view.getObserver(FocusObserver);
32
- // On Android composition events should immediately be applied to the model. Rendering is not disabled.
33
- // On non-Android the model is updated only on composition end.
34
- // On Android we can't rely on composition start/end to update model.
35
- if (env.isAndroid) {
36
- TYPING_INPUT_TYPES.push('insertCompositionText');
37
- }
38
- const viewDocument = view.document;
39
- viewDocument.on('beforeinput', (evt, data) => {
40
- if (!this.isEnabled) {
41
- return;
42
- }
43
- const { data: text, targetRanges, inputType, domEvent } = data;
44
- if (!TYPING_INPUT_TYPES.includes(inputType)) {
45
- return;
46
- }
47
- // Mark the latest focus change as complete (we are typing in editable after the focus
48
- // so the selection is in the focused element).
49
- this.focusObserver.flush();
50
- const eventInfo = new EventInfo(viewDocument, 'insertText');
51
- viewDocument.fire(eventInfo, new DomEventData(view, domEvent, {
52
- text,
53
- selection: view.createSelection(targetRanges)
54
- }));
55
- // Stop the beforeinput event if `delete` event was stopped.
56
- // https://github.com/ckeditor/ckeditor5/issues/753
57
- if (eventInfo.stop.called) {
58
- evt.stop();
59
- }
60
- });
61
- // Note: The priority must be lower than the CompositionObserver handler to call it after the renderer is unblocked.
62
- viewDocument.on('compositionend', (evt, { data, domEvent }) => {
63
- // On Android composition events are immediately applied to the model.
64
- // On non-Android the model is updated only on composition end.
65
- // On Android we can't rely on composition start/end to update model.
66
- if (!this.isEnabled || env.isAndroid) {
67
- return;
68
- }
69
- // In case of aborted composition.
70
- if (!data) {
71
- return;
72
- }
73
- // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
74
- // @if CK_DEBUG_TYPING // console.log( `%c[InsertTextObserver]%c Fire insertText event, text: ${ JSON.stringify( data ) }`,
75
- // @if CK_DEBUG_TYPING // 'font-weight: bold; color: green;', ''
76
- // @if CK_DEBUG_TYPING // );
77
- // @if CK_DEBUG_TYPING // }
78
- // How do we know where to insert the composed text?
79
- // The selection observer is blocked and the view is not updated with the composition changes.
80
- // There were three options:
81
- // - Store the selection on `compositionstart` and use it now. This wouldn't work in RTC
82
- // where the view would change and the stored selection might get incorrect.
83
- // We'd need to fallback to the current view selection anyway.
84
- // - Use the current view selection. This is a bit weird and non-intuitive because
85
- // this isn't necessarily the selection on which the user started composing.
86
- // We cannot even know whether it's still collapsed (there might be some weird
87
- // editor feature that changed it in unpredictable ways for us). But it's by far
88
- // the simplest solution and should be stable (the selection is definitely correct)
89
- // and probably mostly predictable (features usually don't modify the selection
90
- // unless called explicitly by the user).
91
- // - Try to follow it from the `beforeinput` events. This would be really complex as each
92
- // `beforeinput` would come with just the range it's changing and we'd need to calculate that.
93
- // We decided to go with the 2nd option for its simplicity and stability.
94
- viewDocument.fire('insertText', new DomEventData(view, domEvent, {
95
- text: data,
96
- selection: viewDocument.selection
97
- }));
98
- }, { priority: 'lowest' });
99
- }
100
- /**
101
- * @inheritDoc
102
- */
103
- observe() { }
104
- /**
105
- * @inheritDoc
106
- */
107
- stopObserving() { }
108
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module typing/inserttextobserver
7
+ */
8
+ import { env, EventInfo } from '@ckeditor/ckeditor5-utils';
9
+ import { DomEventData, Observer, FocusObserver } from '@ckeditor/ckeditor5-engine';
10
+ const TYPING_INPUT_TYPES = [
11
+ // For collapsed range:
12
+ // - This one is a regular typing (all browsers, all systems).
13
+ // - This one is used by Chrome when typing accented letter – 2nd step when the user selects the accent (Mac).
14
+ // For non-collapsed range:
15
+ // - This one is used by Chrome when typing accented letter – when the selection box first appears (Mac).
16
+ // - This one is used by Safari when accepting spell check suggestions from the context menu (Mac).
17
+ 'insertText',
18
+ // This one is used by Safari when typing accented letter (Mac).
19
+ // This one is used by Safari when accepting spell check suggestions from the autocorrection pop-up (Mac).
20
+ 'insertReplacementText'
21
+ ];
22
+ /**
23
+ * Text insertion observer introduces the {@link module:engine/view/document~Document#event:insertText} event.
24
+ */
25
+ export default class InsertTextObserver extends Observer {
26
+ /**
27
+ * @inheritDoc
28
+ */
29
+ constructor(view) {
30
+ super(view);
31
+ this.focusObserver = view.getObserver(FocusObserver);
32
+ // On Android composition events should immediately be applied to the model. Rendering is not disabled.
33
+ // On non-Android the model is updated only on composition end.
34
+ // On Android we can't rely on composition start/end to update model.
35
+ if (env.isAndroid) {
36
+ TYPING_INPUT_TYPES.push('insertCompositionText');
37
+ }
38
+ const viewDocument = view.document;
39
+ viewDocument.on('beforeinput', (evt, data) => {
40
+ if (!this.isEnabled) {
41
+ return;
42
+ }
43
+ const { data: text, targetRanges, inputType, domEvent } = data;
44
+ if (!TYPING_INPUT_TYPES.includes(inputType)) {
45
+ return;
46
+ }
47
+ // Mark the latest focus change as complete (we are typing in editable after the focus
48
+ // so the selection is in the focused element).
49
+ this.focusObserver.flush();
50
+ const eventInfo = new EventInfo(viewDocument, 'insertText');
51
+ viewDocument.fire(eventInfo, new DomEventData(view, domEvent, {
52
+ text,
53
+ selection: view.createSelection(targetRanges)
54
+ }));
55
+ // Stop the beforeinput event if `delete` event was stopped.
56
+ // https://github.com/ckeditor/ckeditor5/issues/753
57
+ if (eventInfo.stop.called) {
58
+ evt.stop();
59
+ }
60
+ });
61
+ // Note: The priority must be lower than the CompositionObserver handler to call it after the renderer is unblocked.
62
+ viewDocument.on('compositionend', (evt, { data, domEvent }) => {
63
+ // On Android composition events are immediately applied to the model.
64
+ // On non-Android the model is updated only on composition end.
65
+ // On Android we can't rely on composition start/end to update model.
66
+ if (!this.isEnabled || env.isAndroid) {
67
+ return;
68
+ }
69
+ // In case of aborted composition.
70
+ if (!data) {
71
+ return;
72
+ }
73
+ // @if CK_DEBUG_TYPING // if ( ( window as any ).logCKETyping ) {
74
+ // @if CK_DEBUG_TYPING // console.log( `%c[InsertTextObserver]%c Fire insertText event, text: ${ JSON.stringify( data ) }`,
75
+ // @if CK_DEBUG_TYPING // 'font-weight: bold; color: green;', ''
76
+ // @if CK_DEBUG_TYPING // );
77
+ // @if CK_DEBUG_TYPING // }
78
+ // How do we know where to insert the composed text?
79
+ // The selection observer is blocked and the view is not updated with the composition changes.
80
+ // There were three options:
81
+ // - Store the selection on `compositionstart` and use it now. This wouldn't work in RTC
82
+ // where the view would change and the stored selection might get incorrect.
83
+ // We'd need to fallback to the current view selection anyway.
84
+ // - Use the current view selection. This is a bit weird and non-intuitive because
85
+ // this isn't necessarily the selection on which the user started composing.
86
+ // We cannot even know whether it's still collapsed (there might be some weird
87
+ // editor feature that changed it in unpredictable ways for us). But it's by far
88
+ // the simplest solution and should be stable (the selection is definitely correct)
89
+ // and probably mostly predictable (features usually don't modify the selection
90
+ // unless called explicitly by the user).
91
+ // - Try to follow it from the `beforeinput` events. This would be really complex as each
92
+ // `beforeinput` would come with just the range it's changing and we'd need to calculate that.
93
+ // We decided to go with the 2nd option for its simplicity and stability.
94
+ viewDocument.fire('insertText', new DomEventData(view, domEvent, {
95
+ text: data,
96
+ selection: viewDocument.selection
97
+ }));
98
+ }, { priority: 'lowest' });
99
+ }
100
+ /**
101
+ * @inheritDoc
102
+ */
103
+ observe() { }
104
+ /**
105
+ * @inheritDoc
106
+ */
107
+ stopObserving() { }
108
+ }
@@ -1,33 +1,33 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
- */
5
- /**
6
- * @module typing/texttransformation
7
- */
8
- import { Plugin, type Editor } from '@ckeditor/ckeditor5-core';
9
- /**
10
- * The text transformation plugin.
11
- */
12
- export default class TextTransformation extends Plugin {
13
- /**
14
- * @inheritDoc
15
- */
16
- static get requires(): readonly ["Delete", "Input"];
17
- /**
18
- * @inheritDoc
19
- */
20
- static get pluginName(): "TextTransformation";
21
- /**
22
- * @inheritDoc
23
- */
24
- constructor(editor: Editor);
25
- /**
26
- * @inheritDoc
27
- */
28
- init(): void;
29
- /**
30
- * Create new TextWatcher listening to the editor for typing and selection events.
31
- */
32
- private _enableTransformationWatchers;
33
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module typing/texttransformation
7
+ */
8
+ import { Plugin, type Editor } from '@ckeditor/ckeditor5-core';
9
+ /**
10
+ * The text transformation plugin.
11
+ */
12
+ export default class TextTransformation extends Plugin {
13
+ /**
14
+ * @inheritDoc
15
+ */
16
+ static get requires(): readonly ["Delete", "Input"];
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ static get pluginName(): "TextTransformation";
21
+ /**
22
+ * @inheritDoc
23
+ */
24
+ constructor(editor: Editor);
25
+ /**
26
+ * @inheritDoc
27
+ */
28
+ init(): void;
29
+ /**
30
+ * Create new TextWatcher listening to the editor for typing and selection events.
31
+ */
32
+ private _enableTransformationWatchers;
33
+ }