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);
15 this.element.classList.add("search-view");
17 this._searchPanelElement = this.element.createChild("div", "search-drawer-header");
18 this._searchPanelElement.addEventListener("keydown", this._onKeyDown.bind(this), false);
20 this._searchResultsElement = this.element.createChild("div");
21 this._searchResultsElement.className = "search-results";
23 this._search = this._searchPanelElement.createChild("input");
24 this._search.placeholder = WebInspector.UIString("Search sources");
25 this._search.setAttribute("type", "text");
26 this._search.classList.add("search-config-search");
27 this._search.setAttribute("results", "0");
28 this._search.setAttribute("size", 30);
30 this._ignoreCaseLabel = this._searchPanelElement.createChild("label");
31 this._ignoreCaseLabel.classList.add("search-config-label");
32 this._ignoreCaseCheckbox = this._ignoreCaseLabel.createChild("input");
33 this._ignoreCaseCheckbox.setAttribute("type", "checkbox");
34 this._ignoreCaseCheckbox.classList.add("search-config-checkbox");
35 this._ignoreCaseLabel.appendChild(document.createTextNode(WebInspector.UIString("Ignore case")));
37 this._regexLabel = this._searchPanelElement.createChild("label");
38 this._regexLabel.classList.add("search-config-label");
39 this._regexCheckbox = this._regexLabel.createChild("input");
40 this._regexCheckbox.setAttribute("type", "checkbox");
41 this._regexCheckbox.classList.add("search-config-checkbox");
42 this._regexLabel.appendChild(document.createTextNode(WebInspector.UIString("Regular expression")));
44 this._searchStatusBarElement = this.element.createChild("div", "search-status-bar-summary");
45 this._searchMessageElement = this._searchStatusBarElement.createChild("span");
46 this._searchResultsMessageElement = document.createElement("span");
48 WebInspector.settings.advancedSearchConfig = WebInspector.settings.createSetting("advancedSearchConfig", new WebInspector.SearchConfig("", true, false).toPlainObject());
52 WebInspector.AdvancedSearchView.prototype = {
54 * @return {!WebInspector.SearchConfig}
56 _buildSearchConfig: function()
58 return new WebInspector.SearchConfig(this._search.value, this._ignoreCaseCheckbox.checked, this._regexCheckbox.checked);
63 var selection = window.getSelection();
65 if (selection.rangeCount)
66 queryCandidate = selection.toString().replace(/\r?\n.*/, "");
68 if (!this.isShowing())
69 WebInspector.inspectorView.showViewInDrawer("search");
71 this._search.value = queryCandidate;
74 this._startIndexing();
78 * @param {boolean} finished
80 _onIndexingFinished: function(finished)
82 delete this._isIndexing;
83 this._indexingFinished(finished);
85 delete this._pendingSearchConfig;
86 if (!this._pendingSearchConfig)
88 var searchConfig = this._pendingSearchConfig
89 delete this._pendingSearchConfig;
90 this._innerStartSearch(searchConfig);
93 _startIndexing: function()
95 this._isIndexing = true;
96 // FIXME: this._currentSearchScope should be initialized based on searchConfig
97 this._currentSearchScope = this._searchScopes()[0];
98 if (this._progressIndicator)
99 this._progressIndicator.done();
100 this._progressIndicator = new WebInspector.ProgressIndicator();
101 this._indexingStarted(this._progressIndicator);
102 this._currentSearchScope.performIndexing(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)
113 this._addSearchResult(searchResult);
114 if (!searchResult.searchMatches.length)
116 if (!this._searchResultsPane)
117 this._searchResultsPane = this._currentSearchScope.createSearchResultsPane(this._searchConfig);
118 this._resetResults();
119 this._searchResultsElement.appendChild(this._searchResultsPane.element);
120 this._searchResultsPane.addSearchResult(searchResult);
124 * @param {number} searchId
125 * @param {boolean} finished
127 _onSearchFinished: function(searchId, finished)
129 if (searchId !== this._searchId)
131 if (!this._searchResultsPane)
132 this._nothingFound();
133 this._searchFinished(finished);
134 delete this._searchConfig;
138 * @param {!WebInspector.SearchConfig} searchConfig
140 _startSearch: function(searchConfig)
144 if (!this._isIndexing)
145 this._startIndexing();
146 this._pendingSearchConfig = searchConfig;
150 * @param {!WebInspector.SearchConfig} searchConfig
152 _innerStartSearch: function(searchConfig)
154 this._searchConfig = searchConfig;
155 // FIXME: this._currentSearchScope should be initialized based on searchConfig
156 this._currentSearchScope = this._searchScopes()[0];
158 if (this._progressIndicator)
159 this._progressIndicator.done();
160 this._progressIndicator = new WebInspector.ProgressIndicator();
161 this._searchStarted(this._progressIndicator);
162 this._currentSearchScope.performSearch(searchConfig, this._progressIndicator, this._onSearchResult.bind(this, this._searchId), this._onSearchFinished.bind(this, this._searchId));
165 _resetSearch: function()
169 if (this._searchResultsPane) {
170 this._resetResults();
171 delete this._searchResultsPane;
175 _stopSearch: function()
177 if (this._progressIndicator)
178 this._progressIndicator.cancel();
179 if (this._currentSearchScope)
180 this._currentSearchScope.stopSearch();
181 delete this._searchConfig;
185 * @return {!Array.<!WebInspector.SearchScope>}
187 _searchScopes: function()
189 // FIXME: implement multiple search scopes.
190 return /** @type {!Array.<!WebInspector.SearchScope>} */ (WebInspector.moduleManager.instances(WebInspector.SearchScope));
194 * @param {!WebInspector.ProgressIndicator} progressIndicator
196 _searchStarted: function(progressIndicator)
198 this._resetResults();
199 this._resetCounters();
201 this._searchMessageElement.textContent = WebInspector.UIString("Searching...");
202 progressIndicator.show(this._searchStatusBarElement);
203 this._updateSearchResultsMessage();
205 if (!this._searchingView)
206 this._searchingView = new WebInspector.EmptyView(WebInspector.UIString("Searching..."));
207 this._searchingView.show(this._searchResultsElement);
211 * @param {!WebInspector.ProgressIndicator} progressIndicator
213 _indexingStarted: function(progressIndicator)
215 this._searchMessageElement.textContent = WebInspector.UIString("Indexing...");
216 progressIndicator.show(this._searchStatusBarElement);
220 * @param {boolean} finished
222 _indexingFinished: function(finished)
224 this._searchMessageElement.textContent = finished ? "" : WebInspector.UIString("Indexing interrupted.");
227 _updateSearchResultsMessage: function()
229 if (this._searchMatchesCount && this._searchResultsCount)
230 this._searchResultsMessageElement.textContent = WebInspector.UIString("Found %d matches in %d files.", this._searchMatchesCount, this._nonEmptySearchResultsCount);
232 this._searchResultsMessageElement.textContent = "";
235 _resetResults: function()
237 if (this._searchingView)
238 this._searchingView.detach();
239 if (this._notFoundView)
240 this._notFoundView.detach();
241 this._searchResultsElement.removeChildren();
244 _resetCounters: function()
246 this._searchMatchesCount = 0;
247 this._searchResultsCount = 0;
248 this._nonEmptySearchResultsCount = 0;
251 _nothingFound: function()
253 this._resetResults();
255 if (!this._notFoundView)
256 this._notFoundView = new WebInspector.EmptyView(WebInspector.UIString("No matches found."));
257 this._notFoundView.show(this._searchResultsElement);
258 this._searchResultsMessageElement.textContent = WebInspector.UIString("No matches found.");
262 * @param {!WebInspector.FileBasedSearchResult} searchResult
264 _addSearchResult: function(searchResult)
266 this._searchMatchesCount += searchResult.searchMatches.length;
267 this._searchResultsCount++;
268 if (searchResult.searchMatches.length)
269 this._nonEmptySearchResultsCount++;
270 this._updateSearchResultsMessage();
274 * @param {boolean} finished
276 _searchFinished: function(finished)
278 this._searchMessageElement.textContent = finished ? WebInspector.UIString("Search finished.") : WebInspector.UIString("Search interrupted.");
283 WebInspector.setCurrentFocusElement(this._search);
284 this._search.select();
293 * @param {?Event} event
295 _onKeyDown: function(event)
297 switch (event.keyCode) {
298 case WebInspector.KeyboardShortcut.Keys.Enter.code:
306 WebInspector.settings.advancedSearchConfig.set(this._buildSearchConfig().toPlainObject());
311 var searchConfig = WebInspector.SearchConfig.fromPlainObject(WebInspector.settings.advancedSearchConfig.get());
312 this._search.value = searchConfig.query();
313 this._ignoreCaseCheckbox.checked = searchConfig.ignoreCase();
314 this._regexCheckbox.checked = searchConfig.isRegex();
317 _onAction: function()
319 var searchConfig = this._buildSearchConfig();
320 if (!searchConfig.query() || !searchConfig.query().length)
324 this._startSearch(searchConfig);
327 __proto__: WebInspector.VBox.prototype
332 * @param {!WebInspector.ProjectSearchConfig} searchConfig
334 WebInspector.SearchResultsPane = function(searchConfig)
336 this._searchConfig = searchConfig;
337 this.element = document.createElement("div");
340 WebInspector.SearchResultsPane.prototype = {
342 * @return {!WebInspector.ProjectSearchConfig}
346 return this._searchConfig;
350 * @param {!WebInspector.FileBasedSearchResult} searchResult
352 addSearchResult: function(searchResult) { }
357 * @implements {WebInspector.ActionDelegate}
359 WebInspector.AdvancedSearchView.ToggleDrawerViewActionDelegate = function()
363 WebInspector.AdvancedSearchView.ToggleDrawerViewActionDelegate.prototype = {
367 handleAction: function()
369 var searchView = this._searchView();
372 if (!searchView.isShowing() || searchView._search !== document.activeElement) {
373 WebInspector.inspectorView.showPanel("sources");
376 WebInspector.inspectorView.closeDrawer();
382 * @return {?WebInspector.AdvancedSearchView}
384 _searchView: function()
387 var extensions = WebInspector.moduleManager.extensions("drawer-view");
388 for (var i = 0; i < extensions.length; ++i) {
389 if (extensions[i].descriptor()["name"] === "search") {
390 this._view = extensions[i].instance();
402 * @param {!WebInspector.UISourceCode} uiSourceCode
403 * @param {!Array.<!Object>} searchMatches
405 WebInspector.FileBasedSearchResult = function(uiSourceCode, searchMatches) {
406 this.uiSourceCode = uiSourceCode;
407 this.searchMatches = searchMatches;
413 WebInspector.SearchScope = function()
417 WebInspector.SearchScope.prototype = {
419 * @param {!WebInspector.SearchConfig} searchConfig
420 * @param {!WebInspector.Progress} progress
421 * @param {function(!WebInspector.FileBasedSearchResult)} searchResultCallback
422 * @param {function(boolean)} searchFinishedCallback
424 performSearch: function(searchConfig, progress, searchResultCallback, searchFinishedCallback) { },
427 * @param {!WebInspector.Progress} progress
428 * @param {function(boolean)} callback
430 performIndexing: function(progress, callback) { },
432 stopSearch: function() { },
435 * @param {!WebInspector.ProjectSearchConfig} searchConfig
436 * @return {!WebInspector.SearchResultsPane}
438 createSearchResultsPane: function(searchConfig) { }
441 importScript("FileBasedSearchResultsPane.js");
442 importScript("SourcesSearchScope.js");