@ckeditor/ckeditor5-find-and-replace 47.6.1-alpha.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 +2 -2
- package/{src → dist}/findandreplace.d.ts +2 -2
- package/{src → dist}/findandreplaceediting.d.ts +2 -2
- package/{src → dist}/findandreplacestate.d.ts +4 -4
- package/{src → dist}/findandreplaceui.d.ts +2 -2
- package/{src → dist}/findandreplaceutils.d.ts +3 -3
- package/{src → dist}/findcommand.d.ts +2 -2
- package/{src → dist}/findnextcommand.d.ts +1 -1
- package/dist/index-editor.css +165 -40
- package/dist/index.css +162 -59
- package/dist/index.css.map +1 -1
- package/dist/index.js.map +1 -1
- package/{src → dist}/replaceallcommand.d.ts +1 -1
- package/{src → dist}/replacecommandbase.d.ts +1 -1
- package/{src → dist}/ui/findandreplaceformview.d.ts +2 -3
- package/package.json +24 -47
- package/build/find-and-replace.js +0 -5
- package/build/translations/af.js +0 -1
- package/build/translations/ar.js +0 -1
- package/build/translations/ast.js +0 -1
- package/build/translations/az.js +0 -1
- package/build/translations/be.js +0 -1
- package/build/translations/bg.js +0 -1
- package/build/translations/bn.js +0 -1
- package/build/translations/bs.js +0 -1
- package/build/translations/ca.js +0 -1
- package/build/translations/cs.js +0 -1
- package/build/translations/da.js +0 -1
- package/build/translations/de-ch.js +0 -1
- package/build/translations/de.js +0 -1
- package/build/translations/el.js +0 -1
- package/build/translations/en-au.js +0 -1
- package/build/translations/en-gb.js +0 -1
- package/build/translations/eo.js +0 -1
- package/build/translations/es-co.js +0 -1
- package/build/translations/es.js +0 -1
- package/build/translations/et.js +0 -1
- package/build/translations/eu.js +0 -1
- package/build/translations/fa.js +0 -1
- package/build/translations/fi.js +0 -1
- package/build/translations/fr.js +0 -1
- package/build/translations/gl.js +0 -1
- package/build/translations/gu.js +0 -1
- package/build/translations/he.js +0 -1
- package/build/translations/hi.js +0 -1
- package/build/translations/hr.js +0 -1
- package/build/translations/hu.js +0 -1
- package/build/translations/hy.js +0 -1
- package/build/translations/id.js +0 -1
- package/build/translations/it.js +0 -1
- package/build/translations/ja.js +0 -1
- package/build/translations/jv.js +0 -1
- package/build/translations/kk.js +0 -1
- package/build/translations/km.js +0 -1
- package/build/translations/kn.js +0 -1
- package/build/translations/ko.js +0 -1
- package/build/translations/ku.js +0 -1
- package/build/translations/lt.js +0 -1
- package/build/translations/lv.js +0 -1
- package/build/translations/ms.js +0 -1
- package/build/translations/nb.js +0 -1
- package/build/translations/ne.js +0 -1
- package/build/translations/nl.js +0 -1
- package/build/translations/no.js +0 -1
- package/build/translations/oc.js +0 -1
- package/build/translations/pl.js +0 -1
- package/build/translations/pt-br.js +0 -1
- package/build/translations/pt.js +0 -1
- package/build/translations/ro.js +0 -1
- package/build/translations/ru.js +0 -1
- package/build/translations/si.js +0 -1
- package/build/translations/sk.js +0 -1
- package/build/translations/sl.js +0 -1
- package/build/translations/sq.js +0 -1
- package/build/translations/sr-latn.js +0 -1
- package/build/translations/sr.js +0 -1
- package/build/translations/sv.js +0 -1
- package/build/translations/th.js +0 -1
- package/build/translations/ti.js +0 -1
- package/build/translations/tk.js +0 -1
- package/build/translations/tr.js +0 -1
- package/build/translations/tt.js +0 -1
- package/build/translations/ug.js +0 -1
- package/build/translations/uk.js +0 -1
- package/build/translations/ur.js +0 -1
- package/build/translations/uz.js +0 -1
- package/build/translations/vi.js +0 -1
- package/build/translations/zh-cn.js +0 -1
- package/build/translations/zh.js +0 -1
- package/lang/contexts.json +0 -16
- package/lang/translations/af.po +0 -68
- package/lang/translations/ar.po +0 -68
- package/lang/translations/ast.po +0 -68
- package/lang/translations/az.po +0 -68
- package/lang/translations/be.po +0 -68
- package/lang/translations/bg.po +0 -68
- package/lang/translations/bn.po +0 -68
- package/lang/translations/bs.po +0 -68
- package/lang/translations/ca.po +0 -68
- package/lang/translations/cs.po +0 -68
- package/lang/translations/da.po +0 -68
- package/lang/translations/de-ch.po +0 -68
- package/lang/translations/de.po +0 -68
- package/lang/translations/el.po +0 -68
- package/lang/translations/en-au.po +0 -68
- package/lang/translations/en-gb.po +0 -68
- package/lang/translations/en.po +0 -68
- package/lang/translations/eo.po +0 -68
- package/lang/translations/es-co.po +0 -68
- package/lang/translations/es.po +0 -68
- package/lang/translations/et.po +0 -68
- package/lang/translations/eu.po +0 -68
- package/lang/translations/fa.po +0 -68
- package/lang/translations/fi.po +0 -68
- package/lang/translations/fr.po +0 -68
- package/lang/translations/gl.po +0 -68
- package/lang/translations/gu.po +0 -68
- package/lang/translations/he.po +0 -68
- package/lang/translations/hi.po +0 -68
- package/lang/translations/hr.po +0 -68
- package/lang/translations/hu.po +0 -68
- package/lang/translations/hy.po +0 -68
- package/lang/translations/id.po +0 -68
- package/lang/translations/it.po +0 -68
- package/lang/translations/ja.po +0 -68
- package/lang/translations/jv.po +0 -68
- package/lang/translations/kk.po +0 -68
- package/lang/translations/km.po +0 -68
- package/lang/translations/kn.po +0 -68
- package/lang/translations/ko.po +0 -68
- package/lang/translations/ku.po +0 -68
- package/lang/translations/lt.po +0 -68
- package/lang/translations/lv.po +0 -68
- package/lang/translations/ms.po +0 -68
- package/lang/translations/nb.po +0 -68
- package/lang/translations/ne.po +0 -68
- package/lang/translations/nl.po +0 -68
- package/lang/translations/no.po +0 -68
- package/lang/translations/oc.po +0 -68
- package/lang/translations/pl.po +0 -68
- package/lang/translations/pt-br.po +0 -68
- package/lang/translations/pt.po +0 -68
- package/lang/translations/ro.po +0 -68
- package/lang/translations/ru.po +0 -68
- package/lang/translations/si.po +0 -68
- package/lang/translations/sk.po +0 -68
- package/lang/translations/sl.po +0 -68
- package/lang/translations/sq.po +0 -68
- package/lang/translations/sr-latn.po +0 -68
- package/lang/translations/sr.po +0 -68
- package/lang/translations/sv.po +0 -68
- package/lang/translations/th.po +0 -68
- package/lang/translations/ti.po +0 -68
- package/lang/translations/tk.po +0 -68
- package/lang/translations/tr.po +0 -68
- package/lang/translations/tt.po +0 -68
- package/lang/translations/ug.po +0 -68
- package/lang/translations/uk.po +0 -68
- package/lang/translations/ur.po +0 -68
- package/lang/translations/uz.po +0 -68
- package/lang/translations/vi.po +0 -68
- package/lang/translations/zh-cn.po +0 -68
- package/lang/translations/zh.po +0 -68
- package/src/augmentation.js +0 -5
- package/src/findandreplace.js +0 -90
- package/src/findandreplaceconfig.js +0 -5
- package/src/findandreplaceediting.js +0 -247
- package/src/findandreplacestate.js +0 -93
- package/src/findandreplaceui.js +0 -277
- package/src/findandreplaceutils.js +0 -160
- package/src/findcommand.js +0 -83
- package/src/findnextcommand.js +0 -51
- package/src/findpreviouscommand.js +0 -25
- package/src/index.js +0 -20
- package/src/replaceallcommand.js +0 -50
- package/src/replacecommand.js +0 -43
- package/src/replacecommandbase.js +0 -60
- package/src/ui/findandreplaceformview.js +0 -542
- package/theme/findandreplace.css +0 -13
- package/theme/findandreplaceform.css +0 -17
- /package/{src → dist}/augmentation.d.ts +0 -0
- /package/{src → dist}/findandreplaceconfig.d.ts +0 -0
- /package/{src → dist}/findpreviouscommand.d.ts +0 -0
- /package/{src → dist}/index.d.ts +0 -0
- /package/{src → dist}/replacecommand.d.ts +0 -0
package/src/replacecommand.js
DELETED
|
@@ -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
|
-
import { sortSearchResultsByMarkerPositions } from './findandreplacestate.js';
|
|
6
|
-
import { FindReplaceCommandBase } from './replacecommandbase.js';
|
|
7
|
-
/**
|
|
8
|
-
* The replace command. It is used by the {@link module:find-and-replace/findandreplace~FindAndReplace find and replace feature}.
|
|
9
|
-
*/
|
|
10
|
-
export class ReplaceCommand extends FindReplaceCommandBase {
|
|
11
|
-
/**
|
|
12
|
-
* Replace a given find result by a string or a callback.
|
|
13
|
-
*
|
|
14
|
-
* @param result A single result from the find command.
|
|
15
|
-
*
|
|
16
|
-
* @fires execute
|
|
17
|
-
*/
|
|
18
|
-
execute(replacementText, result) {
|
|
19
|
-
// We save highlight offset here, as the information about the highlighted result will be lost after the changes.
|
|
20
|
-
//
|
|
21
|
-
// It happens because result list is partially regenerated if the result is removed from the paragraph.
|
|
22
|
-
// Partially means that all sibling result items that are placed in the same paragraph are removed and added again,
|
|
23
|
-
// which causes the highlighted result to be malformed (usually it's set to first but it's not guaranteed).
|
|
24
|
-
//
|
|
25
|
-
// While this saving can be done in editing state, it's better to keep it here, as it's a part of the command logic
|
|
26
|
-
// and might be super tricky to implement in multi-root documents.
|
|
27
|
-
//
|
|
28
|
-
// Keep in mind that the highlighted offset is indexed from 1, as it's displayed to the user. It's why we subtract 1 here.
|
|
29
|
-
//
|
|
30
|
-
// More info: https://github.com/ckeditor/ckeditor5/issues/16648
|
|
31
|
-
const oldHighlightOffset = Math.max(this._state.highlightedOffset - 1, 0);
|
|
32
|
-
this._replace(replacementText, result);
|
|
33
|
-
// Let's revert the highlight offset to the previous value.
|
|
34
|
-
if (this._state.results.length) {
|
|
35
|
-
// Highlight offset operates on sorted array, so we need to sort the results first.
|
|
36
|
-
// It's not guaranteed that items in state results are sorted, usually they are, but it's not guaranteed when
|
|
37
|
-
// the result is removed from the paragraph with other highlighted results.
|
|
38
|
-
const sortedResults = sortSearchResultsByMarkerPositions(this.editor.model, [...this._state.results]);
|
|
39
|
-
// Just make sure that we don't overflow the results array, so use modulo.
|
|
40
|
-
this._state.highlightedResult = sortedResults[oldHighlightOffset % sortedResults.length];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,60 +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 find-and-replace/replacecommandbase
|
|
7
|
-
*/
|
|
8
|
-
import { Command } from 'ckeditor5/src/core.js';
|
|
9
|
-
export class FindReplaceCommandBase extends Command {
|
|
10
|
-
/**
|
|
11
|
-
* The find and replace state object used for command operations.
|
|
12
|
-
*/
|
|
13
|
-
_state;
|
|
14
|
-
/**
|
|
15
|
-
* Creates a new `ReplaceCommand` instance.
|
|
16
|
-
*
|
|
17
|
-
* @param editor Editor on which this command will be used.
|
|
18
|
-
* @param state An object to hold plugin state.
|
|
19
|
-
*/
|
|
20
|
-
constructor(editor, state) {
|
|
21
|
-
super(editor);
|
|
22
|
-
// The replace command is always enabled.
|
|
23
|
-
this.isEnabled = true;
|
|
24
|
-
this._state = state;
|
|
25
|
-
// Since this command executes on particular result independent of selection, it should be checked directly in execute block.
|
|
26
|
-
this._isEnabledBasedOnSelection = false;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Common logic for both `replace` commands.
|
|
30
|
-
* Replace a given find result by a string or a callback.
|
|
31
|
-
*
|
|
32
|
-
* @param result A single result from the find command.
|
|
33
|
-
*/
|
|
34
|
-
_replace(replacementText, result) {
|
|
35
|
-
const { model } = this.editor;
|
|
36
|
-
const range = result.marker.getRange();
|
|
37
|
-
// Don't replace a result that is in non-editable place.
|
|
38
|
-
if (!model.canEditAt(range)) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
model.change(writer => {
|
|
42
|
-
// Don't replace a result (marker) that found its way into the $graveyard (e.g. removed by collaborators).
|
|
43
|
-
if (range.root.rootName === '$graveyard') {
|
|
44
|
-
this._state.results.remove(result);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
let textAttributes = {};
|
|
48
|
-
for (const item of range.getItems()) {
|
|
49
|
-
if (item.is('$text') || item.is('$textProxy')) {
|
|
50
|
-
textAttributes = item.getAttributes();
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
model.insertContent(writer.createText(replacementText, textAttributes), range);
|
|
55
|
-
if (this._state.results.has(result)) {
|
|
56
|
-
this._state.results.remove(result);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
@@ -1,542 +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 find-and-replace/ui/findandreplaceformview
|
|
7
|
-
*/
|
|
8
|
-
import { View, ButtonView, LabeledFieldView, FocusCycler, createLabeledInputText, submitHandler, ViewCollection, SwitchButtonView, CollapsibleView } from 'ckeditor5/src/ui.js';
|
|
9
|
-
import { FocusTracker, KeystrokeHandler, Rect, isVisible } from 'ckeditor5/src/utils.js';
|
|
10
|
-
// See: #8833.
|
|
11
|
-
// eslint-disable-next-line ckeditor5-rules/ckeditor-imports
|
|
12
|
-
import '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';
|
|
13
|
-
import '../../theme/findandreplaceform.css';
|
|
14
|
-
import { IconPreviousArrow } from 'ckeditor5/src/icons.js';
|
|
15
|
-
/**
|
|
16
|
-
* The find and replace form view class.
|
|
17
|
-
*
|
|
18
|
-
* See {@link module:find-and-replace/ui/findandreplaceformview~FindAndReplaceFormView}.
|
|
19
|
-
*/
|
|
20
|
-
export class FindAndReplaceFormView extends View {
|
|
21
|
-
/**
|
|
22
|
-
* A collection of child views.
|
|
23
|
-
*/
|
|
24
|
-
children;
|
|
25
|
-
/**
|
|
26
|
-
* The find in text input view that stores the searched string.
|
|
27
|
-
*
|
|
28
|
-
* @internal
|
|
29
|
-
*/
|
|
30
|
-
_findInputView;
|
|
31
|
-
/**
|
|
32
|
-
* The replace input view.
|
|
33
|
-
*/
|
|
34
|
-
_replaceInputView;
|
|
35
|
-
/**
|
|
36
|
-
* The find button view that initializes the search process.
|
|
37
|
-
*/
|
|
38
|
-
_findButtonView;
|
|
39
|
-
/**
|
|
40
|
-
* The find previous button view.
|
|
41
|
-
*/
|
|
42
|
-
_findPrevButtonView;
|
|
43
|
-
/**
|
|
44
|
-
* The find next button view.
|
|
45
|
-
*/
|
|
46
|
-
_findNextButtonView;
|
|
47
|
-
/**
|
|
48
|
-
* A collapsible view aggregating the advanced search options.
|
|
49
|
-
*/
|
|
50
|
-
_advancedOptionsCollapsibleView;
|
|
51
|
-
/**
|
|
52
|
-
* A switch button view controlling the "Match case" option.
|
|
53
|
-
*/
|
|
54
|
-
_matchCaseSwitchView;
|
|
55
|
-
/**
|
|
56
|
-
* A switch button view controlling the "Whole words only" option.
|
|
57
|
-
*/
|
|
58
|
-
_wholeWordsOnlySwitchView;
|
|
59
|
-
/**
|
|
60
|
-
* The replace button view.
|
|
61
|
-
*/
|
|
62
|
-
_replaceButtonView;
|
|
63
|
-
/**
|
|
64
|
-
* The replace all button view.
|
|
65
|
-
*/
|
|
66
|
-
_replaceAllButtonView;
|
|
67
|
-
/**
|
|
68
|
-
* The `div` aggregating the inputs.
|
|
69
|
-
*/
|
|
70
|
-
_inputsDivView;
|
|
71
|
-
/**
|
|
72
|
-
* The `div` aggregating the action buttons.
|
|
73
|
-
*/
|
|
74
|
-
_actionButtonsDivView;
|
|
75
|
-
/**
|
|
76
|
-
* Tracks information about the DOM focus in the form.
|
|
77
|
-
*/
|
|
78
|
-
_focusTracker;
|
|
79
|
-
/**
|
|
80
|
-
* An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
|
|
81
|
-
*/
|
|
82
|
-
_keystrokes;
|
|
83
|
-
/**
|
|
84
|
-
* A collection of views that can be focused in the form.
|
|
85
|
-
*/
|
|
86
|
-
_focusables;
|
|
87
|
-
/**
|
|
88
|
-
* Helps cycling over {@link #_focusables} in the form.
|
|
89
|
-
*/
|
|
90
|
-
focusCycler;
|
|
91
|
-
/**
|
|
92
|
-
* Creates a view of find and replace form.
|
|
93
|
-
*
|
|
94
|
-
* @param locale The localization services instance.
|
|
95
|
-
*/
|
|
96
|
-
constructor(locale) {
|
|
97
|
-
super(locale);
|
|
98
|
-
const t = locale.t;
|
|
99
|
-
this.children = this.createCollection();
|
|
100
|
-
this.set('matchCount', 0);
|
|
101
|
-
this.set('highlightOffset', 0);
|
|
102
|
-
this.set('isDirty', false);
|
|
103
|
-
this.set('_areCommandsEnabled', {});
|
|
104
|
-
this.set('_resultsCounterText', '');
|
|
105
|
-
this.set('_matchCase', false);
|
|
106
|
-
this.set('_wholeWordsOnly', false);
|
|
107
|
-
this.bind('_searchResultsFound').to(this, 'matchCount', this, 'isDirty', (matchCount, isDirty) => {
|
|
108
|
-
return matchCount > 0 && !isDirty;
|
|
109
|
-
});
|
|
110
|
-
this._findInputView = this._createInputField(t('Find in text…'));
|
|
111
|
-
this._findPrevButtonView = this._createButton({
|
|
112
|
-
label: t('Previous result'),
|
|
113
|
-
class: 'ck-button-prev',
|
|
114
|
-
icon: IconPreviousArrow,
|
|
115
|
-
keystroke: 'Shift+F3',
|
|
116
|
-
tooltip: true
|
|
117
|
-
});
|
|
118
|
-
this._findNextButtonView = this._createButton({
|
|
119
|
-
label: t('Next result'),
|
|
120
|
-
class: 'ck-button-next',
|
|
121
|
-
icon: IconPreviousArrow,
|
|
122
|
-
keystroke: 'F3',
|
|
123
|
-
tooltip: true
|
|
124
|
-
});
|
|
125
|
-
this._replaceInputView = this._createInputField(t('Replace with…'), 'ck-labeled-field-replace');
|
|
126
|
-
this._inputsDivView = this._createInputsDiv();
|
|
127
|
-
this._matchCaseSwitchView = this._createMatchCaseSwitch();
|
|
128
|
-
this._wholeWordsOnlySwitchView = this._createWholeWordsOnlySwitch();
|
|
129
|
-
this._advancedOptionsCollapsibleView = this._createAdvancedOptionsCollapsible();
|
|
130
|
-
this._replaceAllButtonView = this._createButton({
|
|
131
|
-
label: t('Replace all'),
|
|
132
|
-
class: 'ck-button-replaceall',
|
|
133
|
-
withText: true
|
|
134
|
-
});
|
|
135
|
-
this._replaceButtonView = this._createButton({
|
|
136
|
-
label: t('Replace'),
|
|
137
|
-
class: 'ck-button-replace',
|
|
138
|
-
withText: true
|
|
139
|
-
});
|
|
140
|
-
this._findButtonView = this._createButton({
|
|
141
|
-
label: t('Find'),
|
|
142
|
-
class: 'ck-button-find ck-button-action',
|
|
143
|
-
withText: true
|
|
144
|
-
});
|
|
145
|
-
this._actionButtonsDivView = this._createActionButtonsDiv();
|
|
146
|
-
this._focusTracker = new FocusTracker();
|
|
147
|
-
this._keystrokes = new KeystrokeHandler();
|
|
148
|
-
this._focusables = new ViewCollection();
|
|
149
|
-
this.focusCycler = new FocusCycler({
|
|
150
|
-
focusables: this._focusables,
|
|
151
|
-
focusTracker: this._focusTracker,
|
|
152
|
-
keystrokeHandler: this._keystrokes,
|
|
153
|
-
actions: {
|
|
154
|
-
// Navigate form fields backwards using the <kbd>Shift</kbd> + <kbd>Tab</kbd> keystroke.
|
|
155
|
-
focusPrevious: 'shift + tab',
|
|
156
|
-
// Navigate form fields forwards using the <kbd>Tab</kbd> key.
|
|
157
|
-
focusNext: 'tab'
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
this.children.addMany([
|
|
161
|
-
this._inputsDivView,
|
|
162
|
-
this._advancedOptionsCollapsibleView,
|
|
163
|
-
this._actionButtonsDivView
|
|
164
|
-
]);
|
|
165
|
-
this.setTemplate({
|
|
166
|
-
tag: 'form',
|
|
167
|
-
attributes: {
|
|
168
|
-
class: [
|
|
169
|
-
'ck',
|
|
170
|
-
'ck-find-and-replace-form'
|
|
171
|
-
],
|
|
172
|
-
tabindex: '-1'
|
|
173
|
-
},
|
|
174
|
-
children: this.children
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* @inheritDoc
|
|
179
|
-
*/
|
|
180
|
-
render() {
|
|
181
|
-
super.render();
|
|
182
|
-
submitHandler({ view: this });
|
|
183
|
-
this._initFocusCycling();
|
|
184
|
-
this._initKeystrokeHandling();
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* @inheritDoc
|
|
188
|
-
*/
|
|
189
|
-
destroy() {
|
|
190
|
-
super.destroy();
|
|
191
|
-
this._focusTracker.destroy();
|
|
192
|
-
this._keystrokes.destroy();
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* @inheritDoc
|
|
196
|
-
*/
|
|
197
|
-
focus(direction) {
|
|
198
|
-
if (direction === -1) {
|
|
199
|
-
this.focusCycler.focusLast();
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
this.focusCycler.focusFirst();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Resets the form before re-appearing.
|
|
207
|
-
*
|
|
208
|
-
* It clears error messages, hides the match counter and disables the replace feature
|
|
209
|
-
* until the next hit of the "Find" button.
|
|
210
|
-
*
|
|
211
|
-
* **Note**: It does not reset inputs and options, though. This way the form works better in editors with
|
|
212
|
-
* disappearing toolbar (e.g. BalloonEditor): hiding the toolbar by accident (together with the find and replace UI)
|
|
213
|
-
* does not require filling the entire form again.
|
|
214
|
-
*/
|
|
215
|
-
reset() {
|
|
216
|
-
this._findInputView.errorText = null;
|
|
217
|
-
this.isDirty = true;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Returns the value of the find input.
|
|
221
|
-
*/
|
|
222
|
-
get _textToFind() {
|
|
223
|
-
return this._findInputView.fieldView.element.value;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Returns the value of the replace input.
|
|
227
|
-
*/
|
|
228
|
-
get _textToReplace() {
|
|
229
|
-
return this._replaceInputView.fieldView.element.value;
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Configures and returns the `<div>` aggregating all form inputs.
|
|
233
|
-
*/
|
|
234
|
-
_createInputsDiv() {
|
|
235
|
-
const locale = this.locale;
|
|
236
|
-
const t = locale.t;
|
|
237
|
-
const inputsDivView = new View(locale);
|
|
238
|
-
// Typing in the find field invalidates all previous results (the form is "dirty").
|
|
239
|
-
this._findInputView.fieldView.on('input', () => {
|
|
240
|
-
this.isDirty = true;
|
|
241
|
-
});
|
|
242
|
-
// Pressing prev/next buttons fires related event on the form.
|
|
243
|
-
this._findPrevButtonView.delegate('execute').to(this, 'findPrevious');
|
|
244
|
-
this._findNextButtonView.delegate('execute').to(this, 'findNext');
|
|
245
|
-
// Prev/next buttons will be disabled when related editor command gets disabled.
|
|
246
|
-
this._findPrevButtonView.bind('isEnabled').to(this, '_areCommandsEnabled', ({ findPrevious }) => findPrevious);
|
|
247
|
-
this._findNextButtonView.bind('isEnabled').to(this, '_areCommandsEnabled', ({ findNext }) => findNext);
|
|
248
|
-
this._injectFindResultsCounter();
|
|
249
|
-
this._replaceInputView.bind('isEnabled').to(this, '_areCommandsEnabled', this, '_searchResultsFound', ({ replace }, resultsFound) => replace && resultsFound);
|
|
250
|
-
this._replaceInputView.bind('infoText').to(this._replaceInputView, 'isEnabled', this._replaceInputView, 'isFocused', (isEnabled, isFocused) => {
|
|
251
|
-
if (isEnabled || !isFocused) {
|
|
252
|
-
return '';
|
|
253
|
-
}
|
|
254
|
-
return t('Tip: Find some text first in order to replace it.');
|
|
255
|
-
});
|
|
256
|
-
inputsDivView.setTemplate({
|
|
257
|
-
tag: 'div',
|
|
258
|
-
attributes: {
|
|
259
|
-
class: ['ck', 'ck-find-and-replace-form__inputs']
|
|
260
|
-
},
|
|
261
|
-
children: [
|
|
262
|
-
this._findInputView,
|
|
263
|
-
this._findPrevButtonView,
|
|
264
|
-
this._findNextButtonView,
|
|
265
|
-
this._replaceInputView
|
|
266
|
-
]
|
|
267
|
-
});
|
|
268
|
-
return inputsDivView;
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* The action performed when the {@link #_findButtonView} is pressed.
|
|
272
|
-
*/
|
|
273
|
-
_onFindButtonExecute() {
|
|
274
|
-
// When hitting "Find" in an empty input, an error should be displayed.
|
|
275
|
-
// Also, if the form was "dirty", it should remain so.
|
|
276
|
-
if (!this._textToFind) {
|
|
277
|
-
const t = this.t;
|
|
278
|
-
this._findInputView.errorText = t('Text to find must not be empty.');
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
// Hitting "Find" automatically clears the dirty state.
|
|
282
|
-
this.isDirty = false;
|
|
283
|
-
this.fire('findNext', {
|
|
284
|
-
searchText: this._textToFind,
|
|
285
|
-
matchCase: this._matchCase,
|
|
286
|
-
wholeWords: this._wholeWordsOnly
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Configures an injects the find results counter displaying a "N of M" label of the {@link #_findInputView}.
|
|
291
|
-
*/
|
|
292
|
-
_injectFindResultsCounter() {
|
|
293
|
-
const locale = this.locale;
|
|
294
|
-
const t = locale.t;
|
|
295
|
-
const bind = this.bindTemplate;
|
|
296
|
-
const resultsCounterView = new View(this.locale);
|
|
297
|
-
this.bind('_resultsCounterText').to(this, 'highlightOffset', this, 'matchCount', (highlightOffset, matchCount) => t('%0 of %1', [highlightOffset, matchCount]));
|
|
298
|
-
resultsCounterView.setTemplate({
|
|
299
|
-
tag: 'span',
|
|
300
|
-
attributes: {
|
|
301
|
-
class: [
|
|
302
|
-
'ck',
|
|
303
|
-
'ck-results-counter',
|
|
304
|
-
// The counter only makes sense when the field text corresponds to search results in the editing.
|
|
305
|
-
bind.if('isDirty', 'ck-hidden')
|
|
306
|
-
]
|
|
307
|
-
},
|
|
308
|
-
children: [
|
|
309
|
-
{
|
|
310
|
-
text: bind.to('_resultsCounterText')
|
|
311
|
-
}
|
|
312
|
-
]
|
|
313
|
-
});
|
|
314
|
-
// The whole idea is that when the text of the counter changes, its width also increases/decreases and
|
|
315
|
-
// it consumes more or less space over the input. The input, on the other hand, should adjust it's right
|
|
316
|
-
// padding so its *entire* text always remains visible and available to the user.
|
|
317
|
-
const updateFindInputPadding = () => {
|
|
318
|
-
const inputElement = this._findInputView.fieldView.element;
|
|
319
|
-
// Don't adjust the padding if the input (also: counter) were not rendered or not inserted into DOM yet.
|
|
320
|
-
if (!inputElement || !isVisible(inputElement)) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
const counterWidth = new Rect(resultsCounterView.element).width;
|
|
324
|
-
const paddingPropertyName = locale.uiLanguageDirection === 'ltr' ? 'paddingRight' : 'paddingLeft';
|
|
325
|
-
if (!counterWidth) {
|
|
326
|
-
inputElement.style[paddingPropertyName] = '';
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
inputElement.style[paddingPropertyName] = `calc( 2 * var(--ck-spacing-standard) + ${counterWidth}px )`;
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
// Adjust the input padding when the text of the counter changes, for instance "1 of 200" is narrower than "123 of 200".
|
|
333
|
-
// Using "low" priority to let the text be set by the template binding first.
|
|
334
|
-
this.on('change:_resultsCounterText', updateFindInputPadding, { priority: 'low' });
|
|
335
|
-
// Adjust the input padding when the counter shows or hides. When hidden, there should be no padding. When it shows, the
|
|
336
|
-
// padding should be set according to the text of the counter.
|
|
337
|
-
// Using "low" priority to let the text be set by the template binding first.
|
|
338
|
-
this.on('change:isDirty', updateFindInputPadding, { priority: 'low' });
|
|
339
|
-
// Put the counter element next to the <input> in the find field.
|
|
340
|
-
this._findInputView.template.children[0].children.push(resultsCounterView);
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Creates the collapsible view aggregating the advanced search options.
|
|
344
|
-
*/
|
|
345
|
-
_createAdvancedOptionsCollapsible() {
|
|
346
|
-
const t = this.locale.t;
|
|
347
|
-
const collapsible = new CollapsibleView(this.locale, [
|
|
348
|
-
this._matchCaseSwitchView,
|
|
349
|
-
this._wholeWordsOnlySwitchView
|
|
350
|
-
]);
|
|
351
|
-
collapsible.set({
|
|
352
|
-
label: t('Advanced options'),
|
|
353
|
-
isCollapsed: true
|
|
354
|
-
});
|
|
355
|
-
return collapsible;
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Configures and returns the `<div>` element aggregating all form action buttons.
|
|
359
|
-
*/
|
|
360
|
-
_createActionButtonsDiv() {
|
|
361
|
-
const actionsDivView = new View(this.locale);
|
|
362
|
-
this._replaceButtonView.bind('isEnabled').to(this, '_areCommandsEnabled', this, '_searchResultsFound', ({ replace }, resultsFound) => replace && resultsFound);
|
|
363
|
-
this._replaceAllButtonView.bind('isEnabled').to(this, '_areCommandsEnabled', this, '_searchResultsFound', ({ replaceAll }, resultsFound) => replaceAll && resultsFound);
|
|
364
|
-
this._replaceButtonView.on('execute', () => {
|
|
365
|
-
this.fire('replace', {
|
|
366
|
-
searchText: this._textToFind,
|
|
367
|
-
replaceText: this._textToReplace
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
this._replaceAllButtonView.on('execute', () => {
|
|
371
|
-
this.fire('replaceAll', {
|
|
372
|
-
searchText: this._textToFind,
|
|
373
|
-
replaceText: this._textToReplace
|
|
374
|
-
});
|
|
375
|
-
this.focus();
|
|
376
|
-
});
|
|
377
|
-
this._findButtonView.on('execute', this._onFindButtonExecute.bind(this));
|
|
378
|
-
actionsDivView.setTemplate({
|
|
379
|
-
tag: 'div',
|
|
380
|
-
attributes: {
|
|
381
|
-
class: ['ck', 'ck-find-and-replace-form__actions']
|
|
382
|
-
},
|
|
383
|
-
children: [
|
|
384
|
-
this._replaceAllButtonView,
|
|
385
|
-
this._replaceButtonView,
|
|
386
|
-
this._findButtonView
|
|
387
|
-
]
|
|
388
|
-
});
|
|
389
|
-
return actionsDivView;
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Creates, configures and returns and instance of a dropdown allowing users to narrow
|
|
393
|
-
* the search criteria down. The dropdown has a list with switch buttons for each option.
|
|
394
|
-
*/
|
|
395
|
-
_createMatchCaseSwitch() {
|
|
396
|
-
const t = this.locale.t;
|
|
397
|
-
const matchCaseSwitchButton = new SwitchButtonView(this.locale);
|
|
398
|
-
matchCaseSwitchButton.set({
|
|
399
|
-
label: t('Match case'),
|
|
400
|
-
withText: true
|
|
401
|
-
});
|
|
402
|
-
// Let the switch be controlled by form's observable property.
|
|
403
|
-
matchCaseSwitchButton.bind('isOn').to(this, '_matchCase');
|
|
404
|
-
// // Update the state of the form when a switch is toggled.
|
|
405
|
-
matchCaseSwitchButton.on('execute', () => {
|
|
406
|
-
this._matchCase = !this._matchCase;
|
|
407
|
-
// Toggling a switch makes the form dirty because this changes search criteria
|
|
408
|
-
// just like typing text of the find input.
|
|
409
|
-
this.isDirty = true;
|
|
410
|
-
});
|
|
411
|
-
return matchCaseSwitchButton;
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Creates, configures and returns and instance of a dropdown allowing users to narrow
|
|
415
|
-
* the search criteria down. The dropdown has a list with switch buttons for each option.
|
|
416
|
-
*/
|
|
417
|
-
_createWholeWordsOnlySwitch() {
|
|
418
|
-
const t = this.locale.t;
|
|
419
|
-
const wholeWordsOnlySwitchButton = new SwitchButtonView(this.locale);
|
|
420
|
-
wholeWordsOnlySwitchButton.set({
|
|
421
|
-
label: t('Whole words only'),
|
|
422
|
-
withText: true
|
|
423
|
-
});
|
|
424
|
-
// Let the switch be controlled by form's observable property.
|
|
425
|
-
wholeWordsOnlySwitchButton.bind('isOn').to(this, '_wholeWordsOnly');
|
|
426
|
-
// // Update the state of the form when a switch is toggled.
|
|
427
|
-
wholeWordsOnlySwitchButton.on('execute', () => {
|
|
428
|
-
this._wholeWordsOnly = !this._wholeWordsOnly;
|
|
429
|
-
// Toggling a switch makes the form dirty because this changes search criteria
|
|
430
|
-
// just like typing text of the find input.
|
|
431
|
-
this.isDirty = true;
|
|
432
|
-
});
|
|
433
|
-
return wholeWordsOnlySwitchButton;
|
|
434
|
-
}
|
|
435
|
-
/**
|
|
436
|
-
* Initializes the {@link #_focusables} and {@link #_focusTracker} to allow navigation
|
|
437
|
-
* using <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> keystrokes in the right order.
|
|
438
|
-
*/
|
|
439
|
-
_initFocusCycling() {
|
|
440
|
-
const childViews = [
|
|
441
|
-
this._findInputView,
|
|
442
|
-
this._findPrevButtonView,
|
|
443
|
-
this._findNextButtonView,
|
|
444
|
-
this._replaceInputView,
|
|
445
|
-
this._advancedOptionsCollapsibleView.buttonView,
|
|
446
|
-
this._matchCaseSwitchView,
|
|
447
|
-
this._wholeWordsOnlySwitchView,
|
|
448
|
-
this._replaceAllButtonView,
|
|
449
|
-
this._replaceButtonView,
|
|
450
|
-
this._findButtonView
|
|
451
|
-
];
|
|
452
|
-
childViews.forEach(v => {
|
|
453
|
-
// Register the view as focusable.
|
|
454
|
-
this._focusables.add(v);
|
|
455
|
-
// Register the view in the focus tracker.
|
|
456
|
-
this._focusTracker.add(v.element);
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* Initializes the keystroke handling in the form.
|
|
461
|
-
*/
|
|
462
|
-
_initKeystrokeHandling() {
|
|
463
|
-
const stopPropagation = (data) => data.stopPropagation();
|
|
464
|
-
const stopPropagationAndPreventDefault = (data) => {
|
|
465
|
-
data.stopPropagation();
|
|
466
|
-
data.preventDefault();
|
|
467
|
-
};
|
|
468
|
-
// Start listening for the keystrokes coming from #element.
|
|
469
|
-
this._keystrokes.listenTo(this.element);
|
|
470
|
-
// Find the next result upon F3.
|
|
471
|
-
this._keystrokes.set('f3', event => {
|
|
472
|
-
stopPropagationAndPreventDefault(event);
|
|
473
|
-
this._findNextButtonView.fire('execute');
|
|
474
|
-
});
|
|
475
|
-
// Find the previous result upon F3.
|
|
476
|
-
this._keystrokes.set('shift+f3', event => {
|
|
477
|
-
stopPropagationAndPreventDefault(event);
|
|
478
|
-
this._findPrevButtonView.fire('execute');
|
|
479
|
-
});
|
|
480
|
-
// Find or replace upon pressing Enter in the find and replace fields.
|
|
481
|
-
this._keystrokes.set('enter', event => {
|
|
482
|
-
const target = event.target;
|
|
483
|
-
if (target === this._findInputView.fieldView.element) {
|
|
484
|
-
if (this._areCommandsEnabled.findNext) {
|
|
485
|
-
this._findNextButtonView.fire('execute');
|
|
486
|
-
}
|
|
487
|
-
else {
|
|
488
|
-
this._findButtonView.fire('execute');
|
|
489
|
-
}
|
|
490
|
-
stopPropagationAndPreventDefault(event);
|
|
491
|
-
}
|
|
492
|
-
else if (target === this._replaceInputView.fieldView.element && !this.isDirty) {
|
|
493
|
-
this._replaceButtonView.fire('execute');
|
|
494
|
-
stopPropagationAndPreventDefault(event);
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
// Find previous upon pressing Shift+Enter in the find field.
|
|
498
|
-
this._keystrokes.set('shift+enter', event => {
|
|
499
|
-
const target = event.target;
|
|
500
|
-
if (target !== this._findInputView.fieldView.element) {
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
if (this._areCommandsEnabled.findPrevious) {
|
|
504
|
-
this._findPrevButtonView.fire('execute');
|
|
505
|
-
}
|
|
506
|
-
else {
|
|
507
|
-
this._findButtonView.fire('execute');
|
|
508
|
-
}
|
|
509
|
-
stopPropagationAndPreventDefault(event);
|
|
510
|
-
});
|
|
511
|
-
// Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's
|
|
512
|
-
// keystroke handler would take over the key management in the URL input.
|
|
513
|
-
// We need to prevent this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.
|
|
514
|
-
this._keystrokes.set('arrowright', stopPropagation);
|
|
515
|
-
this._keystrokes.set('arrowleft', stopPropagation);
|
|
516
|
-
this._keystrokes.set('arrowup', stopPropagation);
|
|
517
|
-
this._keystrokes.set('arrowdown', stopPropagation);
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Creates a button view.
|
|
521
|
-
*
|
|
522
|
-
* @param options The properties of the `ButtonView`.
|
|
523
|
-
* @returns The button view instance.
|
|
524
|
-
*/
|
|
525
|
-
_createButton(options) {
|
|
526
|
-
const button = new ButtonView(this.locale);
|
|
527
|
-
button.set(options);
|
|
528
|
-
return button;
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Creates a labeled input view.
|
|
532
|
-
*
|
|
533
|
-
* @param label The input label.
|
|
534
|
-
* @returns The labeled input view instance.
|
|
535
|
-
*/
|
|
536
|
-
_createInputField(label, className) {
|
|
537
|
-
const labeledInput = new LabeledFieldView(this.locale, createLabeledInputText);
|
|
538
|
-
labeledInput.label = label;
|
|
539
|
-
labeledInput.class = className;
|
|
540
|
-
return labeledInput;
|
|
541
|
-
}
|
|
542
|
-
}
|
package/theme/findandreplace.css
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 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
|
-
.ck-find-result {
|
|
7
|
-
background: var(--ck-color-highlight-background);
|
|
8
|
-
color: var(--ck-color-text);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.ck-find-result_selected {
|
|
12
|
-
background: hsl(29, 100%, 60%);
|
|
13
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 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
|
-
.ck.ck-find-and-replace-form {
|
|
7
|
-
max-width: 100%;
|
|
8
|
-
|
|
9
|
-
& .ck-find-and-replace-form__inputs, .ck-find-and-replace-form__actions {
|
|
10
|
-
display: flex;
|
|
11
|
-
|
|
12
|
-
/* The inputs area styles */
|
|
13
|
-
&.ck-find-and-replace-form__inputs .ck-results-counter {
|
|
14
|
-
position: absolute;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{src → dist}/index.d.ts
RENAMED
|
File without changes
|
|
File without changes
|