@ckeditor/ckeditor5-find-and-replace 0.0.0-internal-20241017.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/CHANGELOG.md +4 -0
- package/LICENSE.md +21 -0
- package/README.md +26 -0
- package/build/find-and-replace.js +5 -0
- package/build/translations/af.js +1 -0
- package/build/translations/ar.js +1 -0
- package/build/translations/bg.js +1 -0
- package/build/translations/bn.js +1 -0
- package/build/translations/bs.js +1 -0
- package/build/translations/ca.js +1 -0
- package/build/translations/cs.js +1 -0
- package/build/translations/da.js +1 -0
- package/build/translations/de.js +1 -0
- package/build/translations/el.js +1 -0
- package/build/translations/en-au.js +1 -0
- package/build/translations/es-co.js +1 -0
- package/build/translations/es.js +1 -0
- package/build/translations/et.js +1 -0
- package/build/translations/fa.js +1 -0
- package/build/translations/fi.js +1 -0
- package/build/translations/fr.js +1 -0
- package/build/translations/gl.js +1 -0
- package/build/translations/he.js +1 -0
- package/build/translations/hi.js +1 -0
- package/build/translations/hr.js +1 -0
- package/build/translations/hu.js +1 -0
- package/build/translations/id.js +1 -0
- package/build/translations/it.js +1 -0
- package/build/translations/ja.js +1 -0
- package/build/translations/jv.js +1 -0
- package/build/translations/ko.js +1 -0
- package/build/translations/lt.js +1 -0
- package/build/translations/lv.js +1 -0
- package/build/translations/ms.js +1 -0
- package/build/translations/nl.js +1 -0
- package/build/translations/no.js +1 -0
- package/build/translations/pl.js +1 -0
- package/build/translations/pt-br.js +1 -0
- package/build/translations/pt.js +1 -0
- package/build/translations/ro.js +1 -0
- package/build/translations/ru.js +1 -0
- package/build/translations/sk.js +1 -0
- package/build/translations/sr-latn.js +1 -0
- package/build/translations/sr.js +1 -0
- package/build/translations/sv.js +1 -0
- package/build/translations/th.js +1 -0
- package/build/translations/ti.js +1 -0
- package/build/translations/tr.js +1 -0
- package/build/translations/tt.js +1 -0
- package/build/translations/ug.js +1 -0
- package/build/translations/uk.js +1 -0
- package/build/translations/ur.js +1 -0
- package/build/translations/vi.js +1 -0
- package/build/translations/zh-cn.js +1 -0
- package/build/translations/zh.js +1 -0
- package/ckeditor5-metadata.json +18 -0
- package/dist/augmentation.d.ts +24 -0
- package/dist/findandreplace.d.ts +50 -0
- package/dist/findandreplaceconfig.d.ts +35 -0
- package/dist/findandreplaceediting.d.ts +71 -0
- package/dist/findandreplacestate.d.ts +116 -0
- package/dist/findandreplaceui.d.ts +87 -0
- package/dist/findandreplaceutils.d.ts +77 -0
- package/dist/findcommand.d.ts +52 -0
- package/dist/findnextcommand.d.ts +39 -0
- package/dist/findpreviouscommand.d.ts +23 -0
- package/dist/index-content.css +4 -0
- package/dist/index-editor.css +54 -0
- package/dist/index.css +78 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +1523 -0
- package/dist/index.js.map +1 -0
- package/dist/replaceallcommand.d.ts +39 -0
- package/dist/replacecommand.d.ts +26 -0
- package/dist/replacecommandbase.d.ts +35 -0
- package/dist/translations/af.d.ts +8 -0
- package/dist/translations/af.js +5 -0
- package/dist/translations/af.umd.js +11 -0
- package/dist/translations/ar.d.ts +8 -0
- package/dist/translations/ar.js +5 -0
- package/dist/translations/ar.umd.js +11 -0
- package/dist/translations/bg.d.ts +8 -0
- package/dist/translations/bg.js +5 -0
- package/dist/translations/bg.umd.js +11 -0
- package/dist/translations/bn.d.ts +8 -0
- package/dist/translations/bn.js +5 -0
- package/dist/translations/bn.umd.js +11 -0
- package/dist/translations/bs.d.ts +8 -0
- package/dist/translations/bs.js +5 -0
- package/dist/translations/bs.umd.js +11 -0
- package/dist/translations/ca.d.ts +8 -0
- package/dist/translations/ca.js +5 -0
- package/dist/translations/ca.umd.js +11 -0
- package/dist/translations/cs.d.ts +8 -0
- package/dist/translations/cs.js +5 -0
- package/dist/translations/cs.umd.js +11 -0
- package/dist/translations/da.d.ts +8 -0
- package/dist/translations/da.js +5 -0
- package/dist/translations/da.umd.js +11 -0
- package/dist/translations/de.d.ts +8 -0
- package/dist/translations/de.js +5 -0
- package/dist/translations/de.umd.js +11 -0
- package/dist/translations/el.d.ts +8 -0
- package/dist/translations/el.js +5 -0
- package/dist/translations/el.umd.js +11 -0
- package/dist/translations/en-au.d.ts +8 -0
- package/dist/translations/en-au.js +5 -0
- package/dist/translations/en-au.umd.js +11 -0
- package/dist/translations/en.d.ts +8 -0
- package/dist/translations/en.js +5 -0
- package/dist/translations/en.umd.js +11 -0
- package/dist/translations/es-co.d.ts +8 -0
- package/dist/translations/es-co.js +5 -0
- package/dist/translations/es-co.umd.js +11 -0
- package/dist/translations/es.d.ts +8 -0
- package/dist/translations/es.js +5 -0
- package/dist/translations/es.umd.js +11 -0
- package/dist/translations/et.d.ts +8 -0
- package/dist/translations/et.js +5 -0
- package/dist/translations/et.umd.js +11 -0
- package/dist/translations/fa.d.ts +8 -0
- package/dist/translations/fa.js +5 -0
- package/dist/translations/fa.umd.js +11 -0
- package/dist/translations/fi.d.ts +8 -0
- package/dist/translations/fi.js +5 -0
- package/dist/translations/fi.umd.js +11 -0
- package/dist/translations/fr.d.ts +8 -0
- package/dist/translations/fr.js +5 -0
- package/dist/translations/fr.umd.js +11 -0
- package/dist/translations/gl.d.ts +8 -0
- package/dist/translations/gl.js +5 -0
- package/dist/translations/gl.umd.js +11 -0
- package/dist/translations/he.d.ts +8 -0
- package/dist/translations/he.js +5 -0
- package/dist/translations/he.umd.js +11 -0
- package/dist/translations/hi.d.ts +8 -0
- package/dist/translations/hi.js +5 -0
- package/dist/translations/hi.umd.js +11 -0
- package/dist/translations/hr.d.ts +8 -0
- package/dist/translations/hr.js +5 -0
- package/dist/translations/hr.umd.js +11 -0
- package/dist/translations/hu.d.ts +8 -0
- package/dist/translations/hu.js +5 -0
- package/dist/translations/hu.umd.js +11 -0
- package/dist/translations/id.d.ts +8 -0
- package/dist/translations/id.js +5 -0
- package/dist/translations/id.umd.js +11 -0
- package/dist/translations/it.d.ts +8 -0
- package/dist/translations/it.js +5 -0
- package/dist/translations/it.umd.js +11 -0
- package/dist/translations/ja.d.ts +8 -0
- package/dist/translations/ja.js +5 -0
- package/dist/translations/ja.umd.js +11 -0
- package/dist/translations/jv.d.ts +8 -0
- package/dist/translations/jv.js +5 -0
- package/dist/translations/jv.umd.js +11 -0
- package/dist/translations/ko.d.ts +8 -0
- package/dist/translations/ko.js +5 -0
- package/dist/translations/ko.umd.js +11 -0
- package/dist/translations/lt.d.ts +8 -0
- package/dist/translations/lt.js +5 -0
- package/dist/translations/lt.umd.js +11 -0
- package/dist/translations/lv.d.ts +8 -0
- package/dist/translations/lv.js +5 -0
- package/dist/translations/lv.umd.js +11 -0
- package/dist/translations/ms.d.ts +8 -0
- package/dist/translations/ms.js +5 -0
- package/dist/translations/ms.umd.js +11 -0
- package/dist/translations/nl.d.ts +8 -0
- package/dist/translations/nl.js +5 -0
- package/dist/translations/nl.umd.js +11 -0
- package/dist/translations/no.d.ts +8 -0
- package/dist/translations/no.js +5 -0
- package/dist/translations/no.umd.js +11 -0
- package/dist/translations/pl.d.ts +8 -0
- package/dist/translations/pl.js +5 -0
- package/dist/translations/pl.umd.js +11 -0
- package/dist/translations/pt-br.d.ts +8 -0
- package/dist/translations/pt-br.js +5 -0
- package/dist/translations/pt-br.umd.js +11 -0
- package/dist/translations/pt.d.ts +8 -0
- package/dist/translations/pt.js +5 -0
- package/dist/translations/pt.umd.js +11 -0
- package/dist/translations/ro.d.ts +8 -0
- package/dist/translations/ro.js +5 -0
- package/dist/translations/ro.umd.js +11 -0
- package/dist/translations/ru.d.ts +8 -0
- package/dist/translations/ru.js +5 -0
- package/dist/translations/ru.umd.js +11 -0
- package/dist/translations/sk.d.ts +8 -0
- package/dist/translations/sk.js +5 -0
- package/dist/translations/sk.umd.js +11 -0
- package/dist/translations/sr-latn.d.ts +8 -0
- package/dist/translations/sr-latn.js +5 -0
- package/dist/translations/sr-latn.umd.js +11 -0
- package/dist/translations/sr.d.ts +8 -0
- package/dist/translations/sr.js +5 -0
- package/dist/translations/sr.umd.js +11 -0
- package/dist/translations/sv.d.ts +8 -0
- package/dist/translations/sv.js +5 -0
- package/dist/translations/sv.umd.js +11 -0
- package/dist/translations/th.d.ts +8 -0
- package/dist/translations/th.js +5 -0
- package/dist/translations/th.umd.js +11 -0
- package/dist/translations/ti.d.ts +8 -0
- package/dist/translations/ti.js +5 -0
- package/dist/translations/ti.umd.js +11 -0
- package/dist/translations/tr.d.ts +8 -0
- package/dist/translations/tr.js +5 -0
- package/dist/translations/tr.umd.js +11 -0
- package/dist/translations/tt.d.ts +8 -0
- package/dist/translations/tt.js +5 -0
- package/dist/translations/tt.umd.js +11 -0
- package/dist/translations/ug.d.ts +8 -0
- package/dist/translations/ug.js +5 -0
- package/dist/translations/ug.umd.js +11 -0
- package/dist/translations/uk.d.ts +8 -0
- package/dist/translations/uk.js +5 -0
- package/dist/translations/uk.umd.js +11 -0
- package/dist/translations/ur.d.ts +8 -0
- package/dist/translations/ur.js +5 -0
- package/dist/translations/ur.umd.js +11 -0
- package/dist/translations/vi.d.ts +8 -0
- package/dist/translations/vi.js +5 -0
- package/dist/translations/vi.umd.js +11 -0
- package/dist/translations/zh-cn.d.ts +8 -0
- package/dist/translations/zh-cn.js +5 -0
- package/dist/translations/zh-cn.umd.js +11 -0
- package/dist/translations/zh.d.ts +8 -0
- package/dist/translations/zh.js +5 -0
- package/dist/translations/zh.umd.js +11 -0
- package/dist/ui/findandreplaceformview.d.ts +313 -0
- package/lang/contexts.json +16 -0
- package/lang/translations/af.po +74 -0
- package/lang/translations/ar.po +74 -0
- package/lang/translations/bg.po +74 -0
- package/lang/translations/bn.po +74 -0
- package/lang/translations/bs.po +74 -0
- package/lang/translations/ca.po +74 -0
- package/lang/translations/cs.po +74 -0
- package/lang/translations/da.po +74 -0
- package/lang/translations/de.po +74 -0
- package/lang/translations/el.po +74 -0
- package/lang/translations/en-au.po +74 -0
- package/lang/translations/en.po +74 -0
- package/lang/translations/es-co.po +74 -0
- package/lang/translations/es.po +74 -0
- package/lang/translations/et.po +74 -0
- package/lang/translations/fa.po +74 -0
- package/lang/translations/fi.po +74 -0
- package/lang/translations/fr.po +74 -0
- package/lang/translations/gl.po +74 -0
- package/lang/translations/he.po +74 -0
- package/lang/translations/hi.po +74 -0
- package/lang/translations/hr.po +74 -0
- package/lang/translations/hu.po +74 -0
- package/lang/translations/id.po +74 -0
- package/lang/translations/it.po +74 -0
- package/lang/translations/ja.po +74 -0
- package/lang/translations/jv.po +74 -0
- package/lang/translations/ko.po +74 -0
- package/lang/translations/lt.po +74 -0
- package/lang/translations/lv.po +74 -0
- package/lang/translations/ms.po +74 -0
- package/lang/translations/nl.po +74 -0
- package/lang/translations/no.po +74 -0
- package/lang/translations/pl.po +74 -0
- package/lang/translations/pt-br.po +74 -0
- package/lang/translations/pt.po +74 -0
- package/lang/translations/ro.po +74 -0
- package/lang/translations/ru.po +74 -0
- package/lang/translations/sk.po +74 -0
- package/lang/translations/sr-latn.po +74 -0
- package/lang/translations/sr.po +74 -0
- package/lang/translations/sv.po +74 -0
- package/lang/translations/th.po +74 -0
- package/lang/translations/ti.po +74 -0
- package/lang/translations/tr.po +74 -0
- package/lang/translations/tt.po +74 -0
- package/lang/translations/ug.po +74 -0
- package/lang/translations/uk.po +74 -0
- package/lang/translations/ur.po +74 -0
- package/lang/translations/vi.po +74 -0
- package/lang/translations/zh-cn.po +74 -0
- package/lang/translations/zh.po +74 -0
- package/package.json +42 -0
- package/src/augmentation.d.ts +20 -0
- package/src/augmentation.js +5 -0
- package/src/findandreplace.d.ts +46 -0
- package/src/findandreplace.js +90 -0
- package/src/findandreplaceconfig.d.ts +31 -0
- package/src/findandreplaceconfig.js +5 -0
- package/src/findandreplaceediting.d.ts +67 -0
- package/src/findandreplaceediting.js +233 -0
- package/src/findandreplacestate.d.ts +112 -0
- package/src/findandreplacestate.js +80 -0
- package/src/findandreplaceui.d.ts +83 -0
- package/src/findandreplaceui.js +275 -0
- package/src/findandreplaceutils.d.ts +73 -0
- package/src/findandreplaceutils.js +160 -0
- package/src/findcommand.d.ts +48 -0
- package/src/findcommand.js +79 -0
- package/src/findnextcommand.d.ts +35 -0
- package/src/findnextcommand.js +47 -0
- package/src/findpreviouscommand.d.ts +19 -0
- package/src/findpreviouscommand.js +25 -0
- package/src/index.d.ts +18 -0
- package/src/index.js +17 -0
- package/src/replaceallcommand.d.ts +35 -0
- package/src/replaceallcommand.js +50 -0
- package/src/replacecommand.d.ts +22 -0
- package/src/replacecommand.js +20 -0
- package/src/replacecommandbase.d.ts +31 -0
- package/src/replacecommandbase.js +56 -0
- package/src/ui/findandreplaceformview.d.ts +309 -0
- package/src/ui/findandreplaceformview.js +472 -0
- package/theme/findandreplace.css +13 -0
- package/theme/findandreplaceform.css +17 -0
- package/theme/icons/find-replace.svg +1 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module 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 'lodash-es';
|
|
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 default class FindAndReplaceEditing extends Plugin {
|
|
24
|
+
constructor() {
|
|
25
|
+
super(...arguments);
|
|
26
|
+
/**
|
|
27
|
+
* Reacts to document changes in order to update search list.
|
|
28
|
+
*/
|
|
29
|
+
this._onDocumentChange = () => {
|
|
30
|
+
const changedNodes = new Set();
|
|
31
|
+
const removedMarkers = new Set();
|
|
32
|
+
const model = this.editor.model;
|
|
33
|
+
const { results } = this.state;
|
|
34
|
+
const changes = model.document.differ.getChanges();
|
|
35
|
+
const changedMarkers = model.document.differ.getChangedMarkers();
|
|
36
|
+
// Get nodes in which changes happened to re-run a search callback on them.
|
|
37
|
+
changes.forEach(change => {
|
|
38
|
+
if (!change.position) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (change.name === '$text' || (change.position.nodeAfter && model.schema.isInline(change.position.nodeAfter))) {
|
|
42
|
+
changedNodes.add(change.position.parent);
|
|
43
|
+
[...model.markers.getMarkersAtPosition(change.position)].forEach(markerAtChange => {
|
|
44
|
+
removedMarkers.add(markerAtChange.name);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else if (change.type === 'insert' && change.position.nodeAfter) {
|
|
48
|
+
changedNodes.add(change.position.nodeAfter);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
// Get markers from removed nodes also.
|
|
52
|
+
changedMarkers.forEach(({ name, data: { newRange } }) => {
|
|
53
|
+
if (newRange && newRange.start.root.rootName === '$graveyard') {
|
|
54
|
+
removedMarkers.add(name);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Get markers from the updated nodes and remove all (search will be re-run on these nodes).
|
|
58
|
+
changedNodes.forEach(node => {
|
|
59
|
+
const markersInNode = [...model.markers.getMarkersIntersectingRange(model.createRangeIn(node))];
|
|
60
|
+
markersInNode.forEach(marker => removedMarkers.add(marker.name));
|
|
61
|
+
});
|
|
62
|
+
// Remove results from the changed part of content.
|
|
63
|
+
removedMarkers.forEach(markerName => {
|
|
64
|
+
if (!results.has(markerName)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (results.get(markerName) === this.state.highlightedResult) {
|
|
68
|
+
this.state.highlightedResult = null;
|
|
69
|
+
}
|
|
70
|
+
results.remove(markerName);
|
|
71
|
+
});
|
|
72
|
+
// Run search callback again on updated nodes.
|
|
73
|
+
const changedSearchResults = [];
|
|
74
|
+
const findAndReplaceUtils = this.editor.plugins.get('FindAndReplaceUtils');
|
|
75
|
+
changedNodes.forEach(nodeToCheck => {
|
|
76
|
+
const changedNodeSearchResults = findAndReplaceUtils.updateFindResultFromRange(model.createRangeOn(nodeToCheck), model, this.state.lastSearchCallback, results);
|
|
77
|
+
changedSearchResults.push(...changedNodeSearchResults);
|
|
78
|
+
});
|
|
79
|
+
changedMarkers.forEach(markerToCheck => {
|
|
80
|
+
// Handle search result highlight update when T&C plugin is active.
|
|
81
|
+
// Lookup is performed only on newly inserted markers.
|
|
82
|
+
if (markerToCheck.data.newRange) {
|
|
83
|
+
const changedNodeSearchResults = findAndReplaceUtils.updateFindResultFromRange(markerToCheck.data.newRange, model, this.state.lastSearchCallback, results);
|
|
84
|
+
changedSearchResults.push(...changedNodeSearchResults);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
if (!this.state.highlightedResult && changedSearchResults.length) {
|
|
88
|
+
// If there are found phrases but none is selected, select the first one.
|
|
89
|
+
this.state.highlightedResult = changedSearchResults[0];
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// If there is already highlight item then refresh highlight offset after appending new items.
|
|
93
|
+
this.state.refreshHighlightOffset();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @inheritDoc
|
|
99
|
+
*/
|
|
100
|
+
static get requires() {
|
|
101
|
+
return [FindAndReplaceUtils];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @inheritDoc
|
|
105
|
+
*/
|
|
106
|
+
static get pluginName() {
|
|
107
|
+
return 'FindAndReplaceEditing';
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @inheritDoc
|
|
111
|
+
*/
|
|
112
|
+
static get isOfficialPlugin() {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* @inheritDoc
|
|
117
|
+
*/
|
|
118
|
+
init() {
|
|
119
|
+
this.state = new FindAndReplaceState(this.editor.model);
|
|
120
|
+
this.set('_isSearchActive', false);
|
|
121
|
+
this._defineConverters();
|
|
122
|
+
this._defineCommands();
|
|
123
|
+
this.listenTo(this.state, 'change:highlightedResult', (eventInfo, name, newValue, oldValue) => {
|
|
124
|
+
const { model } = this.editor;
|
|
125
|
+
model.change(writer => {
|
|
126
|
+
if (oldValue) {
|
|
127
|
+
const oldMatchId = oldValue.marker.name.split(':')[1];
|
|
128
|
+
const oldMarker = model.markers.get(`findResultHighlighted:${oldMatchId}`);
|
|
129
|
+
if (oldMarker) {
|
|
130
|
+
writer.removeMarker(oldMarker);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (newValue) {
|
|
134
|
+
const newMatchId = newValue.marker.name.split(':')[1];
|
|
135
|
+
writer.addMarker(`findResultHighlighted:${newMatchId}`, {
|
|
136
|
+
usingOperation: false,
|
|
137
|
+
affectsData: false,
|
|
138
|
+
range: newValue.marker.getRange()
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
/* istanbul ignore next -- @preserve */
|
|
144
|
+
const scrollToHighlightedResult = (eventInfo, name, newValue) => {
|
|
145
|
+
if (newValue) {
|
|
146
|
+
const domConverter = this.editor.editing.view.domConverter;
|
|
147
|
+
const viewRange = this.editor.editing.mapper.toViewRange(newValue.marker.getRange());
|
|
148
|
+
scrollViewportToShowTarget({
|
|
149
|
+
target: domConverter.viewRangeToDom(viewRange),
|
|
150
|
+
viewportOffset: 40
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const debouncedScrollListener = debounce(scrollToHighlightedResult.bind(this), 32);
|
|
155
|
+
// Debounce scroll as highlight might be changed very frequently, e.g. when there's a replace all command.
|
|
156
|
+
this.listenTo(this.state, 'change:highlightedResult', debouncedScrollListener, { priority: 'low' });
|
|
157
|
+
// It's possible that the editor will get destroyed before debounced call kicks in.
|
|
158
|
+
// This would result with accessing a view three that is no longer in DOM.
|
|
159
|
+
this.listenTo(this.editor, 'destroy', debouncedScrollListener.cancel);
|
|
160
|
+
this.on('change:_isSearchActive', (evt, name, isSearchActive) => {
|
|
161
|
+
if (isSearchActive) {
|
|
162
|
+
this.listenTo(this.editor.model.document, 'change:data', this._onDocumentChange);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
this.stopListening(this.editor.model.document, 'change:data', this._onDocumentChange);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Initiate a search.
|
|
171
|
+
*/
|
|
172
|
+
find(callbackOrText, findAttributes) {
|
|
173
|
+
this._isSearchActive = true;
|
|
174
|
+
this.editor.execute('find', callbackOrText, findAttributes);
|
|
175
|
+
return this.state.results;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Stops active results from updating, and clears out the results.
|
|
179
|
+
*/
|
|
180
|
+
stop() {
|
|
181
|
+
this.state.clear(this.editor.model);
|
|
182
|
+
this._isSearchActive = false;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Sets up the commands.
|
|
186
|
+
*/
|
|
187
|
+
_defineCommands() {
|
|
188
|
+
this.editor.commands.add('find', new FindCommand(this.editor, this.state));
|
|
189
|
+
this.editor.commands.add('findNext', new FindNextCommand(this.editor, this.state));
|
|
190
|
+
this.editor.commands.add('findPrevious', new FindPreviousCommand(this.editor, this.state));
|
|
191
|
+
this.editor.commands.add('replace', new ReplaceCommand(this.editor, this.state));
|
|
192
|
+
this.editor.commands.add('replaceAll', new ReplaceAllCommand(this.editor, this.state));
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Sets up the marker downcast converters for search results highlighting.
|
|
196
|
+
*/
|
|
197
|
+
_defineConverters() {
|
|
198
|
+
const { editor } = this;
|
|
199
|
+
// Setup the marker highlighting conversion.
|
|
200
|
+
editor.conversion.for('editingDowncast').markerToHighlight({
|
|
201
|
+
model: 'findResult',
|
|
202
|
+
view: ({ markerName }) => {
|
|
203
|
+
const [, id] = markerName.split(':');
|
|
204
|
+
// Marker removal from the view has a bug: https://github.com/ckeditor/ckeditor5/issues/7499
|
|
205
|
+
// A minimal option is to return a new object for each converted marker...
|
|
206
|
+
return {
|
|
207
|
+
name: 'span',
|
|
208
|
+
classes: ['ck-find-result'],
|
|
209
|
+
attributes: {
|
|
210
|
+
// ...however, adding a unique attribute should be future-proof..
|
|
211
|
+
'data-find-result': id
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
editor.conversion.for('editingDowncast').markerToHighlight({
|
|
217
|
+
model: 'findResultHighlighted',
|
|
218
|
+
view: ({ markerName }) => {
|
|
219
|
+
const [, id] = markerName.split(':');
|
|
220
|
+
// Marker removal from the view has a bug: https://github.com/ckeditor/ckeditor5/issues/7499
|
|
221
|
+
// A minimal option is to return a new object for each converted marker...
|
|
222
|
+
return {
|
|
223
|
+
name: 'span',
|
|
224
|
+
classes: [HIGHLIGHT_CLASS],
|
|
225
|
+
attributes: {
|
|
226
|
+
// ...however, adding a unique attribute should be future-proof..
|
|
227
|
+
'data-find-result': id
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module find-and-replace/findandreplacestate
|
|
7
|
+
*/
|
|
8
|
+
import type { Model, Item } from 'ckeditor5/src/engine.js';
|
|
9
|
+
import { Collection } from 'ckeditor5/src/utils.js';
|
|
10
|
+
import type { ResultType } from './findandreplace.js';
|
|
11
|
+
declare const FindAndReplaceState_base: {
|
|
12
|
+
new (): import("ckeditor5/src/utils.js").Observable;
|
|
13
|
+
prototype: import("ckeditor5/src/utils.js").Observable;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The object storing find and replace plugin state for a given editor instance.
|
|
17
|
+
*/
|
|
18
|
+
export default class FindAndReplaceState extends /* #__PURE__ */ FindAndReplaceState_base {
|
|
19
|
+
/**
|
|
20
|
+
* A collection of find matches.
|
|
21
|
+
*
|
|
22
|
+
* @observable
|
|
23
|
+
*/
|
|
24
|
+
results: Collection<ResultType>;
|
|
25
|
+
/**
|
|
26
|
+
* Currently highlighted search result in {@link #results matched results}.
|
|
27
|
+
*
|
|
28
|
+
* @readonly
|
|
29
|
+
* @observable
|
|
30
|
+
*/
|
|
31
|
+
highlightedResult: ResultType | null;
|
|
32
|
+
/**
|
|
33
|
+
* Currently highlighted search result offset in {@link #results matched results}.
|
|
34
|
+
*
|
|
35
|
+
* @readonly
|
|
36
|
+
* @observable
|
|
37
|
+
*/
|
|
38
|
+
highlightedOffset: number;
|
|
39
|
+
/**
|
|
40
|
+
* Searched text value.
|
|
41
|
+
*
|
|
42
|
+
* @readonly
|
|
43
|
+
* @observable
|
|
44
|
+
*/
|
|
45
|
+
searchText: string;
|
|
46
|
+
/**
|
|
47
|
+
* The most recent search callback used by the feature to find matches.
|
|
48
|
+
* It is used to re-run the search when user modifies the editor content.
|
|
49
|
+
*
|
|
50
|
+
* @readonly
|
|
51
|
+
* @observable
|
|
52
|
+
*/
|
|
53
|
+
lastSearchCallback: FindCallback | null;
|
|
54
|
+
/**
|
|
55
|
+
* Replace text value.
|
|
56
|
+
*
|
|
57
|
+
* @readonly
|
|
58
|
+
* @observable
|
|
59
|
+
*/
|
|
60
|
+
replaceText: string;
|
|
61
|
+
/**
|
|
62
|
+
* Indicates whether the matchCase checkbox has been checked.
|
|
63
|
+
*
|
|
64
|
+
* @readonly
|
|
65
|
+
* @observable
|
|
66
|
+
*/
|
|
67
|
+
matchCase: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Indicates whether the matchWholeWords checkbox has been checked.
|
|
70
|
+
*
|
|
71
|
+
* @readonly
|
|
72
|
+
* @observable
|
|
73
|
+
*/
|
|
74
|
+
matchWholeWords: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Creates an instance of the state.
|
|
77
|
+
*/
|
|
78
|
+
constructor(model: Model);
|
|
79
|
+
/**
|
|
80
|
+
* Cleans the state up and removes markers from the model.
|
|
81
|
+
*/
|
|
82
|
+
clear(model: Model): void;
|
|
83
|
+
/**
|
|
84
|
+
* Refreshes the highlight result offset based on it's index within the result list.
|
|
85
|
+
*/
|
|
86
|
+
refreshHighlightOffset(): void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The callback function used to find matches in the document.
|
|
90
|
+
*/
|
|
91
|
+
export type FindCallback = ({ item, text }: {
|
|
92
|
+
item: Item;
|
|
93
|
+
text: string;
|
|
94
|
+
}) => FindCallbackResultObject | FindCallbackResult;
|
|
95
|
+
/**
|
|
96
|
+
* Represents the result of a find callback.
|
|
97
|
+
*
|
|
98
|
+
* The `searchText` attribute in the result object is used to determine if the search text has changed.
|
|
99
|
+
* If returned `searchText` is different than the last search text, the search results will be invalidated
|
|
100
|
+
* while searching for next item and the search will start from the beginning of the document.
|
|
101
|
+
*/
|
|
102
|
+
export type FindCallbackResultObject = {
|
|
103
|
+
results: Array<ResultType>;
|
|
104
|
+
searchText: string;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Represents the result of a find callback.
|
|
108
|
+
*
|
|
109
|
+
* @deprecated Use `FindCallbackResultObject` instead.
|
|
110
|
+
*/
|
|
111
|
+
export type FindCallbackResult = Array<ResultType>;
|
|
112
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
import { 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 default 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();
|
|
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() {
|
|
69
|
+
const { highlightedResult, results } = this;
|
|
70
|
+
const sortMapping = { before: -1, same: 0, after: 1, different: 1 };
|
|
71
|
+
if (highlightedResult) {
|
|
72
|
+
this.highlightedOffset = Array.from(results)
|
|
73
|
+
.sort((a, b) => sortMapping[a.marker.getStart().compareWith(b.marker.getStart())])
|
|
74
|
+
.indexOf(highlightedResult) + 1;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
this.highlightedOffset = 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module find-and-replace/findandreplaceui
|
|
7
|
+
*/
|
|
8
|
+
import { type Editor, Plugin } from 'ckeditor5/src/core.js';
|
|
9
|
+
import { Dialog, type ViewWithCssTransitionDisabler } from 'ckeditor5/src/ui.js';
|
|
10
|
+
import FindAndReplaceFormView from './ui/findandreplaceformview.js';
|
|
11
|
+
/**
|
|
12
|
+
* The default find and replace UI.
|
|
13
|
+
*
|
|
14
|
+
* It registers the `'findAndReplace'` UI button in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}.
|
|
15
|
+
* that uses the {@link module:find-and-replace/findandreplace~FindAndReplace FindAndReplace} plugin API.
|
|
16
|
+
*/
|
|
17
|
+
export default class FindAndReplaceUI extends Plugin {
|
|
18
|
+
/**
|
|
19
|
+
* @inheritDoc
|
|
20
|
+
*/
|
|
21
|
+
static get requires(): readonly [typeof Dialog];
|
|
22
|
+
/**
|
|
23
|
+
* @inheritDoc
|
|
24
|
+
*/
|
|
25
|
+
static get pluginName(): "FindAndReplaceUI";
|
|
26
|
+
/**
|
|
27
|
+
* @inheritDoc
|
|
28
|
+
*/
|
|
29
|
+
static get isOfficialPlugin(): true;
|
|
30
|
+
/**
|
|
31
|
+
* A reference to the find and replace form view.
|
|
32
|
+
*/
|
|
33
|
+
formView: FindAndReplaceFormView & ViewWithCssTransitionDisabler | null;
|
|
34
|
+
/**
|
|
35
|
+
* @inheritDoc
|
|
36
|
+
*/
|
|
37
|
+
constructor(editor: Editor);
|
|
38
|
+
/**
|
|
39
|
+
* @inheritDoc
|
|
40
|
+
*/
|
|
41
|
+
init(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a dropdown containing the find and replace form.
|
|
44
|
+
*/
|
|
45
|
+
private _createDropdown;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a button that opens a dialog with the find and replace form.
|
|
48
|
+
*/
|
|
49
|
+
private _createDialogButtonForToolbar;
|
|
50
|
+
/**
|
|
51
|
+
* Creates a button for for menu bar that will show find and replace dialog.
|
|
52
|
+
*/
|
|
53
|
+
private _createDialogButtonForMenuBar;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a button for find and replace command to use either in toolbar or in menu bar.
|
|
56
|
+
*/
|
|
57
|
+
private _createButton;
|
|
58
|
+
/**
|
|
59
|
+
* Shows the find and replace dialog.
|
|
60
|
+
*/
|
|
61
|
+
private _showDialog;
|
|
62
|
+
/**
|
|
63
|
+
* Sets up the form view for the find and replace.
|
|
64
|
+
*
|
|
65
|
+
* @param formView A related form view.
|
|
66
|
+
*/
|
|
67
|
+
private _createFormView;
|
|
68
|
+
/**
|
|
69
|
+
* Clears the find and replace form and focuses the search text field.
|
|
70
|
+
*/
|
|
71
|
+
private _setupFormView;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Fired when the UI was reset and the search results marked in the editing root should be invalidated,
|
|
75
|
+
* for instance, because the user changed the searched phrase (or options) but didn't hit
|
|
76
|
+
* the "Find" button yet.
|
|
77
|
+
*
|
|
78
|
+
* @eventName ~FindAndReplaceUI#searchReseted
|
|
79
|
+
*/
|
|
80
|
+
export type SearchResetedEvent = {
|
|
81
|
+
name: 'searchReseted';
|
|
82
|
+
args: [];
|
|
83
|
+
};
|