@@ -106,14 +106,20 @@ define(function (require, exports, module) {
106106 $searchContent ,
107107 $selectedRow ;
108108
109-
109+ /** @type {FindInFilesDialog } dialog having the modalbar for search */
110+ var dialog = null ;
111+
110112 /**
111113 * @private
112114 * Returns a regular expression from the given query and shows an error in the modal-bar if it was invalid
113115 * @param {string } query The query from the modal-bar input
114116 * @return {RegExp }
115117 */
116118 function _getQueryRegExp ( query ) {
119+ if ( ! query ) {
120+ return null ;
121+ }
122+
117123 // Clear any pending RegEx error message
118124 $ ( ".modal-bar .message" ) . css ( "display" , "inline-block" ) ;
119125 $ ( ".modal-bar .error" ) . css ( "display" , "none" ) ;
@@ -162,83 +168,7 @@ define(function (require, exports, module) {
162168 return Strings . FIND_IN_FILES_NO_SCOPE ;
163169 }
164170 }
165-
166-
167- // This dialog class was mostly copied from QuickOpen. We should have a common dialog
168- // class that everyone can use.
169-
170- /**
171- * FindInFilesDialog class
172- * @constructor
173- */
174- function FindInFilesDialog ( ) {
175- this . closed = false ;
176- this . result = null ; // $.Deferred
177- }
178171
179- /**
180- * Closes the search dialog and resolves the promise that showDialog returned
181- */
182- FindInFilesDialog . prototype . _close = function ( value ) {
183- if ( this . closed ) {
184- return ;
185- }
186-
187- this . closed = true ;
188- this . modalBar . close ( ) ;
189- EditorManager . focusEditor ( ) ;
190- this . result . resolve ( value ) ;
191- } ;
192-
193- /**
194- * Shows the search dialog
195- * @param {string= } initialString Default text to prepopulate the search field with
196- * @param {Entry= } scope Search scope, or null to search whole project
197- * @returns {$.Promise } that is resolved with the string to search for
198- */
199- FindInFilesDialog . prototype . showDialog = function ( initialString , scope ) {
200- // Note the prefix label is a simple "Find:" - the "in ..." part comes after the text field
201- var templateVars = {
202- value : initialString || "" ,
203- label : _labelForScope ( scope )
204- } ,
205- dialogHTML = Mustache . render ( searchDialogTemplate , $ . extend ( templateVars , Strings ) ) ,
206- that = this ;
207-
208- this . result = new $ . Deferred ( ) ;
209- this . modalBar = new ModalBar ( dialogHTML , false ) ;
210- var $searchField = $ ( "input#searchInput" ) ;
211-
212- $searchField . get ( 0 ) . select ( ) ;
213- $searchField
214- . bind ( "keydown" , function ( event ) {
215- if ( event . keyCode === KeyEvent . DOM_VK_RETURN || event . keyCode === KeyEvent . DOM_VK_ESCAPE ) { // Enter/Return key or Esc key
216- event . stopPropagation ( ) ;
217- event . preventDefault ( ) ;
218-
219- var query = $searchField . val ( ) ;
220-
221- if ( event . keyCode === KeyEvent . DOM_VK_ESCAPE ) {
222- query = null ;
223- }
224-
225- that . _close ( query ) ;
226- }
227- } )
228- . bind ( "input" , function ( event ) {
229- // Check the query expression on every input event. This way the user is alerted
230- // to any RegEx syntax errors immediately.
231- _getQueryRegExp ( $searchField . val ( ) ) ;
232- } )
233- . blur ( function ( ) {
234- that . _close ( null ) ;
235- } )
236- . focus ( ) ;
237-
238- return this . result . promise ( ) ;
239- } ;
240-
241-
242172 /**
243173 * @private
244174 * Hides the Search Results Panel
@@ -541,9 +471,23 @@ define(function (require, exports, module) {
541471 $selectedRow = null ;
542472 }
543473 searchResultsPanel . show ( ) ;
544-
474+
475+ if ( dialog ) {
476+ dialog . _close ( ) ;
477+ dialog = null ;
478+ }
545479 } else {
480+
546481 _hideSearchResults ( ) ;
482+
483+ if ( dialog ) {
484+ dialog . getDialogTextField ( ) . addClass ( "no-results" )
485+ . removeAttr ( "disabled" )
486+ . get ( 0 ) . select ( ) ;
487+
488+ $ ( ".modal-bar .message" ) . css ( "display" , "none" ) ;
489+ $ ( ".modal-bar .error" ) . css ( "display" , "inline-block" ) . html ( Strings . FIND_NO_RESULTS ) ;
490+ }
547491 }
548492 }
549493
@@ -706,8 +650,141 @@ define(function (require, exports, module) {
706650 }
707651 }
708652
653+ /**
654+ * @private
655+ * Executes the Find in Files search inside the 'currentScope'
656+ * @param {string } query String to be searched
657+ */
658+ function _doSearch ( query ) {
659+ currentQuery = query ;
660+ currentQueryExpr = _getQueryRegExp ( query ) ;
661+
662+ if ( ! currentQueryExpr ) {
663+ StatusBar . hideBusyIndicator ( ) ;
664+ dialog . _close ( ) ;
665+ dialog = null ;
666+ return ;
667+ }
668+ FileIndexManager . getFileInfoList ( "all" )
669+ . done ( function ( fileListResult ) {
670+ Async . doInParallel ( fileListResult , function ( fileInfo ) {
671+ var result = new $ . Deferred ( ) ;
672+
673+ if ( ! _inScope ( fileInfo , currentScope ) ) {
674+ result . resolve ( ) ;
675+ } else {
676+ // Search one file
677+ DocumentManager . getDocumentForPath ( fileInfo . fullPath )
678+ . done ( function ( doc ) {
679+ _addSearchMatches ( fileInfo . fullPath , doc . getText ( ) , currentQueryExpr ) ;
680+ result . resolve ( ) ;
681+ } )
682+ . fail ( function ( error ) {
683+ // Error reading this file. This is most likely because the file isn't a text file.
684+ // Resolve here so we move on to the next file.
685+ result . resolve ( ) ;
686+ } ) ;
687+ }
688+ return result . promise ( ) ;
689+ } )
690+ . done ( function ( ) {
691+ // Done searching all files: show results
692+ _showSearchResults ( ) ;
693+ StatusBar . hideBusyIndicator ( ) ;
694+ $ ( DocumentModule ) . on ( "documentChange.findInFiles" , _documentChangeHandler ) ;
695+ } )
696+ . fail ( function ( ) {
697+ console . log ( "find in files failed." ) ;
698+ StatusBar . hideBusyIndicator ( ) ;
699+ } ) ;
700+ } ) ;
701+ }
702+
703+
704+ // This dialog class was mostly copied from QuickOpen. We should have a common dialog
705+ // class that everyone can use.
706+
707+ /**
708+ * FindInFilesDialog class
709+ * @constructor
710+ */
711+ function FindInFilesDialog ( ) {
712+ this . closed = false ;
713+ }
714+
715+ /**
716+ * Returns the input text field of the modalbar in the dialog
717+ * @return jQuery Object pointing to input text field
718+ */
719+ FindInFilesDialog . prototype . getDialogTextField = function ( ) {
720+ return $ ( "input[type='text']" , this . modalBar . getRoot ( ) ) ;
721+ } ;
709722
710723
724+ /**
725+ * Closes the search dialog and resolves the promise that showDialog returned
726+ */
727+ FindInFilesDialog . prototype . _close = function ( value ) {
728+ if ( this . closed ) {
729+ return ;
730+ }
731+
732+ this . closed = true ;
733+ this . modalBar . close ( ) ;
734+ EditorManager . focusEditor ( ) ;
735+ } ;
736+
737+ /**
738+ * Shows the search dialog
739+ * @param {string= } initialString Default text to prepopulate the search field with
740+ * @param {Entry= } scope Search scope, or null to search whole project
741+ * @returns {$.Promise } that is resolved with the string to search for
742+ */
743+ FindInFilesDialog . prototype . showDialog = function ( initialString , scope ) {
744+ // Note the prefix label is a simple "Find:" - the "in ..." part comes after the text field
745+ var templateVars = {
746+ value : initialString || "" ,
747+ label : _labelForScope ( scope )
748+ } ,
749+ dialogHTML = Mustache . render ( searchDialogTemplate , $ . extend ( templateVars , Strings ) ) ,
750+ that = this ;
751+
752+ this . modalBar = new ModalBar ( dialogHTML , false ) ;
753+ var $searchField = $ ( "input#searchInput" ) ;
754+
755+ $searchField . get ( 0 ) . select ( ) ;
756+ $searchField
757+ . bind ( "keydown" , function ( event ) {
758+ if ( event . keyCode === KeyEvent . DOM_VK_RETURN || event . keyCode === KeyEvent . DOM_VK_ESCAPE ) { // Enter/Return key or Esc key
759+ event . stopPropagation ( ) ;
760+ event . preventDefault ( ) ;
761+
762+ var query = $searchField . val ( ) ;
763+
764+ if ( event . keyCode === KeyEvent . DOM_VK_ESCAPE ) {
765+ that . _close ( null ) ;
766+ } else if ( event . keyCode === KeyEvent . DOM_VK_RETURN ) {
767+ StatusBar . showBusyIndicator ( true ) ;
768+ that . getDialogTextField ( ) . attr ( "disabled" , "disabled" ) ;
769+ _doSearch ( query ) ;
770+ }
771+ }
772+ } )
773+ . bind ( "input" , function ( event ) {
774+ // Check the query expression on every input event. This way the user is alerted
775+ // to any RegEx syntax errors immediately.
776+ _getQueryRegExp ( $searchField . val ( ) ) ;
777+ that . getDialogTextField ( ) . removeClass ( "no-results" ) ;
778+ } )
779+ . blur ( function ( ) {
780+ if ( that . getDialogTextField ( ) . attr ( "disabled" ) ) {
781+ return ;
782+ }
783+ that . _close ( null ) ;
784+ } )
785+ . focus ( ) ;
786+ } ;
787+
711788 /**
712789 * @private
713790 * Displays a non-modal embedded dialog above the code mirror editor that allows the user to do
@@ -724,61 +801,17 @@ define(function (require, exports, module) {
724801
725802 // Default to searching for the current selection
726803 var currentEditor = EditorManager . getActiveEditor ( ) ,
727- initialString = currentEditor && currentEditor . getSelectedText ( ) ,
728- dialog = new FindInFilesDialog ( ) ;
804+ initialString = currentEditor && currentEditor . getSelectedText ( ) ;
729805
806+ dialog = new FindInFilesDialog ( ) ;
730807 searchResults = { } ;
731808 currentStart = 0 ;
732809 currentQuery = "" ;
733810 currentQueryExpr = null ;
734811 currentScope = scope ;
735812 maxHitsFoundInFile = false ;
736813
737- dialog . showDialog ( initialString , scope )
738- . done ( function ( query ) {
739- if ( query ) {
740- currentQuery = query ;
741- currentQueryExpr = _getQueryRegExp ( query ) ;
742-
743- if ( ! currentQueryExpr ) {
744- return ;
745- }
746- StatusBar . showBusyIndicator ( true ) ;
747- FileIndexManager . getFileInfoList ( "all" )
748- . done ( function ( fileListResult ) {
749- Async . doInParallel ( fileListResult , function ( fileInfo ) {
750- var result = new $ . Deferred ( ) ;
751-
752- if ( ! _inScope ( fileInfo , scope ) ) {
753- result . resolve ( ) ;
754- } else {
755- // Search one file
756- DocumentManager . getDocumentForPath ( fileInfo . fullPath )
757- . done ( function ( doc ) {
758- _addSearchMatches ( fileInfo . fullPath , doc . getText ( ) , currentQueryExpr ) ;
759- result . resolve ( ) ;
760- } )
761- . fail ( function ( error ) {
762- // Error reading this file. This is most likely because the file isn't a text file.
763- // Resolve here so we move on to the next file.
764- result . resolve ( ) ;
765- } ) ;
766- }
767- return result . promise ( ) ;
768- } )
769- . done ( function ( ) {
770- // Done searching all files: show results
771- _showSearchResults ( ) ;
772- StatusBar . hideBusyIndicator ( ) ;
773- $ ( DocumentModule ) . on ( "documentChange.findInFiles" , _documentChangeHandler ) ;
774- } )
775- . fail ( function ( ) {
776- console . log ( "find in files failed." ) ;
777- StatusBar . hideBusyIndicator ( ) ;
778- } ) ;
779- } ) ;
780- }
781- } ) ;
814+ dialog . showDialog ( initialString , scope ) ;
782815 }
783816
784817 /**
0 commit comments