@@ -18,13 +18,15 @@ import upArrow from '../images/up-arrow.svg?byContent';
1818import exitIcon from '../images/exit.svg?byContent' ;
1919
2020function searchOverlay ( query , caseInsensitive ) {
21- if ( typeof query == 'string' )
21+ // if the query is a string, we need to convert it into a regular expression
22+ if ( typeof query == 'string' ) {
2223 query = new RegExp (
2324 query . replace ( / [ \- \[ \] \/ \{ \} \( \) \* \+ \? \. \\ \^ \$ \| ] / g, '\\$&' ) ,
2425 caseInsensitive ? 'gi' : 'g'
2526 ) ;
26- else if ( ! query . global )
27+ } else if ( ! query . global ) {
2728 query = new RegExp ( query . source , query . ignoreCase ? 'gi' : 'g' ) ;
29+ }
2830
2931 return {
3032 token : function ( stream ) {
@@ -42,13 +44,15 @@ function searchOverlay(query, caseInsensitive) {
4244 } ;
4345}
4446
47+ // SearchState is a constructor function that initializes an object to keep track of search-related settings
4548function SearchState ( ) {
4649 this . posFrom = this . posTo = this . lastQuery = this . query = null ;
4750 this . overlay = null ;
4851 this . regexp = false ;
4952 this . caseInsensitive = true ;
5053 this . wholeWord = false ;
5154 this . replaceStarted = false ;
55+ this . lastFileName = 'sketch.js' ;
5256}
5357
5458function getSearchState ( cm ) {
@@ -60,6 +64,51 @@ function getSearchCursor(cm, query, pos) {
6064 return cm . getSearchCursor ( query , pos , getSearchState ( cm ) . caseInsensitive ) ;
6165}
6266
67+ function watchFileChanges ( cm , searchState , searchField ) {
68+ let observer = null ;
69+
70+ function setupObserver ( ) {
71+ var fileNameElement = document . querySelector ( '.editor__file-name span' ) ;
72+
73+ if ( ! fileNameElement ) {
74+ setTimeout ( setupObserver , 500 ) ;
75+ return ;
76+ }
77+
78+ if ( observer ) {
79+ return ;
80+ }
81+
82+ observer = new MutationObserver ( ( ) => {
83+ if ( searchField . value . length > 1 ) {
84+ startSearch ( cm , searchState , searchField . value ) ;
85+ }
86+ } ) ;
87+
88+ observer . observe ( fileNameElement , { characterData : true , subtree : true } ) ;
89+ }
90+
91+ function disconnectObserver ( ) {
92+ if ( observer ) {
93+ observer . disconnect ( ) ;
94+ observer = null ;
95+ }
96+ }
97+
98+ setupObserver ( ) ;
99+
100+ // continuously check for the dialog's existence (every 500ms)
101+ setInterval ( ( ) => {
102+ var searchDialog = document . querySelector ( '.CodeMirror-dialog' ) ;
103+ if ( ! searchDialog && observer ) {
104+ disconnectObserver ( ) ;
105+ return ;
106+ } else if ( searchDialog && ! observer ) {
107+ setupObserver ( ) ;
108+ }
109+ } , 500 ) ;
110+ }
111+
63112function isMouseClick ( event ) {
64113 if ( event . detail > 0 ) return true ;
65114 else return false ;
@@ -88,6 +137,9 @@ function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {
88137
89138 var state = getSearchState ( cm ) ;
90139
140+ watchFileChanges ( cm , getSearchState ( cm ) , searchField ) ;
141+
142+ // this runs when the user types in the search box
91143 CodeMirror . on ( searchField , 'keyup' , function ( e ) {
92144 state . replaceStarted = false ;
93145 if ( e . keyCode !== 13 && searchField . value . length > 1 ) {
@@ -101,8 +153,8 @@ function persistentDialog(cm, text, deflt, onEnter, replaceOpened, onKeyDown) {
101153 } ) ;
102154
103155 CodeMirror . on ( closeButton , 'click' , function ( ) {
104- clearSearch ( cm ) ;
105156 dialog . parentNode . removeChild ( dialog ) ;
157+ clearSearch ( cm ) ;
106158 cm . focus ( ) ;
107159 } ) ;
108160
@@ -349,44 +401,66 @@ function parseQuery(query, state) {
349401}
350402
351403function startSearch ( cm , state , query ) {
352- state . queryText = query ;
353- state . lastQuery = query ;
354- state . query = parseQuery ( query , state ) ;
355- cm . removeOverlay ( state . overlay , state . caseInsensitive ) ;
356- state . overlay = searchOverlay ( state . query , state . caseInsensitive ) ;
357- cm . addOverlay ( state . overlay ) ;
358- if ( cm . showMatchesOnScrollbar ) {
359- if ( state . annotate ) {
360- state . annotate . clear ( ) ;
361- state . annotate = null ;
404+ var searchDialog = document . querySelector ( '.CodeMirror-dialog' ) ;
405+ if ( searchDialog ) {
406+ // check if the file has changed
407+ let currentFileName = document . querySelector ( '.editor__file-name span' )
408+ ?. innerText ;
409+
410+ if ( state . lastFileName !== currentFileName ) {
411+ state . lastFileName = currentFileName ; // update stored filename
412+ state . queryText = null ;
413+ state . lastQuery = null ;
414+ state . query = null ;
415+ cm . removeOverlay ( state . overlay ) ;
416+ state . overlay = null ;
417+
418+ if ( searchDialog ) {
419+ cm . display . wrapper . querySelector (
420+ '.CodeMirror-search-results'
421+ ) . innerText = '0/0' ;
422+ }
362423 }
363- state . annotate = cm . showMatchesOnScrollbar (
364- state . query ,
365- state . caseInsensitive
366- ) ;
367- }
368424
369- //Updating the UI everytime the search input changes
370- var cursor = getSearchCursor ( cm , state . query ) ;
371- cursor . findNext ( ) ;
372- var num_match = cm . state . search . annotate . matches . length ;
373- //no matches found
374- if ( num_match == 0 ) {
375- cm . display . wrapper . querySelector (
376- '.CodeMirror-search-results'
377- ) . innerText = i18n . t ( 'CodemirrorFindAndReplace.NoResults' ) ;
425+ state . queryText = query ;
426+ state . lastQuery = query ;
427+ state . query = parseQuery ( query , state ) ;
378428 cm . removeOverlay ( state . overlay , state . caseInsensitive ) ;
379- } else {
380- var next =
381- cm . state . search . annotate . matches . findIndex ( ( s ) => {
382- return (
383- s . from . ch === cursor . from ( ) . ch && s . from . line === cursor . from ( ) . line
384- ) ;
385- } ) + 1 ;
386- var text_match = next + '/' + num_match ;
387- cm . display . wrapper . querySelector (
388- '.CodeMirror-search-results'
389- ) . innerText = text_match ;
429+ state . overlay = searchOverlay ( state . query , state . caseInsensitive ) ;
430+ cm . addOverlay ( state . overlay ) ;
431+ if ( cm . showMatchesOnScrollbar ) {
432+ if ( state . annotate ) {
433+ state . annotate . clear ( ) ;
434+ state . annotate = null ;
435+ }
436+ state . annotate = cm . showMatchesOnScrollbar (
437+ state . query ,
438+ state . caseInsensitive
439+ ) ;
440+ }
441+
442+ // Updating the UI everytime the search input changes
443+ var cursor = getSearchCursor ( cm , state . query ) ;
444+ cursor . findNext ( ) ;
445+ var num_match = cm . state . search . annotate . matches . length ;
446+ // no matches found
447+ if ( num_match == 0 ) {
448+ cm . display . wrapper . querySelector (
449+ '.CodeMirror-search-results'
450+ ) . innerText = i18n . t ( 'CodemirrorFindAndReplace.NoResults' ) ;
451+ cm . removeOverlay ( state . overlay , state . caseInsensitive ) ; // removes any existing search highlights
452+ } else {
453+ var next =
454+ cm . state . search . annotate . matches . findIndex ( ( s ) => {
455+ return (
456+ s . from . ch === cursor . from ( ) . ch && s . from . line === cursor . from ( ) . line
457+ ) ;
458+ } ) + 1 ;
459+ var text_match = next + '/' + num_match ;
460+ cm . display . wrapper . querySelector (
461+ '.CodeMirror-search-results'
462+ ) . innerText = text_match ;
463+ }
390464 }
391465}
392466
0 commit comments