@ckeditor/ckeditor5-find-and-replace 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.
Files changed (186) hide show
  1. package/LICENSE.md +1 -1
  2. package/ckeditor5-metadata.json +2 -2
  3. package/{src → dist}/findandreplace.d.ts +2 -2
  4. package/{src → dist}/findandreplaceediting.d.ts +2 -2
  5. package/{src → dist}/findandreplacestate.d.ts +4 -4
  6. package/{src → dist}/findandreplaceui.d.ts +2 -2
  7. package/{src → dist}/findandreplaceutils.d.ts +3 -3
  8. package/{src → dist}/findcommand.d.ts +2 -2
  9. package/{src → dist}/findnextcommand.d.ts +1 -1
  10. package/dist/index-editor.css +165 -40
  11. package/dist/index.css +162 -59
  12. package/dist/index.css.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/{src → dist}/replaceallcommand.d.ts +1 -1
  15. package/{src → dist}/replacecommandbase.d.ts +1 -1
  16. package/{src → dist}/ui/findandreplaceformview.d.ts +2 -3
  17. package/package.json +24 -47
  18. package/build/find-and-replace.js +0 -5
  19. package/build/translations/af.js +0 -1
  20. package/build/translations/ar.js +0 -1
  21. package/build/translations/ast.js +0 -1
  22. package/build/translations/az.js +0 -1
  23. package/build/translations/be.js +0 -1
  24. package/build/translations/bg.js +0 -1
  25. package/build/translations/bn.js +0 -1
  26. package/build/translations/bs.js +0 -1
  27. package/build/translations/ca.js +0 -1
  28. package/build/translations/cs.js +0 -1
  29. package/build/translations/da.js +0 -1
  30. package/build/translations/de-ch.js +0 -1
  31. package/build/translations/de.js +0 -1
  32. package/build/translations/el.js +0 -1
  33. package/build/translations/en-au.js +0 -1
  34. package/build/translations/en-gb.js +0 -1
  35. package/build/translations/eo.js +0 -1
  36. package/build/translations/es-co.js +0 -1
  37. package/build/translations/es.js +0 -1
  38. package/build/translations/et.js +0 -1
  39. package/build/translations/eu.js +0 -1
  40. package/build/translations/fa.js +0 -1
  41. package/build/translations/fi.js +0 -1
  42. package/build/translations/fr.js +0 -1
  43. package/build/translations/gl.js +0 -1
  44. package/build/translations/gu.js +0 -1
  45. package/build/translations/he.js +0 -1
  46. package/build/translations/hi.js +0 -1
  47. package/build/translations/hr.js +0 -1
  48. package/build/translations/hu.js +0 -1
  49. package/build/translations/hy.js +0 -1
  50. package/build/translations/id.js +0 -1
  51. package/build/translations/it.js +0 -1
  52. package/build/translations/ja.js +0 -1
  53. package/build/translations/jv.js +0 -1
  54. package/build/translations/kk.js +0 -1
  55. package/build/translations/km.js +0 -1
  56. package/build/translations/kn.js +0 -1
  57. package/build/translations/ko.js +0 -1
  58. package/build/translations/ku.js +0 -1
  59. package/build/translations/lt.js +0 -1
  60. package/build/translations/lv.js +0 -1
  61. package/build/translations/ms.js +0 -1
  62. package/build/translations/nb.js +0 -1
  63. package/build/translations/ne.js +0 -1
  64. package/build/translations/nl.js +0 -1
  65. package/build/translations/no.js +0 -1
  66. package/build/translations/oc.js +0 -1
  67. package/build/translations/pl.js +0 -1
  68. package/build/translations/pt-br.js +0 -1
  69. package/build/translations/pt.js +0 -1
  70. package/build/translations/ro.js +0 -1
  71. package/build/translations/ru.js +0 -1
  72. package/build/translations/si.js +0 -1
  73. package/build/translations/sk.js +0 -1
  74. package/build/translations/sl.js +0 -1
  75. package/build/translations/sq.js +0 -1
  76. package/build/translations/sr-latn.js +0 -1
  77. package/build/translations/sr.js +0 -1
  78. package/build/translations/sv.js +0 -1
  79. package/build/translations/th.js +0 -1
  80. package/build/translations/ti.js +0 -1
  81. package/build/translations/tk.js +0 -1
  82. package/build/translations/tr.js +0 -1
  83. package/build/translations/tt.js +0 -1
  84. package/build/translations/ug.js +0 -1
  85. package/build/translations/uk.js +0 -1
  86. package/build/translations/ur.js +0 -1
  87. package/build/translations/uz.js +0 -1
  88. package/build/translations/vi.js +0 -1
  89. package/build/translations/zh-cn.js +0 -1
  90. package/build/translations/zh.js +0 -1
  91. package/lang/contexts.json +0 -16
  92. package/lang/translations/af.po +0 -68
  93. package/lang/translations/ar.po +0 -68
  94. package/lang/translations/ast.po +0 -68
  95. package/lang/translations/az.po +0 -68
  96. package/lang/translations/be.po +0 -68
  97. package/lang/translations/bg.po +0 -68
  98. package/lang/translations/bn.po +0 -68
  99. package/lang/translations/bs.po +0 -68
  100. package/lang/translations/ca.po +0 -68
  101. package/lang/translations/cs.po +0 -68
  102. package/lang/translations/da.po +0 -68
  103. package/lang/translations/de-ch.po +0 -68
  104. package/lang/translations/de.po +0 -68
  105. package/lang/translations/el.po +0 -68
  106. package/lang/translations/en-au.po +0 -68
  107. package/lang/translations/en-gb.po +0 -68
  108. package/lang/translations/en.po +0 -68
  109. package/lang/translations/eo.po +0 -68
  110. package/lang/translations/es-co.po +0 -68
  111. package/lang/translations/es.po +0 -68
  112. package/lang/translations/et.po +0 -68
  113. package/lang/translations/eu.po +0 -68
  114. package/lang/translations/fa.po +0 -68
  115. package/lang/translations/fi.po +0 -68
  116. package/lang/translations/fr.po +0 -68
  117. package/lang/translations/gl.po +0 -68
  118. package/lang/translations/gu.po +0 -68
  119. package/lang/translations/he.po +0 -68
  120. package/lang/translations/hi.po +0 -68
  121. package/lang/translations/hr.po +0 -68
  122. package/lang/translations/hu.po +0 -68
  123. package/lang/translations/hy.po +0 -68
  124. package/lang/translations/id.po +0 -68
  125. package/lang/translations/it.po +0 -68
  126. package/lang/translations/ja.po +0 -68
  127. package/lang/translations/jv.po +0 -68
  128. package/lang/translations/kk.po +0 -68
  129. package/lang/translations/km.po +0 -68
  130. package/lang/translations/kn.po +0 -68
  131. package/lang/translations/ko.po +0 -68
  132. package/lang/translations/ku.po +0 -68
  133. package/lang/translations/lt.po +0 -68
  134. package/lang/translations/lv.po +0 -68
  135. package/lang/translations/ms.po +0 -68
  136. package/lang/translations/nb.po +0 -68
  137. package/lang/translations/ne.po +0 -68
  138. package/lang/translations/nl.po +0 -68
  139. package/lang/translations/no.po +0 -68
  140. package/lang/translations/oc.po +0 -68
  141. package/lang/translations/pl.po +0 -68
  142. package/lang/translations/pt-br.po +0 -68
  143. package/lang/translations/pt.po +0 -68
  144. package/lang/translations/ro.po +0 -68
  145. package/lang/translations/ru.po +0 -68
  146. package/lang/translations/si.po +0 -68
  147. package/lang/translations/sk.po +0 -68
  148. package/lang/translations/sl.po +0 -68
  149. package/lang/translations/sq.po +0 -68
  150. package/lang/translations/sr-latn.po +0 -68
  151. package/lang/translations/sr.po +0 -68
  152. package/lang/translations/sv.po +0 -68
  153. package/lang/translations/th.po +0 -68
  154. package/lang/translations/ti.po +0 -68
  155. package/lang/translations/tk.po +0 -68
  156. package/lang/translations/tr.po +0 -68
  157. package/lang/translations/tt.po +0 -68
  158. package/lang/translations/ug.po +0 -68
  159. package/lang/translations/uk.po +0 -68
  160. package/lang/translations/ur.po +0 -68
  161. package/lang/translations/uz.po +0 -68
  162. package/lang/translations/vi.po +0 -68
  163. package/lang/translations/zh-cn.po +0 -68
  164. package/lang/translations/zh.po +0 -68
  165. package/src/augmentation.js +0 -5
  166. package/src/findandreplace.js +0 -90
  167. package/src/findandreplaceconfig.js +0 -5
  168. package/src/findandreplaceediting.js +0 -247
  169. package/src/findandreplacestate.js +0 -93
  170. package/src/findandreplaceui.js +0 -277
  171. package/src/findandreplaceutils.js +0 -160
  172. package/src/findcommand.js +0 -83
  173. package/src/findnextcommand.js +0 -51
  174. package/src/findpreviouscommand.js +0 -25
  175. package/src/index.js +0 -20
  176. package/src/replaceallcommand.js +0 -50
  177. package/src/replacecommand.js +0 -43
  178. package/src/replacecommandbase.js +0 -60
  179. package/src/ui/findandreplaceformview.js +0 -542
  180. package/theme/findandreplace.css +0 -13
  181. package/theme/findandreplaceform.css +0 -17
  182. /package/{src → dist}/augmentation.d.ts +0 -0
  183. /package/{src → dist}/findandreplaceconfig.d.ts +0 -0
  184. /package/{src → dist}/findpreviouscommand.d.ts +0 -0
  185. /package/{src → dist}/index.d.ts +0 -0
  186. /package/{src → dist}/replacecommand.d.ts +0 -0
