@ckeditor/ckeditor5-find-and-replace 30.0.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 +17 -0
- package/README.md +20 -0
- package/build/find-and-replace.js +5 -0
- package/build/translations/de.js +1 -0
- package/build/translations/gl.js +1 -0
- package/build/translations/hu.js +1 -0
- package/build/translations/it.js +1 -0
- package/build/translations/nl.js +1 -0
- package/build/translations/no.js +1 -0
- package/build/translations/ru.js +1 -0
- package/build/translations/sr-latn.js +1 -0
- package/build/translations/sr.js +1 -0
- package/build/translations/zh-cn.js +1 -0
- package/ckeditor5-metadata.json +18 -0
- package/lang/contexts.json +15 -0
- package/lang/translations/de.po +69 -0
- package/lang/translations/en.po +69 -0
- package/lang/translations/gl.po +69 -0
- package/lang/translations/hu.po +69 -0
- package/lang/translations/it.po +69 -0
- package/lang/translations/nl.po +69 -0
- package/lang/translations/no.po +69 -0
- package/lang/translations/ru.po +69 -0
- package/lang/translations/sr-latn.po +69 -0
- package/lang/translations/sr.po +69 -0
- package/lang/translations/zh-cn.po +69 -0
- package/package.json +62 -0
- package/src/findandreplace.js +97 -0
- package/src/findandreplaceediting.js +254 -0
- package/src/findandreplacestate.js +131 -0
- package/src/findandreplaceui.js +202 -0
- package/src/findcommand.js +95 -0
- package/src/findnextcommand.js +67 -0
- package/src/findpreviouscommand.js +31 -0
- package/src/index.js +10 -0
- package/src/replaceallcommand.js +61 -0
- package/src/replacecommand.js +69 -0
- package/src/ui/findandreplaceformview.js +827 -0
- package/src/utils.js +166 -0
- package/theme/findandreplace.css +13 -0
- package/theme/findandreplaceform.css +17 -0
- package/theme/icons/find-replace.svg +1 -0
package/src/utils.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @module find-and-replace/utils
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { uid, Collection } from 'ckeditor5/src/utils';
|
|
11
|
+
import { escapeRegExp } from 'lodash-es';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Executes findCallback and updates search results list.
|
|
15
|
+
*
|
|
16
|
+
* @param {module:engine/model/range~Range} range The model range to scan for matches.
|
|
17
|
+
* @param {module:engine/model/model~Model} model The model.
|
|
18
|
+
* @param {Function} findCallback The callback that should return `true` if provided text matches the search term.
|
|
19
|
+
* @param {module:utils/collection~Collection} [startResults] An optional collection of find matches that the function should
|
|
20
|
+
* start with. This would be a collection returned by a previous `updateFindResultFromRange()` call.
|
|
21
|
+
* @returns {module:utils/collection~Collection} A collection of objects describing find match.
|
|
22
|
+
*
|
|
23
|
+
* An example structure:
|
|
24
|
+
*
|
|
25
|
+
* ```js
|
|
26
|
+
* {
|
|
27
|
+
* id: resultId,
|
|
28
|
+
* label: foundItem.label,
|
|
29
|
+
* marker
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function updateFindResultFromRange( range, model, findCallback, startResults ) {
|
|
34
|
+
const results = startResults || new Collection();
|
|
35
|
+
|
|
36
|
+
model.change( writer => {
|
|
37
|
+
[ ...range ].forEach( ( { type, item } ) => {
|
|
38
|
+
if ( type === 'elementStart' ) {
|
|
39
|
+
if ( model.schema.checkChild( item, '$text' ) ) {
|
|
40
|
+
const foundItems = findCallback( {
|
|
41
|
+
item,
|
|
42
|
+
text: rangeToText( model.createRangeIn( item ) )
|
|
43
|
+
} );
|
|
44
|
+
|
|
45
|
+
if ( !foundItems ) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
foundItems.forEach( foundItem => {
|
|
50
|
+
const resultId = `findResult:${ uid() }`;
|
|
51
|
+
const marker = writer.addMarker( resultId, {
|
|
52
|
+
usingOperation: false,
|
|
53
|
+
affectsData: false,
|
|
54
|
+
range: writer.createRange(
|
|
55
|
+
writer.createPositionAt( item, foundItem.start ),
|
|
56
|
+
writer.createPositionAt( item, foundItem.end )
|
|
57
|
+
)
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
const index = findInsertIndex( results, marker );
|
|
61
|
+
|
|
62
|
+
results.add(
|
|
63
|
+
{
|
|
64
|
+
id: resultId,
|
|
65
|
+
label: foundItem.label,
|
|
66
|
+
marker
|
|
67
|
+
},
|
|
68
|
+
index
|
|
69
|
+
);
|
|
70
|
+
} );
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} );
|
|
74
|
+
} );
|
|
75
|
+
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Returns text representation of a range. The returned text length should be the same as range length.
|
|
81
|
+
* In order to achieve this this function will replace inline elements (text-line) as new line character ("\n").
|
|
82
|
+
*
|
|
83
|
+
* @param {module:engine/model/range~Range} range The model range.
|
|
84
|
+
* @returns {String} The text content of the provided range.
|
|
85
|
+
*/
|
|
86
|
+
export function rangeToText( range ) {
|
|
87
|
+
return Array.from( range.getItems() ).reduce( ( rangeText, node ) => {
|
|
88
|
+
// Trim text to a last occurrence of an inline element and update range start.
|
|
89
|
+
if ( !( node.is( 'text' ) || node.is( 'textProxy' ) ) ) {
|
|
90
|
+
// Editor has only one inline element defined in schema: `<softBreak>` which is treated as new line character in blocks.
|
|
91
|
+
// Special handling might be needed for other inline elements (inline widgets).
|
|
92
|
+
return `${ rangeText }\n`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return rangeText + node.data;
|
|
96
|
+
}, '' );
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Finds the appropriate index in the resultsList Collection.
|
|
100
|
+
function findInsertIndex( resultsList, markerToInsert ) {
|
|
101
|
+
const result = resultsList.find( ( { marker } ) => {
|
|
102
|
+
return markerToInsert.getStart().isBefore( marker.getStart() );
|
|
103
|
+
} );
|
|
104
|
+
|
|
105
|
+
return result ? resultsList.getIndex( result ) : resultsList.length;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Maps RegExp match result to find result.
|
|
109
|
+
function regexpMatchToFindResult( matchResult ) {
|
|
110
|
+
const lastGroupIndex = matchResult.length - 1;
|
|
111
|
+
|
|
112
|
+
let startOffset = matchResult.index;
|
|
113
|
+
|
|
114
|
+
// Searches with match all flag have an extra matching group with empty string or white space matched before the word.
|
|
115
|
+
// If the search term starts with the space already, there is no extra group even with match all flag on.
|
|
116
|
+
if ( matchResult.length === 3 ) {
|
|
117
|
+
startOffset += matchResult[ 1 ].length;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
label: matchResult[ lastGroupIndex ],
|
|
122
|
+
start: startOffset,
|
|
123
|
+
end: startOffset + matchResult[ lastGroupIndex ].length
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Creates a text matching callback for a specified search term and matching options.
|
|
129
|
+
*
|
|
130
|
+
* @param {String} searchTerm The search term.
|
|
131
|
+
* @param {Object} [options] Matching options.
|
|
132
|
+
* @param {Boolean} [options.matchCase=false] If set to `true` letter casing will be ignored.
|
|
133
|
+
* @param {Boolean} [options.wholeWords=false] If set to `true` only whole words that match `callbackOrText` will be matched.
|
|
134
|
+
* @returns {Function}
|
|
135
|
+
*/
|
|
136
|
+
export function findByTextCallback( searchTerm, options ) {
|
|
137
|
+
let flags = 'gu';
|
|
138
|
+
|
|
139
|
+
if ( !options.matchCase ) {
|
|
140
|
+
flags += 'i';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let regExpQuery = `(${ escapeRegExp( searchTerm ) })`;
|
|
144
|
+
|
|
145
|
+
if ( options.wholeWords ) {
|
|
146
|
+
const nonLetterGroup = '[^a-zA-Z\u00C0-\u024F\u1E00-\u1EFF]';
|
|
147
|
+
|
|
148
|
+
if ( !new RegExp( '^' + nonLetterGroup ).test( searchTerm ) ) {
|
|
149
|
+
regExpQuery = `(^|${ nonLetterGroup }|_)${ regExpQuery }`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if ( !new RegExp( nonLetterGroup + '$' ).test( searchTerm ) ) {
|
|
153
|
+
regExpQuery = `${ regExpQuery }(?:_|${ nonLetterGroup }|$)`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const regExp = new RegExp( regExpQuery, flags );
|
|
158
|
+
|
|
159
|
+
function findCallback( { text } ) {
|
|
160
|
+
const matches = [ ...text.matchAll( regExp ) ];
|
|
161
|
+
|
|
162
|
+
return matches.map( regexpMatchToFindResult );
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return findCallback;
|
|
166
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.ck-find-result {
|
|
7
|
+
background: hsl(60, 100%, 50%);
|
|
8
|
+
color: var(--ck-color-text);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.ck-find-result_selected {
|
|
12
|
+
background: hsl(29, 100%, 60%);
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.ck.ck-find-and-replace-form {
|
|
7
|
+
max-width: 100%;
|
|
8
|
+
|
|
9
|
+
& fieldset {
|
|
10
|
+
display: flex;
|
|
11
|
+
|
|
12
|
+
/* The find fieldset */
|
|
13
|
+
&.ck-find-and-replace-form__find .ck-results-counter {
|
|
14
|
+
position: absolute;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m12.87 13.786 1.532-1.286 3.857 4.596a1 1 0 1 1-1.532 1.286l-3.857-4.596z"/><path d="M16.004 8.5a6.5 6.5 0 0 1-9.216 5.905c-1.154-.53-.863-1.415-.663-1.615.194-.194.564-.592 1.635-.141a4.5 4.5 0 0 0 5.89-5.904l-.104-.227 1.332-1.331c.045-.046.196-.041.224.007a6.47 6.47 0 0 1 .902 3.306zm-3.4-5.715c.562.305.742 1.106.354 1.494-.388.388-.995.414-1.476.178a4.5 4.5 0 0 0-6.086 5.882l.114.236-1.348 1.349c-.038.037-.17.022-.198-.023a6.5 6.5 0 0 1 5.54-9.9 6.469 6.469 0 0 1 3.1.784z"/><path d="M4.001 11.93.948 8.877a.2.2 0 0 1 .141-.341h6.106a.2.2 0 0 1 .141.341L4.283 11.93a.2.2 0 0 1-.282 0zm11.083-6.789 3.053 3.053a.2.2 0 0 1-.14.342H11.89a.2.2 0 0 1-.14-.342l3.052-3.053a.2.2 0 0 1 .282 0z"/></svg>
|