@@ -6,6 +6,8 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
6
6
useCtrlF = false ;
7
7
useCtrlH = false ;
8
8
9
+ findMatchesOnValueChange = true ; // Needed so the program can insert text to the find value and thus add it to Ctrl+Z without highlighting matches.
10
+
9
11
/**
10
12
* Create a find-and-replace command plugin to pass into a template
11
13
* @param {boolean } useCtrlF Should Ctrl+F be overriden for find-and-replace find functionality? If not, you can trigger it yourself using (instance of this plugin)`.showPrompt(code-input element, false)`.
@@ -100,7 +102,7 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
100
102
} , 100 ) ;
101
103
}
102
104
103
- /* Deal with Enter and Escape being pressed in the find field */
105
+ /* Deal with Enter being pressed in the find field */
104
106
checkFindPrompt ( dialog , codeInput , event ) {
105
107
if ( event . key == 'Enter' ) {
106
108
// Find next match
@@ -109,19 +111,28 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
109
111
}
110
112
}
111
113
112
- /* Deal with Enter and Escape being pressed in the replace field */
114
+ /* Deal with Enter being pressed in the replace field */
113
115
checkReplacePrompt ( dialog , codeInput , event ) {
114
116
if ( event . key == 'Enter' ) {
115
117
// Replace focused match
116
118
dialog . findMatchState . replaceOnce ( dialog . replaceInput . value ) ;
119
+ dialog . replaceInput . focus ( ) ;
117
120
this . updateMatchDescription ( dialog ) ;
118
121
}
119
122
}
120
123
121
124
/* Called with a dialog box keyup event to close and clear the dialog box */
122
125
cancelPrompt ( dialog , codeInput , event ) {
123
126
event . preventDefault ( ) ;
124
-
127
+
128
+ // Add current value of find/replace to Ctrl+Z stack.
129
+ this . findMatchesOnValueChange = false ;
130
+ dialog . findInput . focus ( ) ;
131
+ dialog . findInput . selectionStart = 0 ;
132
+ dialog . findInput . selectionEnd = dialog . findInput . value . length ;
133
+ document . execCommand ( "insertText" , false , dialog . findInput . value ) ;
134
+ this . findMatchesOnValueChange = true ;
135
+
125
136
// Reset original selection in code-input
126
137
dialog . textarea . focus ( ) ;
127
138
if ( dialog . findMatchState . numMatches > 0 ) {
@@ -146,10 +157,11 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
146
157
* @param {boolean } replacePartExpanded whether the replace part of the find-and-replace dialog should be expanded
147
158
*/
148
159
showPrompt ( codeInputElement , replacePartExpanded ) {
160
+ let dialog ;
149
161
if ( codeInputElement . pluginData . findAndReplace == undefined || codeInputElement . pluginData . findAndReplace . dialog == undefined ) {
150
162
const textarea = codeInputElement . textareaElement ;
151
163
152
- const dialog = document . createElement ( 'div' ) ;
164
+ dialog = document . createElement ( 'div' ) ;
153
165
const findInput = document . createElement ( 'input' ) ;
154
166
const findCaseSensitiveCheckbox = document . createElement ( 'input' ) ;
155
167
const findRegExpCheckbox = document . createElement ( 'input' ) ;
@@ -229,7 +241,7 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
229
241
event . preventDefault ( ) ;
230
242
231
243
dialog . findMatchState . replaceOnce ( replaceInput . value ) ;
232
- replaceButton . focus ( ) ;
244
+ dialog . focus ( ) ;
233
245
} ) ;
234
246
replaceAllButton . addEventListener ( "click" , ( event ) => {
235
247
// Stop form submit
@@ -275,14 +287,30 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
275
287
/* Stop enter from submitting form */
276
288
if ( event . key == 'Enter' ) event . preventDefault ( ) ;
277
289
} ) ;
290
+ replaceInput . addEventListener ( 'input' , ( event ) => {
291
+ // Ctrl+Z can trigger this. If the dialog/replace dropdown aren't open, open them!
292
+ if ( dialog . classList . contains ( "code-input_find-and-replace_hidden-dialog" ) ) {
293
+ // Show prompt
294
+ this . showPrompt ( dialog . codeInput , true ) ;
295
+ } else if ( ! dialog . replaceDropdown . hasAttribute ( "open" ) ) {
296
+ // Open dropdown
297
+ dialog . replaceDropdown . setAttribute ( "open" , true ) ;
298
+ }
299
+ } ) ;
278
300
279
301
dialog . addEventListener ( 'keyup' , ( event ) => {
280
302
/* Close prompt on Enter pressed */
281
303
if ( event . key == 'Escape' ) this . cancelPrompt ( dialog , codeInputElement , event ) ;
282
304
} ) ;
283
305
284
306
findInput . addEventListener ( 'keyup' , ( event ) => { this . checkFindPrompt ( dialog , codeInputElement , event ) ; } ) ;
285
- findInput . addEventListener ( 'input' , ( event ) => { this . updateFindMatches ( dialog ) ; } ) ;
307
+ findInput . addEventListener ( 'input' , ( event ) => {
308
+ if ( this . findMatchesOnValueChange ) this . updateFindMatches ( dialog ) ;
309
+ // Ctrl+Z can trigger this. If the dialog isn't open, open it!
310
+ if ( dialog . classList . contains ( "code-input_find-and-replace_hidden-dialog" ) ) {
311
+ this . showPrompt ( dialog . codeInput , false ) ;
312
+ }
313
+ } ) ;
286
314
findCaseSensitiveCheckbox . addEventListener ( 'click' , ( event ) => { this . updateFindMatches ( dialog ) ; } ) ;
287
315
findRegExpCheckbox . addEventListener ( 'click' , ( event ) => { this . updateFindMatches ( dialog ) ; } ) ;
288
316
@@ -303,24 +331,42 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
303
331
// Save selection position
304
332
dialog . selectionStart = codeInputElement . textareaElement . selectionStart ;
305
333
dialog . selectionEnd = codeInputElement . textareaElement . selectionEnd ;
334
+
335
+ if ( dialog . selectionStart < dialog . selectionEnd ) {
336
+ // Copy selected text to Find input
337
+ let textToFind = codeInputElement . textareaElement . value . substring ( dialog . selectionStart , dialog . selectionEnd ) ;
338
+ dialog . findInput . focus ( ) ;
339
+ dialog . findInput . selectionStart = 0 ;
340
+ dialog . findInput . selectionEnd = dialog . findInput . value . length ;
341
+ document . execCommand ( "insertText" , false , textToFind ) ;
342
+ }
306
343
} else {
344
+ dialog = codeInputElement . pluginData . findAndReplace . dialog ;
307
345
// Re-open dialog
308
- codeInputElement . pluginData . findAndReplace . dialog . classList . remove ( "code-input_find-and-replace_hidden-dialog" ) ;
309
- codeInputElement . pluginData . findAndReplace . dialog . findInput . focus ( ) ;
346
+ dialog . classList . remove ( "code-input_find-and-replace_hidden-dialog" ) ;
347
+ dialog . findInput . focus ( ) ;
310
348
if ( replacePartExpanded ) {
311
- codeInputElement . pluginData . findAndReplace . dialog . replaceDropdown . setAttribute ( "open" , true ) ;
349
+ dialog . replaceDropdown . setAttribute ( "open" , true ) ;
312
350
} else {
313
- codeInputElement . pluginData . findAndReplace . dialog . replaceDropdown . removeAttribute ( "open" ) ;
351
+ dialog . replaceDropdown . removeAttribute ( "open" ) ;
314
352
}
353
+ }
315
354
316
-
317
- // Highlight matches
318
- this . updateFindMatches ( codeInputElement . pluginData . findAndReplace . dialog ) ;
319
-
320
- // Save selection position
321
- codeInputElement . pluginData . findAndReplace . dialog . selectionStart = codeInputElement . textareaElement . selectionStart ;
322
- codeInputElement . pluginData . findAndReplace . dialog . selectionEnd = codeInputElement . textareaElement . selectionEnd ;
355
+ // Save selection position
356
+ dialog . selectionStart = codeInputElement . textareaElement . selectionStart ;
357
+ dialog . selectionEnd = codeInputElement . textareaElement . selectionEnd ;
358
+
359
+ if ( dialog . selectionStart < dialog . selectionEnd ) {
360
+ // Copy selected text to Find input
361
+ let textToFind = codeInputElement . textareaElement . value . substring ( dialog . selectionStart , dialog . selectionEnd ) ;
362
+ dialog . findInput . focus ( ) ;
363
+ dialog . findInput . selectionStart = 0 ;
364
+ dialog . findInput . selectionEnd = dialog . findInput . value . length ;
365
+ document . execCommand ( "insertText" , false , textToFind ) ;
323
366
}
367
+
368
+ // Highlight matches
369
+ this . updateFindMatches ( dialog ) ;
324
370
}
325
371
326
372
/* Event handler for keydown event that makes Ctrl+F open find dialog */
0 commit comments