@@ -1,277 +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/findandreplaceui
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { IconFindReplace } from 'ckeditor5/src/icons.js';
10
- import { ButtonView, MenuBarMenuListItemButtonView, Dialog, DialogViewPosition, createDropdown, DropdownView, FormHeaderView, CssTransitionDisablerMixin } from 'ckeditor5/src/ui.js';
11
- import { FindAndReplaceFormView } from './ui/findandreplaceformview.js';
12
- /**
13
- * The default find and replace UI.
14
- *
15
- * It registers the `'findAndReplace'` UI button in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}.
16
- * that uses the {@link module:find-and-replace/findandreplace~FindAndReplace FindAndReplace} plugin API.
17
- */
18
- export class FindAndReplaceUI extends Plugin {
19
- /**
20
- * @inheritDoc
21
- */
22
- static get requires() {
23
- return [Dialog];
24
- }
25
- /**
26
- * @inheritDoc
27
- */
28
- static get pluginName() {
29
- return 'FindAndReplaceUI';
30
- }
31
- /**
32
- * @inheritDoc
33
- */
34
- static get isOfficialPlugin() {
35
- return true;
36
- }
37
- /**
38
- * A reference to the find and replace form view.
39
- */
40
- formView;
41
- /**
42
- * @inheritDoc
43
- */
44
- constructor(editor) {
45
- super(editor);
46
- editor.config.define('findAndReplace.uiType', 'dialog');
47
- this.formView = null;
48
- }
49
- /**
50
- * @inheritDoc
51
- */
52
- init() {
53
- const editor = this.editor;
54
- const isUiUsingDropdown = editor.config.get('findAndReplace.uiType') === 'dropdown';
55
- const findCommand = editor.commands.get('find');
56
- const t = this.editor.t;
57
- // Register the toolbar component: dropdown or button (that opens a dialog).
58
- editor.ui.componentFactory.add('findAndReplace', () => {
59
- let view;
60
- if (isUiUsingDropdown) {
61
- view = this._createDropdown();
62
- // Button should be disabled when in source editing mode. See #10001.
63
- view.bind('isEnabled').to(findCommand);
64
- }
65
- else {
66
- view = this._createDialogButtonForToolbar();
67
- }
68
- editor.keystrokes.set('Ctrl+F', (data, cancelEvent) => {
69
- if (!findCommand.isEnabled) {
70
- return;
71
- }
72
- if (view instanceof DropdownView) {
73
- const dropdownButtonView = view.buttonView;
74
- if (!dropdownButtonView.isOn) {
75
- dropdownButtonView.fire('execute');
76
- }
77
- }
78
- else {
79
- if (view.isOn) {
80
- // If the dialog is open, do not close it. Instead focus it.
81
- // Unfortunately we can't simply use:
82
- // this.formView!.focus();
83
- // because it would always move focus to the first input field, which we don't want.
84
- editor.plugins.get('Dialog').view.focus();
85
- }
86
- else {
87
- view.fire('execute');
88
- }
89
- }
90
- cancelEvent();
91
- });
92
- return view;
93
- });
94
- if (!isUiUsingDropdown) {
95
- editor.ui.componentFactory.add('menuBar:findAndReplace', () => {
96
- return this._createDialogButtonForMenuBar();
97
- });
98
- }
99
- // Add the information about the keystroke to the accessibility database.
100
- editor.accessibility.addKeystrokeInfos({
101
- keystrokes: [
102
- {
103
- label: t('Find in the document'),
104
- keystroke: 'CTRL+F'
105
- }
106
- ]
107
- });
108
- }
109
- /**
110
- * Creates a dropdown containing the find and replace form.
111
- */
112
- _createDropdown() {
113
- const editor = this.editor;
114
- const t = editor.locale.t;
115
- const dropdownView = createDropdown(editor.locale);
116
- dropdownView.once('change:isOpen', () => {
117
- this.formView = this._createFormView();
118
- this.formView.children.add(new FormHeaderView(editor.locale, {
119
- label: t('Find and replace')
120
- }), 0);
121
- dropdownView.panelView.children.add(this.formView);
122
- });
123
- // Every time a dropdown is opened, the search text field should get focused and selected for better UX.
124
- // Note: Using the low priority here to make sure the following listener starts working after
125
- // the default action of the drop-down is executed (i.e. the panel showed up). Otherwise,
126
- // the invisible form/input cannot be focused/selected.
127
- //
128
- // Each time a dropdown is closed, move the focus back to the find and replace toolbar button
129
- // and let the find and replace editing feature know that all search results can be invalidated
130
- // and no longer should be marked in the content.
131
- dropdownView.on('change:isOpen', (event, name, isOpen) => {
132
- if (isOpen) {
133
- this._setupFormView();
134
- }
135
- else {
136
- this.fire('searchReseted');
137
- }
138
- }, { priority: 'low' });
139
- dropdownView.buttonView.set({
140
- icon: IconFindReplace,
141
- label: t('Find and replace'),
142
- keystroke: 'CTRL+F',
143
- tooltip: true
144
- });
145
- return dropdownView;
146
- }
147
- /**
148
- * Creates a button that opens a dialog with the find and replace form.
149
- */
150
- _createDialogButtonForToolbar() {
151
- const editor = this.editor;
152
- const buttonView = this._createButton(ButtonView);
153
- const dialog = editor.plugins.get('Dialog');
154
- buttonView.set({
155
- tooltip: true
156
- });
157
- // Button should be on when the find and replace dialog is opened.
158
- buttonView.bind('isOn').to(dialog, 'id', id => id === 'findAndReplace');
159
- // Every time a dialog is opened, the search text field should get focused and selected for better UX.
160
- // Each time a dialog is closed, move the focus back to the find and replace toolbar button
161
- // and let the find and replace editing feature know that all search results can be invalidated
162
- // and no longer should be marked in the content.
163
- buttonView.on('execute', () => {
164
- if (buttonView.isOn) {
165
- dialog.hide();
166
- }
167
- else {
168
- this._showDialog();
169
- }
170
- });
171
- return buttonView;
172
- }
173
- /**
174
- * Creates a button for for menu bar that will show find and replace dialog.
175
- */
176
- _createDialogButtonForMenuBar() {
177
- const buttonView = this._createButton(MenuBarMenuListItemButtonView);
178
- const dialogPlugin = this.editor.plugins.get('Dialog');
179
- const dialog = this.editor.plugins.get('Dialog');
180
- buttonView.set({
181
- role: 'menuitemcheckbox',
182
- isToggleable: true
183
- });
184
- // Button should be on when the find and replace dialog is opened.
185
- buttonView.bind('isOn').to(dialog, 'id', id => id === 'findAndReplace');
186
- buttonView.on('execute', () => {
187
- if (dialogPlugin.id === 'findAndReplace') {
188
- dialogPlugin.hide();
189
- return;
190
- }
191
- this._showDialog();
192
- });
193
- return buttonView;
194
- }
195
- /**
196
- * Creates a button for find and replace command to use either in toolbar or in menu bar.
197
- */
198
- _createButton(ButtonClass) {
199
- const editor = this.editor;
200
- const findCommand = editor.commands.get('find');
201
- const buttonView = new ButtonClass(editor.locale);
202
- const t = editor.locale.t;
203
- // Button should be disabled when in source editing mode. See #10001.
204
- buttonView.bind('isEnabled').to(findCommand);
205
- buttonView.set({
206
- icon: IconFindReplace,
207
- label: t('Find and replace'),
208
- keystroke: 'CTRL+F'
209
- });
210
- return buttonView;
211
- }
212
- /**
213
- * Shows the find and replace dialog.
214
- */
215
- _showDialog() {
216
- const editor = this.editor;
217
- const dialog = editor.plugins.get('Dialog');
218
- const t = editor.locale.t;
219
- if (!this.formView) {
220
- this.formView = this._createFormView();
221
- }
222
- dialog.show({
223
- id: 'findAndReplace',
224
- title: t('Find and replace'),
225
- content: this.formView,
226
- position: DialogViewPosition.EDITOR_TOP_SIDE,
227
- onShow: () => {
228
- this._setupFormView();
229
- },
230
- onHide: () => {
231
- this.fire('searchReseted');
232
- }
233
- });
234
- }
235
- /**
236
- * Sets up the form view for the findN and replace.
237
- */
238
- _createFormView() {
239
- const editor = this.editor;
240
- const formView = new (CssTransitionDisablerMixin(FindAndReplaceFormView))(editor.locale);
241
- const commands = editor.commands;
242
- const findAndReplaceEditing = this.editor.plugins.get('FindAndReplaceEditing');
243
- const editingState = findAndReplaceEditing.state;
244
- formView.bind('highlightOffset').to(editingState, 'highlightedOffset');
245
- // Let the form know how many results were found in total.
246
- formView.listenTo(editingState.results, 'change', () => {
247
- formView.matchCount = editingState.results.length;
248
- });
249
- // Command states are used to enable/disable individual form controls.
250
- // To keep things simple, instead of binding 4 individual observables, there's only one that combines every
251
- // commands' isEnabled state. Yes, it will change more often but this simplifies the structure of the form.
252
- const findNextCommand = commands.get('findNext');
253
- const findPreviousCommand = commands.get('findPrevious');
254
- const replaceCommand = commands.get('replace');
255
- const replaceAllCommand = commands.get('replaceAll');
256
- formView.bind('_areCommandsEnabled').to(findNextCommand, 'isEnabled', findPreviousCommand, 'isEnabled', replaceCommand, 'isEnabled', replaceAllCommand, 'isEnabled', (findNext, findPrevious, replace, replaceAll) => ({ findNext, findPrevious, replace, replaceAll }));
257
- // The UI plugin works as an interface between the form and the editing part of the feature.
258
- formView.delegate('findNext', 'findPrevious', 'replace', 'replaceAll').to(this);
259
- // Let the feature know that search results are no longer relevant because the user changed the searched phrase
260
- // (or options) but didn't hit the "Find" button yet (e.g. still typing).
261
- formView.on('change:isDirty', (evt, data, isDirty) => {
262
- if (isDirty) {
263
- this.fire('searchReseted');
264
- }
265
- });
266
- return formView;
267
- }
268
- /**
269
- * Clears the find and replace form and focuses the search text field.
270
- */
271
- _setupFormView() {
272
- this.formView.disableCssTransitions();
273
- this.formView.reset();
274
- this.formView._findInputView.fieldView.select();
275
- this.formView.enableCssTransitions();
276
- }
277
- }
@@ -1,160 +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 { Plugin } from 'ckeditor5/src/core.js';
6
- import { Collection, uid } from 'ckeditor5/src/utils.js';
7
- import { escapeRegExp } from 'es-toolkit/compat';
8
- /**
9
- * A set of helpers related to find and replace.
10
- */
11
- export class FindAndReplaceUtils extends Plugin {
12
- /**
13
- * @inheritDoc
14
- */
15
- static get pluginName() {
16
- return 'FindAndReplaceUtils';
17
- }
18
- /**
19
- * @inheritDoc
20
- */
21
- static get isOfficialPlugin() {
22
- return true;
23
- }
24
- /**
25
- * Executes findCallback and updates search results list.
26
- *
27
- * @param range The model range to scan for matches.
28
- * @param model The model.
29
- * @param findCallback The callback that should return `true` if provided text matches the search term.
30
- * @param startResults An optional collection of find matches that the function should
31
- * start with. This would be a collection returned by a previous `updateFindResultFromRange()` call.
32
- * @returns A collection of objects describing find match.
33
- *
34
- * An example structure:
35
- *
36
- * ```js
37
- * {
38
- * id: resultId,
39
- * label: foundItem.label,
40
- * marker
41
- * }
42
- * ```
43
- */
44
- updateFindResultFromRange(range, model, findCallback, startResults) {
45
- const results = startResults || new Collection();
46
- const checkIfResultAlreadyOnList = (marker) => results.find(markerItem => {
47
- const { marker: resultsMarker } = markerItem;
48
- const resultRange = resultsMarker.getRange();
49
- const markerRange = marker.getRange();
50
- return resultRange.isEqual(markerRange);
51
- });
52
- model.change(writer => {
53
- [...range].forEach(({ type, item }) => {
54
- if (type === 'elementStart') {
55
- if (model.schema.checkChild(item, '$text')) {
56
- let foundItems = findCallback({
57
- item,
58
- text: this.rangeToText(model.createRangeIn(item))
59
- });
60
- if (!foundItems) {
61
- return;
62
- }
63
- if ('results' in foundItems) {
64
- foundItems = foundItems.results;
65
- }
66
- foundItems.forEach(foundItem => {
67
- const resultId = `findResult:${uid()}`;
68
- const marker = writer.addMarker(resultId, {
69
- usingOperation: false,
70
- affectsData: false,
71
- range: writer.createRange(writer.createPositionAt(item, foundItem.start), writer.createPositionAt(item, foundItem.end))
72
- });
73
- const index = findInsertIndex(results, marker);
74
- if (!checkIfResultAlreadyOnList(marker)) {
75
- results.add({
76
- id: resultId,
77
- label: foundItem.label,
78
- marker
79
- }, index);
80
- }
81
- });
82
- }
83
- }
84
- });
85
- });
86
- return results;
87
- }
88
- /**
89
- * Returns text representation of a range. The returned text length should be the same as range length.
90
- * In order to achieve this, this function will replace inline elements (text-line) as new line character ("\n").
91
- *
92
- * @param range The model range.
93
- * @returns The text content of the provided range.
94
- */
95
- rangeToText(range) {
96
- return Array.from(range.getItems({ shallow: true })).reduce((rangeText, node) => {
97
- // Trim text to a last occurrence of an inline element and update range start.
98
- if (!(node.is('$text') || node.is('$textProxy'))) {
99
- // Editor has only one inline element defined in schema: `<softBreak>` which is treated as new line character in blocks.
100
- // Special handling might be needed for other inline elements (inline widgets).
101
- return `${rangeText}\n`;
102
- }
103
- return rangeText + node.data;
104
- }, '');
105
- }
106
- /**
107
- * Creates a text matching callback for a specified search term and matching options.
108
- *
109
- * @param searchTerm The search term.
110
- * @param options Matching options.
111
- * - options.matchCase=false If set to `true` letter casing will be ignored.
112
- * - options.wholeWords=false If set to `true` only whole words that match `callbackOrText` will be matched.
113
- */
114
- findByTextCallback(searchTerm, options) {
115
- let flags = 'gu';
116
- if (!options.matchCase) {
117
- flags += 'i';
118
- }
119
- let regExpQuery = `(${escapeRegExp(searchTerm)})`;
120
- if (options.wholeWords) {
121
- const nonLetterGroup = '[^a-zA-Z\u00C0-\u024F\u1E00-\u1EFF]';
122
- if (!new RegExp('^' + nonLetterGroup).test(searchTerm)) {
123
- regExpQuery = `(^|${nonLetterGroup}|_)${regExpQuery}`;
124
- }
125
- if (!new RegExp(nonLetterGroup + '$').test(searchTerm)) {
126
- regExpQuery = `${regExpQuery}(?=_|${nonLetterGroup}|$)`;
127
- }
128
- }
129
- const regExp = new RegExp(regExpQuery, flags);
130
- function findCallback({ text }) {
131
- const matches = [...text.matchAll(regExp)];
132
- return matches.map(regexpMatchToFindResult);
133
- }
134
- return findCallback;
135
- }
136
- }
137
- // Finds the appropriate index in the resultsList Collection.
138
- function findInsertIndex(resultsList, markerToInsert) {
139
- const result = resultsList.find(({ marker }) => {
140
- return markerToInsert.getStart().isBefore(marker.getStart());
141
- });
142
- return result ? resultsList.getIndex(result) : resultsList.length;
143
- }
144
- /**
145
- * Maps RegExp match result to find result.
146
- */
147
- function regexpMatchToFindResult(matchResult) {
148
- const lastGroupIndex = matchResult.length - 1;
149
- let startOffset = matchResult.index;
150
- // Searches with match all flag have an extra matching group with empty string or white space matched before the word.
151
- // If the search term starts with the space already, there is no extra group even with match all flag on.
152
- if (matchResult.length === 3) {
153
- startOffset += matchResult[1].length;
154
- }
155
- return {
156
- label: matchResult[lastGroupIndex],
157
- start: startOffset,
158
- end: startOffset + matchResult[lastGroupIndex].length
159
- };
160
- }
@@ -1,83 +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/findcommand
7
- */
8
- import { Command } from 'ckeditor5/src/core.js';
9
- /**
10
- * The find command. It is used by the {@link module:find-and-replace/findandreplace~FindAndReplace find and replace feature}.
11
- */
12
- export class FindCommand extends Command {
13
- /**
14
- * The find and replace state object used for command operations.
15
- */
16
- _state;
17
- /**
18
- * Creates a new `FindCommand` instance.
19
- *
20
- * @param editor The editor on which this command will be used.
21
- * @param state An object to hold plugin state.
22
- */
23
- constructor(editor, state) {
24
- super(editor);
25
- // The find command is always enabled.
26
- this.isEnabled = true;
27
- // It does not affect data so should be enabled in read-only mode.
28
- this.affectsData = false;
29
- this._state = state;
30
- }
31
- /**
32
- * Executes the command.
33
- *
34
- * @param callbackOrText
35
- * @param options Options object.
36
- * @param options.matchCase If set to `true`, the letter case will be matched.
37
- * @param options.wholeWords If set to `true`, only whole words that match `callbackOrText` will be matched.
38
- *
39
- * @fires execute
40
- */
41
- execute(callbackOrText, { matchCase, wholeWords } = {}) {
42
- const { editor } = this;
43
- const { model } = editor;
44
- const findAndReplaceUtils = editor.plugins.get('FindAndReplaceUtils');
45
- let findCallback;
46
- let callbackSearchText = '';
47
- // Allow to execute `find()` on a plugin with a keyword only.
48
- if (typeof callbackOrText === 'string') {
49
- findCallback = (...args) => ({
50
- results: findAndReplaceUtils.findByTextCallback(callbackOrText, { matchCase, wholeWords })(...args),
51
- searchText: callbackOrText
52
- });
53
- }
54
- else {
55
- findCallback = callbackOrText;
56
- }
57
- // Wrap the callback to get the search text that will be assigned to the state.
58
- const oldCallback = findCallback;
59
- findCallback = (...args) => {
60
- const result = oldCallback(...args);
61
- if (result && 'searchText' in result) {
62
- callbackSearchText = result.searchText;
63
- }
64
- return result;
65
- };
66
- // Initial search is done on all nodes in all roots inside the content.
67
- const results = model.document.getRootNames()
68
- .reduce(((currentResults, rootName) => findAndReplaceUtils.updateFindResultFromRange(model.createRangeIn(model.document.getRoot(rootName)), model, findCallback, currentResults)), null);
69
- this._state.clear(model);
70
- this._state.results.addMany(results);
71
- this._state.highlightedResult = results.get(0);
72
- this._state.searchText = callbackSearchText;
73
- if (findCallback) {
74
- this._state.lastSearchCallback = findCallback;
75
- }
76
- this._state.matchCase = !!matchCase;
77
- this._state.matchWholeWords = !!wholeWords;
78
- return {
79
- results,
80
- findCallback
81
- };
82
- }
83
- }
@@ -1,51 +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/findnextcommand
7
- */
8
- import { Command } from 'ckeditor5/src/core.js';
9
- /**
10
- * The find next command. Moves the highlight to the next search result.
11
- *
12
- * It is used by the {@link module:find-and-replace/findandreplace~FindAndReplace find and replace feature}.
13
- */
14
- export class FindNextCommand extends Command {
15
- /**
16
- * The find and replace state object used for command operations.
17
- */
18
- _state;
19
- /**
20
- * Creates a new `FindNextCommand` instance.
21
- *
22
- * @param editor The editor on which this command will be used.
23
- * @param state An object to hold plugin state.
24
- */
25
- constructor(editor, state) {
26
- super(editor);
27
- // It does not affect data so should be enabled in read-only mode.
28
- this.affectsData = false;
29
- this._state = state;
30
- this.isEnabled = false;
31
- this.listenTo(this._state.results, 'change', () => {
32
- this.isEnabled = this._state.results.length > 1;
33
- });
34
- }
35
- /**
36
- * @inheritDoc
37
- */
38
- refresh() {
39
- this.isEnabled = this._state.results.length > 1;
40
- }
41
- /**
42
- * @inheritDoc
43
- */
44
- execute() {
45
- const results = this._state.results;
46
- const currentIndex = results.getIndex(this._state.highlightedResult);
47
- const nextIndex = currentIndex + 1 >= results.length ?
48
- 0 : currentIndex + 1;
49
- this._state.highlightedResult = this._state.results.get(nextIndex);
50
- }
51
- }
@@ -1,25 +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/findpreviouscommand
7
- */
8
- import { FindNextCommand } from './findnextcommand.js';
9
- /**
10
- * The find previous command. Moves the highlight to the previous search result.
11
- *
12
- * It is used by the {@link module:find-and-replace/findandreplace~FindAndReplace find and replace feature}.
13
- */
14
- export class FindPreviousCommand extends FindNextCommand {
15
- /**
16
- * @inheritDoc
17
- */
18
- execute() {
19
- const results = this._state.results;
20
- const currentIndex = results.getIndex(this._state.highlightedResult);
21
- const previousIndex = currentIndex - 1 < 0 ?
22
- this._state.results.length - 1 : currentIndex - 1;
23
- this._state.highlightedResult = this._state.results.get(previousIndex);
24
- }
25
- }
package/src/index.js DELETED
@@ -1,20 +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
7
- */
8
- export { FindAndReplace } from './findandreplace.js';
9
- export { FindAndReplaceEditing } from './findandreplaceediting.js';
10
- export { FindAndReplaceUI } from './findandreplaceui.js';
11
- export { FindAndReplaceUtils } from './findandreplaceutils.js';
12
- export { FindCommand } from './findcommand.js';
13
- export { FindNextCommand } from './findnextcommand.js';
14
- export { FindPreviousCommand } from './findpreviouscommand.js';
15
- export { ReplaceCommand } from './replacecommand.js';
16
- export { ReplaceAllCommand } from './replaceallcommand.js';
17
- export { FindReplaceCommandBase } from './replacecommandbase.js';
18
- export { FindAndReplaceFormView } from './ui/findandreplaceformview.js';
19
- export { FindAndReplaceState, sortSearchResultsByMarkerPositions as _sortFindResultsByMarkerPositions } from './findandreplacestate.js';
20
- import './augmentation.js';
@@ -1,50 +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/replaceallcommand
7
- */
8
- import { Collection } from 'ckeditor5/src/utils.js';
9
- import { FindReplaceCommandBase } from './replacecommandbase.js';
10
- /**
11
- * The replace all command. It is used by the {@link module:find-and-replace/findandreplace~FindAndReplace find and replace feature}.
12
- */
13
- export class ReplaceAllCommand extends FindReplaceCommandBase {
14
- /**
15
- * Replaces all the occurrences of `textToReplace` with a given `newText` string.
16
- *
17
- * ```ts
18
- * replaceAllCommand.execute( 'replaceAll', 'new text replacement', 'text to replace' );
19
- * ```
20
- *
21
- * Alternatively you can call it from editor instance:
22
- *
23
- * ```ts
24
- * editor.execute( 'replaceAll', 'new text', 'old text' );
25
- * ```
26
- *
27
- * @param newText Text that will be inserted to the editor for each match.
28
- * @param textToReplace Text to be replaced or a collection of matches
29
- * as returned by the find command.
30
- *
31
- * @fires module:core/command~Command#event:execute
32
- */
33
- execute(newText, textToReplace) {
34
- const { editor } = this;
35
- const { model } = editor;
36
- const findAndReplaceUtils = editor.plugins.get('FindAndReplaceUtils');
37
- const results = textToReplace instanceof Collection ?
38
- textToReplace : model.document.getRootNames()
39
- .reduce(((currentResults, rootName) => findAndReplaceUtils.updateFindResultFromRange(model.createRangeIn(model.document.getRoot(rootName)), model, findAndReplaceUtils.findByTextCallback(textToReplace, this._state), currentResults)), null);
40
- if (results.length) {
41
- // Wrapped in single change will batch it into one transaction.
42
- model.change(() => {
43
- [...results].forEach(searchResult => {
44
- // Just reuse logic from the replace command to replace a single match.
45
- this._replace(newText, searchResult);
46
- });
47
- });
48
- }
49
- }
50
- }