1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 * @extends {WebInspector.VBox}
9 WebInspector
.AdvancedSearchView = function()
11 WebInspector
.VBox
.call(this, true);
12 this.setMinimumSize(0, 40);
13 this.registerRequiredCSS("sources/sourcesSearch.css");
17 this.contentElement
.classList
.add("search-view");
19 this._searchPanelElement
= this.contentElement
.createChild("div", "search-drawer-header");
20 this._searchPanelElement
.addEventListener("keydown", this._onKeyDown
.bind(this), false);
22 this._searchResultsElement
= this.contentElement
.createChild("div");
23 this._searchResultsElement
.className
= "search-results";
25 this._search
= WebInspector
.HistoryInput
.create();
26 this._searchPanelElement
.appendChild(this._search
);
27 this._search
.placeholder
= WebInspector
.UIString("Enter query, use `file:` to filter by path");
28 this._search
.setAttribute("type", "text");
29 this._search
.classList
.add("search-config-search");
30 this._search
.setAttribute("results", "0");
31 this._search
.setAttribute("size", 30);
33 this._ignoreCaseLabel
= createCheckboxLabel(WebInspector
.UIString("Ignore case"));
34 this._ignoreCaseLabel
.classList
.add("search-config-label");
35 this._searchPanelElement
.appendChild(this._ignoreCaseLabel
);
36 this._ignoreCaseCheckbox
= this._ignoreCaseLabel
.checkboxElement
;
37 this._ignoreCaseCheckbox
.classList
.add("search-config-checkbox");
39 this._regexLabel
= createCheckboxLabel(WebInspector
.UIString("Regular expression"));
40 this._regexLabel
.classList
.add("search-config-label");
41 this._searchPanelElement
.appendChild(this._regexLabel
);
42 this._regexCheckbox
= this._regexLabel
.checkboxElement
;
43 this._regexCheckbox
.classList
.add("search-config-checkbox");
45 this._searchToolbarElement
= this.contentElement
.createChild("div", "search-toolbar-summary");
46 this._searchMessageElement
= this._searchToolbarElement
.createChild("div", "search-message");
47 this._searchProgressPlaceholderElement
= this._searchToolbarElement
.createChild("div", "flex-centered");
48 this._searchToolbarElement
.createChild("div", "search-message-spacer");
49 this._searchResultsMessageElement
= this._searchToolbarElement
.createChild("div", "search-message");
51 this._advancedSearchConfig
= WebInspector
.settings
.createLocalSetting("advancedSearchConfig", new WebInspector
.SearchConfig("", true, false).toPlainObject());
53 /** @type {!WebInspector.SearchScope} */
54 this._searchScope
= new WebInspector
.SourcesSearchScope();
57 WebInspector
.AdvancedSearchView
.prototype = {
59 * @return {!WebInspector.SearchConfig}
61 _buildSearchConfig: function()
63 return new WebInspector
.SearchConfig(this._search
.value
, this._ignoreCaseCheckbox
.checked
, this._regexCheckbox
.checked
);
67 * @param {string} queryCandidate
69 _toggle: function(queryCandidate
)
72 this._search
.value
= queryCandidate
;
75 this._startIndexing();
78 _onIndexingFinished: function()
80 var finished
= !this._progressIndicator
.isCanceled();
81 this._progressIndicator
.done();
82 delete this._progressIndicator
;
83 delete this._isIndexing
;
84 this._indexingFinished(finished
);
86 delete this._pendingSearchConfig
;
87 if (!this._pendingSearchConfig
)
89 var searchConfig
= this._pendingSearchConfig
;
90 delete this._pendingSearchConfig
;
91 this._innerStartSearch(searchConfig
);
94 _startIndexing: function()
96 this._isIndexing
= true;
97 if (this._progressIndicator
)
98 this._progressIndicator
.done();
99 this._progressIndicator
= new WebInspector
.ProgressIndicator();
100 this._searchMessageElement
.textContent
= WebInspector
.UIString("Indexing\u2026");
101 this._progressIndicator
.show(this._searchProgressPlaceholderElement
);
102 this._searchScope
.performIndexing(new WebInspector
.ProgressProxy(this._progressIndicator
, this._onIndexingFinished
.bind(this)));
106 * @param {number} searchId
107 * @param {!WebInspector.FileBasedSearchResult} searchResult
109 _onSearchResult: function(searchId
, searchResult
)
111 if (searchId
!== this._searchId
|| !this._progressIndicator
)
113 if (this._progressIndicator
&& this._progressIndicator
.isCanceled()) {
114 this._onIndexingFinished();
117 this._addSearchResult(searchResult
);
118 if (!searchResult
.searchMatches
.length
)
120 if (!this._searchResultsPane
)
121 this._searchResultsPane
= this._searchScope
.createSearchResultsPane(this._searchConfig
);
122 this._resetResults();
123 this._searchResultsElement
.appendChild(this._searchResultsPane
.element
);
124 this._searchResultsPane
.addSearchResult(searchResult
);
128 * @param {number} searchId
129 * @param {boolean} finished
131 _onSearchFinished: function(searchId
, finished
)
133 if (searchId
!== this._searchId
|| !this._progressIndicator
)
135 if (!this._searchResultsPane
)
136 this._nothingFound();
137 this._searchFinished(finished
);
138 delete this._searchConfig
;
142 * @param {!WebInspector.SearchConfig} searchConfig
144 _startSearch: function(searchConfig
)
148 if (!this._isIndexing
)
149 this._startIndexing();
150 this._pendingSearchConfig
= searchConfig
;
154 * @param {!WebInspector.SearchConfig} searchConfig
156 _innerStartSearch: function(searchConfig
)
158 this._searchConfig
= searchConfig
;
159 if (this._progressIndicator
)
160 this._progressIndicator
.done();
161 this._progressIndicator
= new WebInspector
.ProgressIndicator();
162 this._searchStarted(this._progressIndicator
);
163 this._searchScope
.performSearch(searchConfig
, this._progressIndicator
, this._onSearchResult
.bind(this, this._searchId
), this._onSearchFinished
.bind(this, this._searchId
));
166 _resetSearch: function()
170 if (this._searchResultsPane
) {
171 this._resetResults();
172 delete this._searchResultsPane
;
176 _stopSearch: function()
178 if (this._progressIndicator
&& !this._isIndexing
)
179 this._progressIndicator
.cancel();
180 if (this._searchScope
)
181 this._searchScope
.stopSearch();
182 delete this._searchConfig
;
186 * @param {!WebInspector.ProgressIndicator} progressIndicator
188 _searchStarted: function(progressIndicator
)
190 this._resetResults();
191 this._resetCounters();
193 this._searchMessageElement
.textContent
= WebInspector
.UIString("Searching\u2026");
194 progressIndicator
.show(this._searchProgressPlaceholderElement
);
195 this._updateSearchResultsMessage();
197 if (!this._searchingView
)
198 this._searchingView
= new WebInspector
.EmptyWidget(WebInspector
.UIString("Searching\u2026"));
199 this._searchingView
.show(this._searchResultsElement
);
203 * @param {boolean} finished
205 _indexingFinished: function(finished
)
207 this._searchMessageElement
.textContent
= finished
? "" : WebInspector
.UIString("Indexing interrupted.");
210 _updateSearchResultsMessage: function()
212 if (this._searchMatchesCount
&& this._searchResultsCount
)
213 this._searchResultsMessageElement
.textContent
= WebInspector
.UIString("Found %d matches in %d files.", this._searchMatchesCount
, this._nonEmptySearchResultsCount
);
215 this._searchResultsMessageElement
.textContent
= "";
218 _resetResults: function()
220 if (this._searchingView
)
221 this._searchingView
.detach();
222 if (this._notFoundView
)
223 this._notFoundView
.detach();
224 this._searchResultsElement
.removeChildren();
227 _resetCounters: function()
229 this._searchMatchesCount
= 0;
230 this._searchResultsCount
= 0;
231 this._nonEmptySearchResultsCount
= 0;
234 _nothingFound: function()
236 this._resetResults();
238 if (!this._notFoundView
)
239 this._notFoundView
= new WebInspector
.EmptyWidget(WebInspector
.UIString("No matches found."));
240 this._notFoundView
.show(this._searchResultsElement
);
241 this._searchResultsMessageElement
.textContent
= WebInspector
.UIString("No matches found.");
245 * @param {!WebInspector.FileBasedSearchResult} searchResult
247 _addSearchResult: function(searchResult
)
249 this._searchMatchesCount
+= searchResult
.searchMatches
.length
;
250 this._searchResultsCount
++;
251 if (searchResult
.searchMatches
.length
)
252 this._nonEmptySearchResultsCount
++;
253 this._updateSearchResultsMessage();
257 * @param {boolean} finished
259 _searchFinished: function(finished
)
261 this._searchMessageElement
.textContent
= finished
? WebInspector
.UIString("Search finished.") : WebInspector
.UIString("Search interrupted.");
266 WebInspector
.setCurrentFocusElement(this._search
);
267 this._search
.select();
276 * @param {!Event} event
278 _onKeyDown: function(event
)
280 switch (event
.keyCode
) {
281 case WebInspector
.KeyboardShortcut
.Keys
.Enter
.code
:
289 this._advancedSearchConfig
.set(this._buildSearchConfig().toPlainObject());
294 var searchConfig
= WebInspector
.SearchConfig
.fromPlainObject(this._advancedSearchConfig
.get());
295 this._search
.value
= searchConfig
.query();
296 this._ignoreCaseCheckbox
.checked
= searchConfig
.ignoreCase();
297 this._regexCheckbox
.checked
= searchConfig
.isRegex();
300 _onAction: function()
302 var searchConfig
= this._buildSearchConfig();
303 if (!searchConfig
.query() || !searchConfig
.query().length
)
307 this._startSearch(searchConfig
);
310 __proto__
: WebInspector
.VBox
.prototype
315 * @param {!WebInspector.ProjectSearchConfig} searchConfig
317 WebInspector
.SearchResultsPane = function(searchConfig
)
319 this._searchConfig
= searchConfig
;
320 this.element
= createElement("div");
323 WebInspector
.SearchResultsPane
.prototype = {
325 * @return {!WebInspector.ProjectSearchConfig}
329 return this._searchConfig
;
333 * @param {!WebInspector.FileBasedSearchResult} searchResult
335 addSearchResult: function(searchResult
) { }
340 * @implements {WebInspector.ActionDelegate}
342 WebInspector
.AdvancedSearchView
.ActionDelegate = function()
344 this._searchView
= new WebInspector
.AdvancedSearchView();
347 WebInspector
.AdvancedSearchView
.ActionDelegate
.prototype = {
350 * @param {!WebInspector.Context} context
351 * @param {string} actionId
353 handleAction: function(context
, actionId
)
355 if (!this._searchView
.isShowing() || this._searchView
._search
!== this._searchView
.element
.window().document
.activeElement
) {
356 var selection
= WebInspector
.inspectorView
.element
.getDeepSelection();
357 var queryCandidate
= "";
358 if (selection
.rangeCount
)
359 queryCandidate
= selection
.toString().replace(/\r?\n.*/, "");
361 WebInspector
.inspectorView
.setCurrentPanel(WebInspector
.SourcesPanel
.instance());
362 this._searchView
._toggle(queryCandidate
);
363 WebInspector
.inspectorView
.showCloseableViewInDrawer("sources.search", WebInspector
.UIString("Search"), this._searchView
);
364 this._searchView
.focus();
371 * @param {!WebInspector.UISourceCode} uiSourceCode
372 * @param {!Array.<!Object>} searchMatches
374 WebInspector
.FileBasedSearchResult = function(uiSourceCode
, searchMatches
) {
375 this.uiSourceCode
= uiSourceCode
;
376 this.searchMatches
= searchMatches
;
382 WebInspector
.SearchScope = function()
386 WebInspector
.SearchScope
.prototype = {
388 * @param {!WebInspector.SearchConfig} searchConfig
389 * @param {!WebInspector.Progress} progress
390 * @param {function(!WebInspector.FileBasedSearchResult)} searchResultCallback
391 * @param {function(boolean)} searchFinishedCallback
393 performSearch: function(searchConfig
, progress
, searchResultCallback
, searchFinishedCallback
) { },
396 * @param {!WebInspector.Progress} progress
398 performIndexing: function(progress
) { },
400 stopSearch: function() { },
403 * @param {!WebInspector.ProjectSearchConfig} searchConfig
404 * @return {!WebInspector.SearchResultsPane}
406 createSearchResultsPane: function(searchConfig
) { }