@@ -6,6 +6,8 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
66 useCtrlF = false ;
77 useCtrlH = false ;
88
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+
911 /**
1012 * Create a find-and-replace command plugin to pass into a template
1113 * @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 {
100102 } , 100 ) ;
101103 }
102104
103- /* Deal with Enter and Escape being pressed in the find field */
105+ /* Deal with Enter being pressed in the find field */
104106 checkFindPrompt ( dialog , codeInput , event ) {
105107 if ( event . key == 'Enter' ) {
106108 // Find next match
@@ -109,19 +111,28 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
109111 }
110112 }
111113
112- /* Deal with Enter and Escape being pressed in the replace field */
114+ /* Deal with Enter being pressed in the replace field */
113115 checkReplacePrompt ( dialog , codeInput , event ) {
114116 if ( event . key == 'Enter' ) {
115117 // Replace focused match
116118 dialog . findMatchState . replaceOnce ( dialog . replaceInput . value ) ;
119+ dialog . replaceInput . focus ( ) ;
117120 this . updateMatchDescription ( dialog ) ;
118121 }
119122 }
120123
121124 /* Called with a dialog box keyup event to close and clear the dialog box */
122125 cancelPrompt ( dialog , codeInput , event ) {
123126 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+
125136 // Reset original selection in code-input
126137 dialog . textarea . focus ( ) ;
127138 if ( dialog . findMatchState . numMatches > 0 ) {
@@ -146,10 +157,11 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
146157 * @param {boolean } replacePartExpanded whether the replace part of the find-and-replace dialog should be expanded
147158 */
148159 showPrompt ( codeInputElement , replacePartExpanded ) {
160+ let dialog ;
149161 if ( codeInputElement . pluginData . findAndReplace == undefined || codeInputElement . pluginData . findAndReplace . dialog == undefined ) {
150162 const textarea = codeInputElement . textareaElement ;
151163
152- const dialog = document . createElement ( 'div' ) ;
164+ dialog = document . createElement ( 'div' ) ;
153165 const findInput = document . createElement ( 'input' ) ;
154166 const findCaseSensitiveCheckbox = document . createElement ( 'input' ) ;
155167 const findRegExpCheckbox = document . createElement ( 'input' ) ;
@@ -229,7 +241,7 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
229241 event . preventDefault ( ) ;
230242
231243 dialog . findMatchState . replaceOnce ( replaceInput . value ) ;
232- replaceButton . focus ( ) ;
244+ dialog . focus ( ) ;
233245 } ) ;
234246 replaceAllButton . addEventListener ( "click" , ( event ) => {
235247 // Stop form submit
@@ -275,14 +287,30 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
275287 /* Stop enter from submitting form */
276288 if ( event . key == 'Enter' ) event . preventDefault ( ) ;
277289 } ) ;
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+ } ) ;
278300
279301 dialog . addEventListener ( 'keyup' , ( event ) => {
280302 /* Close prompt on Enter pressed */
281303 if ( event . key == 'Escape' ) this . cancelPrompt ( dialog , codeInputElement , event ) ;
282304 } ) ;
283305
284306 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+ } ) ;
286314 findCaseSensitiveCheckbox . addEventListener ( 'click' , ( event ) => { this . updateFindMatches ( dialog ) ; } ) ;
287315 findRegExpCheckbox . addEventListener ( 'click' , ( event ) => { this . updateFindMatches ( dialog ) ; } ) ;
288316
@@ -303,24 +331,42 @@ codeInput.plugins.FindAndReplace = class extends codeInput.Plugin {
303331 // Save selection position
304332 dialog . selectionStart = codeInputElement . textareaElement . selectionStart ;
305333 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+ }
306343 } else {
344+ dialog = codeInputElement . pluginData . findAndReplace . dialog ;
307345 // 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 ( ) ;
310348 if ( replacePartExpanded ) {
311- codeInputElement . pluginData . findAndReplace . dialog . replaceDropdown . setAttribute ( "open" , true ) ;
349+ dialog . replaceDropdown . setAttribute ( "open" , true ) ;
312350 } else {
313- codeInputElement . pluginData . findAndReplace . dialog . replaceDropdown . removeAttribute ( "open" ) ;
351+ dialog . replaceDropdown . removeAttribute ( "open" ) ;
314352 }
353+ }
315354
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 ) ;
323366 }
367+
368+ // Highlight matches
369+ this . updateFindMatches ( dialog ) ;
324370 }
325371
326372 /* Event handler for keydown event that makes Ctrl+F open find dialog */
0 commit comments