@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/lang/translations/zh.po
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
2
|
-
#
|
|
3
|
-
# Want to contribute to this file? Submit your changes via a GitHub Pull Request.
|
|
4
|
-
#
|
|
5
|
-
# Check out the official contributor's guide:
|
|
6
|
-
# https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
|
|
7
|
-
#
|
|
8
|
-
msgid ""
|
|
9
|
-
msgstr ""
|
|
10
|
-
"Language: zh_TW\n"
|
|
11
|
-
"Plural-Forms: nplurals=1; plural=0;\n"
|
|
12
|
-
"Content-Type: text/plain; charset=UTF-8\n"
|
|
13
|
-
|
|
14
|
-
msgctxt "The tooltip of a find and replace button in the toolbar. Also, the title of the find and replace form."
|
|
15
|
-
msgid "Find and replace"
|
|
16
|
-
msgstr "尋找和取代"
|
|
17
|
-
|
|
18
|
-
msgctxt "The label for the searched text in the find and replace dropdown."
|
|
19
|
-
msgid "Find in text…"
|
|
20
|
-
msgstr "在文本中尋找"
|
|
21
|
-
|
|
22
|
-
msgctxt "The label for the find action button in the find and replace dropdown."
|
|
23
|
-
msgid "Find"
|
|
24
|
-
msgstr "尋找"
|
|
25
|
-
|
|
26
|
-
msgctxt "The label for the previous result button in the find and replace dropdown."
|
|
27
|
-
msgid "Previous result"
|
|
28
|
-
msgstr "前一個結果"
|
|
29
|
-
|
|
30
|
-
msgctxt "The label for the previous result button in the find and replace dropdown."
|
|
31
|
-
msgid "Next result"
|
|
32
|
-
msgstr "後一個結果"
|
|
33
|
-
|
|
34
|
-
msgctxt "The label for the (single) replace action button in the find and replace dropdown."
|
|
35
|
-
msgid "Replace"
|
|
36
|
-
msgstr "取代"
|
|
37
|
-
|
|
38
|
-
msgctxt "The label for the replace all action button in the find and replace dropdown."
|
|
39
|
-
msgid "Replace all"
|
|
40
|
-
msgstr "全部取代"
|
|
41
|
-
|
|
42
|
-
msgctxt "The label for the match case checkbox in the find and replace dropdown."
|
|
43
|
-
msgid "Match case"
|
|
44
|
-
msgstr "大小寫需相符"
|
|
45
|
-
|
|
46
|
-
msgctxt "The label for the whole words only checkbox in the find and replace dropdown."
|
|
47
|
-
msgid "Whole words only"
|
|
48
|
-
msgstr "僅全字拼寫"
|
|
49
|
-
|
|
50
|
-
msgctxt "The label for the text replacement in the find and replace dropdown."
|
|
51
|
-
msgid "Replace with…"
|
|
52
|
-
msgstr "以…替代"
|
|
53
|
-
|
|
54
|
-
msgctxt "An error text displayed when user attempted to find an empty text."
|
|
55
|
-
msgid "Text to find must not be empty."
|
|
56
|
-
msgstr "不能查找空字串"
|
|
57
|
-
|
|
58
|
-
msgctxt "A message displayed next to the replace field when disabled but user tries to use it."
|
|
59
|
-
msgid "Tip: Find some text first in order to replace it."
|
|
60
|
-
msgstr "提示:先查找字串再取代"
|
|
61
|
-
|
|
62
|
-
msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
|
|
63
|
-
msgid "Advanced options"
|
|
64
|
-
msgstr "進階選項"
|
|
65
|
-
|
|
66
|
-
msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
|
|
67
|
-
msgid "Find in the document"
|
|
68
|
-
msgstr "在文件中尋找"
|
package/src/augmentation.js
DELETED
package/src/findandreplace.js
DELETED
|
@@ -1,90 +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/findandreplace
|
|
7
|
-
*/
|
|
8
|
-
import { Plugin } from 'ckeditor5/src/core.js';
|
|
9
|
-
import { FindAndReplaceUI } from './findandreplaceui.js';
|
|
10
|
-
import { FindAndReplaceEditing } from './findandreplaceediting.js';
|
|
11
|
-
/**
|
|
12
|
-
* The find and replace plugin.
|
|
13
|
-
*
|
|
14
|
-
* For a detailed overview, check the {@glink features/find-and-replace Find and replace feature documentation}.
|
|
15
|
-
*
|
|
16
|
-
* This is a "glue" plugin which loads the following plugins:
|
|
17
|
-
*
|
|
18
|
-
* * The {@link module:find-and-replace/findandreplaceediting~FindAndReplaceEditing find and replace editing feature},
|
|
19
|
-
* * The {@link module:find-and-replace/findandreplaceui~FindAndReplaceUI find and replace UI feature}
|
|
20
|
-
*/
|
|
21
|
-
export class FindAndReplace extends Plugin {
|
|
22
|
-
/**
|
|
23
|
-
* @inheritDoc
|
|
24
|
-
*/
|
|
25
|
-
static get requires() {
|
|
26
|
-
return [FindAndReplaceEditing, FindAndReplaceUI];
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* @inheritDoc
|
|
30
|
-
*/
|
|
31
|
-
static get pluginName() {
|
|
32
|
-
return 'FindAndReplace';
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* @inheritDoc
|
|
36
|
-
*/
|
|
37
|
-
static get isOfficialPlugin() {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* @inheritDoc
|
|
42
|
-
*/
|
|
43
|
-
init() {
|
|
44
|
-
const ui = this.editor.plugins.get('FindAndReplaceUI');
|
|
45
|
-
const findAndReplaceEditing = this.editor.plugins.get('FindAndReplaceEditing');
|
|
46
|
-
const state = findAndReplaceEditing.state;
|
|
47
|
-
ui.on('findNext', (event, data) => {
|
|
48
|
-
// Data is contained only for the "find" button.
|
|
49
|
-
if (data) {
|
|
50
|
-
state.searchText = data.searchText;
|
|
51
|
-
findAndReplaceEditing.find(data.searchText, data);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
// Find next arrow button press.
|
|
55
|
-
this.editor.execute('findNext');
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
ui.on('findPrevious', (event, data) => {
|
|
59
|
-
if (data && state.searchText !== data.searchText) {
|
|
60
|
-
findAndReplaceEditing.find(data.searchText);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
// Subsequent calls.
|
|
64
|
-
this.editor.execute('findPrevious');
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
ui.on('replace', (event, data) => {
|
|
68
|
-
if (state.searchText !== data.searchText) {
|
|
69
|
-
findAndReplaceEditing.find(data.searchText);
|
|
70
|
-
}
|
|
71
|
-
const highlightedResult = state.highlightedResult;
|
|
72
|
-
if (highlightedResult) {
|
|
73
|
-
this.editor.execute('replace', data.replaceText, highlightedResult);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
ui.on('replaceAll', (event, data) => {
|
|
77
|
-
// The state hadn't been yet built for this search text.
|
|
78
|
-
if (state.searchText !== data.searchText) {
|
|
79
|
-
findAndReplaceEditing.find(data.searchText);
|
|
80
|
-
}
|
|
81
|
-
this.editor.execute('replaceAll', data.replaceText, state.results);
|
|
82
|
-
});
|
|
83
|
-
// Reset the state when the user invalidated last search results, for instance,
|
|
84
|
-
// by starting typing another search query or changing options.
|
|
85
|
-
ui.on('searchReseted', () => {
|
|
86
|
-
state.clear(this.editor.model);
|
|
87
|
-
findAndReplaceEditing.stop();
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,247 +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/findandreplaceediting
|
|
7
|
-
*/
|
|
8
|
-
import { Plugin } from 'ckeditor5/src/core.js';
|
|
9
|
-
import { scrollViewportToShowTarget } from 'ckeditor5/src/utils.js';
|
|
10
|
-
import { FindCommand } from './findcommand.js';
|
|
11
|
-
import { ReplaceCommand } from './replacecommand.js';
|
|
12
|
-
import { ReplaceAllCommand } from './replaceallcommand.js';
|
|
13
|
-
import { FindNextCommand } from './findnextcommand.js';
|
|
14
|
-
import { FindPreviousCommand } from './findpreviouscommand.js';
|
|
15
|
-
import { FindAndReplaceState } from './findandreplacestate.js';
|
|
16
|
-
import { FindAndReplaceUtils } from './findandreplaceutils.js';
|
|
17
|
-
import { debounce } from 'es-toolkit/compat';
|
|
18
|
-
import '../theme/findandreplace.css';
|
|
19
|
-
const HIGHLIGHT_CLASS = 'ck-find-result_selected';
|
|
20
|
-
/**
|
|
21
|
-
* Implements the editing part for find and replace plugin. For example conversion, commands etc.
|
|
22
|
-
*/
|
|
23
|
-
export class FindAndReplaceEditing extends Plugin {
|
|
24
|
-
/**
|
|
25
|
-
* @inheritDoc
|
|
26
|
-
*/
|
|
27
|
-
static get requires() {
|
|
28
|
-
return [FindAndReplaceUtils];
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* @inheritDoc
|
|
32
|
-
*/
|
|
33
|
-
static get pluginName() {
|
|
34
|
-
return 'FindAndReplaceEditing';
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* @inheritDoc
|
|
38
|
-
* @internal
|
|
39
|
-
*/
|
|
40
|
-
static get licenseFeatureCode() {
|
|
41
|
-
return 'FAR';
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* @inheritDoc
|
|
45
|
-
*/
|
|
46
|
-
static get isPremiumPlugin() {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* @inheritDoc
|
|
51
|
-
*/
|
|
52
|
-
static get isOfficialPlugin() {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* An object storing the find and replace state within a given editor instance.
|
|
57
|
-
*/
|
|
58
|
-
state;
|
|
59
|
-
/**
|
|
60
|
-
* @inheritDoc
|
|
61
|
-
*/
|
|
62
|
-
init() {
|
|
63
|
-
this.state = new FindAndReplaceState(this.editor.model);
|
|
64
|
-
this.set('_isSearchActive', false);
|
|
65
|
-
this._defineConverters();
|
|
66
|
-
this._defineCommands();
|
|
67
|
-
this.listenTo(this.state, 'change:highlightedResult', (eventInfo, name, newValue, oldValue) => {
|
|
68
|
-
const { model } = this.editor;
|
|
69
|
-
model.change(writer => {
|
|
70
|
-
if (oldValue) {
|
|
71
|
-
const oldMatchId = oldValue.marker.name.split(':')[1];
|
|
72
|
-
const oldMarker = model.markers.get(`findResultHighlighted:${oldMatchId}`);
|
|
73
|
-
if (oldMarker) {
|
|
74
|
-
writer.removeMarker(oldMarker);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (newValue) {
|
|
78
|
-
const newMatchId = newValue.marker.name.split(':')[1];
|
|
79
|
-
writer.addMarker(`findResultHighlighted:${newMatchId}`, {
|
|
80
|
-
usingOperation: false,
|
|
81
|
-
affectsData: false,
|
|
82
|
-
range: newValue.marker.getRange()
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
/* istanbul ignore next -- @preserve */
|
|
88
|
-
const scrollToHighlightedResult = (eventInfo, name, newValue) => {
|
|
89
|
-
if (newValue) {
|
|
90
|
-
const domConverter = this.editor.editing.view.domConverter;
|
|
91
|
-
const viewRange = this.editor.editing.mapper.toViewRange(newValue.marker.getRange());
|
|
92
|
-
scrollViewportToShowTarget({
|
|
93
|
-
target: domConverter.viewRangeToDom(viewRange),
|
|
94
|
-
viewportOffset: 40
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
const debouncedScrollListener = debounce(scrollToHighlightedResult.bind(this), 32);
|
|
99
|
-
// Debounce scroll as highlight might be changed very frequently, e.g. when there's a replace all command.
|
|
100
|
-
this.listenTo(this.state, 'change:highlightedResult', debouncedScrollListener, { priority: 'low' });
|
|
101
|
-
// It's possible that the editor will get destroyed before debounced call kicks in.
|
|
102
|
-
// This would result with accessing a view three that is no longer in DOM.
|
|
103
|
-
this.listenTo(this.editor, 'destroy', debouncedScrollListener.cancel);
|
|
104
|
-
this.on('change:_isSearchActive', (evt, name, isSearchActive) => {
|
|
105
|
-
if (isSearchActive) {
|
|
106
|
-
this.listenTo(this.editor.model.document, 'change:data', this._onDocumentChange);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
this.stopListening(this.editor.model.document, 'change:data', this._onDocumentChange);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Initiate a search.
|
|
115
|
-
*/
|
|
116
|
-
find(callbackOrText, findAttributes) {
|
|
117
|
-
this._isSearchActive = true;
|
|
118
|
-
this.editor.execute('find', callbackOrText, findAttributes);
|
|
119
|
-
return this.state.results;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Stops active results from updating, and clears out the results.
|
|
123
|
-
*/
|
|
124
|
-
stop() {
|
|
125
|
-
this.state.clear(this.editor.model);
|
|
126
|
-
this._isSearchActive = false;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Sets up the commands.
|
|
130
|
-
*/
|
|
131
|
-
_defineCommands() {
|
|
132
|
-
this.editor.commands.add('find', new FindCommand(this.editor, this.state));
|
|
133
|
-
this.editor.commands.add('findNext', new FindNextCommand(this.editor, this.state));
|
|
134
|
-
this.editor.commands.add('findPrevious', new FindPreviousCommand(this.editor, this.state));
|
|
135
|
-
this.editor.commands.add('replace', new ReplaceCommand(this.editor, this.state));
|
|
136
|
-
this.editor.commands.add('replaceAll', new ReplaceAllCommand(this.editor, this.state));
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Sets up the marker downcast converters for search results highlighting.
|
|
140
|
-
*/
|
|
141
|
-
_defineConverters() {
|
|
142
|
-
const { editor } = this;
|
|
143
|
-
// Setup the marker highlighting conversion.
|
|
144
|
-
editor.conversion.for('editingDowncast').markerToHighlight({
|
|
145
|
-
model: 'findResult',
|
|
146
|
-
view: ({ markerName }) => {
|
|
147
|
-
const [, id] = markerName.split(':');
|
|
148
|
-
// Marker removal from the view has a bug: https://github.com/ckeditor/ckeditor5/issues/7499
|
|
149
|
-
// A minimal option is to return a new object for each converted marker...
|
|
150
|
-
return {
|
|
151
|
-
name: 'span',
|
|
152
|
-
classes: ['ck-find-result'],
|
|
153
|
-
attributes: {
|
|
154
|
-
// ...however, adding a unique attribute should be future-proof..
|
|
155
|
-
'data-find-result': id
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
editor.conversion.for('editingDowncast').markerToHighlight({
|
|
161
|
-
model: 'findResultHighlighted',
|
|
162
|
-
view: ({ markerName }) => {
|
|
163
|
-
const [, id] = markerName.split(':');
|
|
164
|
-
// Marker removal from the view has a bug: https://github.com/ckeditor/ckeditor5/issues/7499
|
|
165
|
-
// A minimal option is to return a new object for each converted marker...
|
|
166
|
-
return {
|
|
167
|
-
name: 'span',
|
|
168
|
-
classes: [HIGHLIGHT_CLASS],
|
|
169
|
-
attributes: {
|
|
170
|
-
// ...however, adding a unique attribute should be future-proof..
|
|
171
|
-
'data-find-result': id
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Reacts to document changes in order to update search list.
|
|
179
|
-
*/
|
|
180
|
-
_onDocumentChange = () => {
|
|
181
|
-
const changedNodes = new Set();
|
|
182
|
-
const removedMarkers = new Set();
|
|
183
|
-
const model = this.editor.model;
|
|
184
|
-
const { results } = this.state;
|
|
185
|
-
const changes = model.document.differ.getChanges();
|
|
186
|
-
const changedMarkers = model.document.differ.getChangedMarkers();
|
|
187
|
-
// Get nodes in which changes happened to re-run a search callback on them.
|
|
188
|
-
changes.forEach(change => {
|
|
189
|
-
if (!change.position) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (change.name === '$text' || (change.position.nodeAfter && model.schema.isInline(change.position.nodeAfter))) {
|
|
193
|
-
changedNodes.add(change.position.parent);
|
|
194
|
-
[...model.markers.getMarkersAtPosition(change.position)].forEach(markerAtChange => {
|
|
195
|
-
removedMarkers.add(markerAtChange.name);
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
else if (change.type === 'insert' && change.position.nodeAfter) {
|
|
199
|
-
changedNodes.add(change.position.nodeAfter);
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
// Get markers from removed nodes also.
|
|
203
|
-
changedMarkers.forEach(({ name, data: { newRange } }) => {
|
|
204
|
-
if (newRange && newRange.start.root.rootName === '$graveyard') {
|
|
205
|
-
removedMarkers.add(name);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
// Get markers from the updated nodes and remove all (search will be re-run on these nodes).
|
|
209
|
-
changedNodes.forEach(node => {
|
|
210
|
-
const markersInNode = [...model.markers.getMarkersIntersectingRange(model.createRangeIn(node))];
|
|
211
|
-
markersInNode.forEach(marker => removedMarkers.add(marker.name));
|
|
212
|
-
});
|
|
213
|
-
// Remove results from the changed part of content.
|
|
214
|
-
removedMarkers.forEach(markerName => {
|
|
215
|
-
if (!results.has(markerName)) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
if (results.get(markerName) === this.state.highlightedResult) {
|
|
219
|
-
this.state.highlightedResult = null;
|
|
220
|
-
}
|
|
221
|
-
results.remove(markerName);
|
|
222
|
-
});
|
|
223
|
-
// Run search callback again on updated nodes.
|
|
224
|
-
const changedSearchResults = [];
|
|
225
|
-
const findAndReplaceUtils = this.editor.plugins.get('FindAndReplaceUtils');
|
|
226
|
-
changedNodes.forEach(nodeToCheck => {
|
|
227
|
-
const changedNodeSearchResults = findAndReplaceUtils.updateFindResultFromRange(model.createRangeOn(nodeToCheck), model, this.state.lastSearchCallback, results);
|
|
228
|
-
changedSearchResults.push(...changedNodeSearchResults);
|
|
229
|
-
});
|
|
230
|
-
changedMarkers.forEach(markerToCheck => {
|
|
231
|
-
// Handle search result highlight update when T&C plugin is active.
|
|
232
|
-
// Lookup is performed only on newly inserted markers.
|
|
233
|
-
if (markerToCheck.data.newRange) {
|
|
234
|
-
const changedNodeSearchResults = findAndReplaceUtils.updateFindResultFromRange(markerToCheck.data.newRange, model, this.state.lastSearchCallback, results);
|
|
235
|
-
changedSearchResults.push(...changedNodeSearchResults);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
if (!this.state.highlightedResult && changedSearchResults.length) {
|
|
239
|
-
// If there are found phrases but none is selected, select the first one.
|
|
240
|
-
this.state.highlightedResult = changedSearchResults[0];
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
// If there is already highlight item then refresh highlight offset after appending new items.
|
|
244
|
-
this.state.refreshHighlightOffset(model);
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
}
|
|
@@ -1,93 +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 { ObservableMixin, Collection } from 'ckeditor5/src/utils.js';
|
|
6
|
-
/**
|
|
7
|
-
* The object storing find and replace plugin state for a given editor instance.
|
|
8
|
-
*/
|
|
9
|
-
export class FindAndReplaceState extends /* #__PURE__ */ ObservableMixin() {
|
|
10
|
-
/**
|
|
11
|
-
* Creates an instance of the state.
|
|
12
|
-
*/
|
|
13
|
-
constructor(model) {
|
|
14
|
-
super();
|
|
15
|
-
this.set('results', new Collection());
|
|
16
|
-
this.set('highlightedResult', null);
|
|
17
|
-
this.set('highlightedOffset', 0);
|
|
18
|
-
this.set('searchText', '');
|
|
19
|
-
this.set('replaceText', '');
|
|
20
|
-
this.set('lastSearchCallback', null);
|
|
21
|
-
this.set('matchCase', false);
|
|
22
|
-
this.set('matchWholeWords', false);
|
|
23
|
-
this.results.on('change', (eventInfo, { removed, index }) => {
|
|
24
|
-
if (Array.from(removed).length) {
|
|
25
|
-
let highlightedResultRemoved = false;
|
|
26
|
-
model.change(writer => {
|
|
27
|
-
for (const removedResult of removed) {
|
|
28
|
-
if (this.highlightedResult === removedResult) {
|
|
29
|
-
highlightedResultRemoved = true;
|
|
30
|
-
}
|
|
31
|
-
if (model.markers.has(removedResult.marker.name)) {
|
|
32
|
-
writer.removeMarker(removedResult.marker);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
if (highlightedResultRemoved) {
|
|
37
|
-
const nextHighlightedIndex = index >= this.results.length ? 0 : index;
|
|
38
|
-
this.highlightedResult = this.results.get(nextHighlightedIndex);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
this.on('change:highlightedResult', () => {
|
|
43
|
-
this.refreshHighlightOffset(model);
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Cleans the state up and removes markers from the model.
|
|
48
|
-
*/
|
|
49
|
-
clear(model) {
|
|
50
|
-
this.searchText = '';
|
|
51
|
-
model.change(writer => {
|
|
52
|
-
if (this.highlightedResult) {
|
|
53
|
-
const oldMatchId = this.highlightedResult.marker.name.split(':')[1];
|
|
54
|
-
const oldMarker = model.markers.get(`findResultHighlighted:${oldMatchId}`);
|
|
55
|
-
if (oldMarker) {
|
|
56
|
-
writer.removeMarker(oldMarker);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
[...this.results].forEach(({ marker }) => {
|
|
60
|
-
writer.removeMarker(marker);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
this.results.clear();
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Refreshes the highlight result offset based on it's index within the result list.
|
|
67
|
-
*/
|
|
68
|
-
refreshHighlightOffset(model) {
|
|
69
|
-
const { highlightedResult, results } = this;
|
|
70
|
-
if (highlightedResult) {
|
|
71
|
-
this.highlightedOffset = sortSearchResultsByMarkerPositions(model, [...results]).indexOf(highlightedResult) + 1;
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
this.highlightedOffset = 0;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Sorts search results by marker positions. Make sure that the results are sorted in the same order as they appear in the document
|
|
80
|
-
* to avoid issues with the `find next` command. Apparently, the order of the results in the state might be different than the order
|
|
81
|
-
* of the markers in the model.
|
|
82
|
-
*
|
|
83
|
-
* @internal
|
|
84
|
-
*/
|
|
85
|
-
export function sortSearchResultsByMarkerPositions(model, results) {
|
|
86
|
-
const sortMapping = { before: -1, same: 0, after: 1, different: 1 };
|
|
87
|
-
// `compareWith` doesn't play well with multi-root documents, so we need to sort results by root name first
|
|
88
|
-
// and then sort them within each root. It prevents "random" order of results when the document has multiple roots.
|
|
89
|
-
// See more: https://github.com/ckeditor/ckeditor5/pull/17292#issuecomment-2442084549
|
|
90
|
-
return model.document.getRootNames().flatMap(rootName => results
|
|
91
|
-
.filter(result => result.marker.getStart().root.rootName === rootName)
|
|
92
|
-
.sort((a, b) => sortMapping[a.marker.getStart().compareWith(b.marker.getStart())]));
|
|
93
|
-
}
|