Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / search / AdvancedSearchView.js
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.
4
5 /**
6  * @constructor
7  * @extends {WebInspector.VBox}
8  */
9 WebInspector.AdvancedSearchView = function()
10 {
11     WebInspector.VBox.call(this);
12
13     this._searchId = 0;
14
15     this.element.classList.add("search-view");
16
17     this._searchPanelElement = this.element.createChild("div", "search-drawer-header");
18     this._searchPanelElement.addEventListener("keydown", this._onKeyDown.bind(this), false);
19
20     this._searchResultsElement = this.element.createChild("div");
21     this._searchResultsElement.className = "search-results";
22
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);
29
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")));
36
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")));
43
44     this._searchStatusBarElement = this.element.createChild("div", "search-status-bar-summary");
45     this._searchMessageElement = this._searchStatusBarElement.createChild("span");
46     this._searchResultsMessageElement = document.createElement("span");
47
48     WebInspector.settings.advancedSearchConfig = WebInspector.settings.createSetting("advancedSearchConfig", new WebInspector.SearchConfig("", true, false).toPlainObject());
49     this._load();
50 }
51
52 WebInspector.AdvancedSearchView.prototype = {
53     /**
54      * @return {!WebInspector.SearchConfig}
55      */
56     _buildSearchConfig: function()
57     {
58         return new WebInspector.SearchConfig(this._search.value, this._ignoreCaseCheckbox.checked, this._regexCheckbox.checked);
59     },
60
61     toggle: function()
62     {
63         var selection = window.getSelection();
64         var queryCandidate;
65         if (selection.rangeCount)
66             queryCandidate = selection.toString().replace(/\r?\n.*/, "");
67
68         if (!this.isShowing())
69             WebInspector.inspectorView.showViewInDrawer("search");
70         if (queryCandidate)
71             this._search.value = queryCandidate;
72         this.focus();
73
74         this._startIndexing();
75     },
76
77     /**
78      * @param {boolean} finished
79      */
80     _onIndexingFinished: function(finished)
81     {
82         delete this._isIndexing;
83         this._indexingFinished(finished);
84         if (!finished)
85             delete this._pendingSearchConfig;
86         if (!this._pendingSearchConfig)
87             return;
88         var searchConfig = this._pendingSearchConfig
89         delete this._pendingSearchConfig;
90         this._innerStartSearch(searchConfig);
91     },
92
93     _startIndexing: function()
94     {
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));
103     },
104
105     /**
106      * @param {number} searchId
107      * @param {!WebInspector.FileBasedSearchResult} searchResult
108      */
109     _onSearchResult: function(searchId, searchResult)
110     {
111         if (searchId !== this._searchId)
112             return;
113         this._addSearchResult(searchResult);
114         if (!searchResult.searchMatches.length)
115             return;
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);
121     },
122
123     /**
124      * @param {number} searchId
125      * @param {boolean} finished
126      */
127     _onSearchFinished: function(searchId, finished)
128     {
129         if (searchId !== this._searchId)
130             return;
131         if (!this._searchResultsPane)
132             this._nothingFound();
133         this._searchFinished(finished);
134         delete this._searchConfig;
135     },
136
137     /**
138      * @param {!WebInspector.SearchConfig} searchConfig
139      */
140     _startSearch: function(searchConfig)
141     {
142         this._resetSearch();
143         ++this._searchId;
144         if (!this._isIndexing)
145             this._startIndexing();
146         this._pendingSearchConfig = searchConfig;
147     },
148
149     /**
150      * @param {!WebInspector.SearchConfig} searchConfig
151      */
152     _innerStartSearch: function(searchConfig)
153     {
154         this._searchConfig = searchConfig;
155         // FIXME: this._currentSearchScope should be initialized based on searchConfig
156         this._currentSearchScope = this._searchScopes()[0];
157
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));
163     },
164
165     _resetSearch: function()
166     {
167         this._stopSearch();
168
169         if (this._searchResultsPane) {
170             this._resetResults();
171             delete this._searchResultsPane;
172         }
173     },
174
175     _stopSearch: function()
176     {
177         if (this._progressIndicator)
178             this._progressIndicator.cancel();
179         if (this._currentSearchScope)
180             this._currentSearchScope.stopSearch();
181         delete this._searchConfig;
182     },
183
184     /**
185      * @return {!Array.<!WebInspector.SearchScope>}
186      */
187     _searchScopes: function()
188     {
189         // FIXME: implement multiple search scopes.
190         return /** @type {!Array.<!WebInspector.SearchScope>} */ (WebInspector.moduleManager.instances(WebInspector.SearchScope));
191     },
192
193     /**
194      * @param {!WebInspector.ProgressIndicator} progressIndicator
195      */
196     _searchStarted: function(progressIndicator)
197     {
198         this._resetResults();
199         this._resetCounters();
200
201         this._searchMessageElement.textContent = WebInspector.UIString("Searching...");
202         progressIndicator.show(this._searchStatusBarElement);
203         this._updateSearchResultsMessage();
204
205         if (!this._searchingView)
206             this._searchingView = new WebInspector.EmptyView(WebInspector.UIString("Searching..."));
207         this._searchingView.show(this._searchResultsElement);
208     },
209
210     /**
211      * @param {!WebInspector.ProgressIndicator} progressIndicator
212      */
213     _indexingStarted: function(progressIndicator)
214     {
215         this._searchMessageElement.textContent = WebInspector.UIString("Indexing...");
216         progressIndicator.show(this._searchStatusBarElement);
217     },
218
219     /**
220      * @param {boolean} finished
221      */
222     _indexingFinished: function(finished)
223     {
224         this._searchMessageElement.textContent = finished ? "" : WebInspector.UIString("Indexing interrupted.");
225     },
226
227     _updateSearchResultsMessage: function()
228     {
229         if (this._searchMatchesCount && this._searchResultsCount)
230             this._searchResultsMessageElement.textContent = WebInspector.UIString("Found %d matches in %d files.", this._searchMatchesCount, this._nonEmptySearchResultsCount);
231         else
232             this._searchResultsMessageElement.textContent = "";
233     },
234
235     _resetResults: function()
236     {
237         if (this._searchingView)
238             this._searchingView.detach();
239         if (this._notFoundView)
240             this._notFoundView.detach();
241         this._searchResultsElement.removeChildren();
242     },
243
244     _resetCounters: function()
245     {
246         this._searchMatchesCount = 0;
247         this._searchResultsCount = 0;
248         this._nonEmptySearchResultsCount = 0;
249     },
250
251     _nothingFound: function()
252     {
253         this._resetResults();
254
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.");
259     },
260
261     /**
262      * @param {!WebInspector.FileBasedSearchResult} searchResult
263      */
264     _addSearchResult: function(searchResult)
265     {
266         this._searchMatchesCount += searchResult.searchMatches.length;
267         this._searchResultsCount++;
268         if (searchResult.searchMatches.length)
269             this._nonEmptySearchResultsCount++;
270         this._updateSearchResultsMessage();
271     },
272
273     /**
274      * @param {boolean} finished
275      */
276     _searchFinished: function(finished)
277     {
278         this._searchMessageElement.textContent = finished ? WebInspector.UIString("Search finished.") : WebInspector.UIString("Search interrupted.");
279     },
280
281     focus: function()
282     {
283         WebInspector.setCurrentFocusElement(this._search);
284         this._search.select();
285     },
286
287     willHide: function()
288     {
289         this._stopSearch();
290     },
291
292     /**
293      * @param {?Event} event
294      */
295     _onKeyDown: function(event)
296     {
297         switch (event.keyCode) {
298         case WebInspector.KeyboardShortcut.Keys.Enter.code:
299             this._onAction();
300             break;
301         }
302     },
303
304     _save: function()
305     {
306         WebInspector.settings.advancedSearchConfig.set(this._buildSearchConfig().toPlainObject());
307     },
308
309     _load: function()
310     {
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();
315     },
316
317     _onAction: function()
318     {
319         var searchConfig = this._buildSearchConfig();
320         if (!searchConfig.query() || !searchConfig.query().length)
321             return;
322
323         this._save();
324         this._startSearch(searchConfig);
325     },
326
327     __proto__: WebInspector.VBox.prototype
328 }
329
330 /**
331  * @constructor
332  * @param {!WebInspector.ProjectSearchConfig} searchConfig
333  */
334 WebInspector.SearchResultsPane = function(searchConfig)
335 {
336     this._searchConfig = searchConfig;
337     this.element = document.createElement("div");
338 }
339
340 WebInspector.SearchResultsPane.prototype = {
341     /**
342      * @return {!WebInspector.ProjectSearchConfig}
343      */
344     get searchConfig()
345     {
346         return this._searchConfig;
347     },
348
349     /**
350      * @param {!WebInspector.FileBasedSearchResult} searchResult
351      */
352     addSearchResult: function(searchResult) { }
353 }
354
355 /**
356  * @constructor
357  * @implements {WebInspector.ActionDelegate}
358  */
359 WebInspector.AdvancedSearchView.ToggleDrawerViewActionDelegate = function()
360 {
361 }
362
363 WebInspector.AdvancedSearchView.ToggleDrawerViewActionDelegate.prototype = {
364     /**
365      * @return {boolean}
366      */
367     handleAction: function()
368     {
369         var searchView = this._searchView();
370         if (!searchView)
371             return false;
372         if (!searchView.isShowing() || searchView._search !== document.activeElement) {
373             WebInspector.inspectorView.showPanel("sources");
374             searchView.toggle();
375         } else {
376             WebInspector.inspectorView.closeDrawer();
377         }
378         return true;
379     },
380
381     /**
382      * @return {?WebInspector.AdvancedSearchView}
383      */
384     _searchView: function()
385     {
386         if (!this._view) {
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();
391                     break;
392                 }
393             }
394         }
395         return this._view;
396     }
397 }
398
399
400 /**
401  * @constructor
402  * @param {!WebInspector.UISourceCode} uiSourceCode
403  * @param {!Array.<!Object>} searchMatches
404  */
405 WebInspector.FileBasedSearchResult = function(uiSourceCode, searchMatches) {
406     this.uiSourceCode = uiSourceCode;
407     this.searchMatches = searchMatches;
408 }
409
410 /**
411  * @interface
412  */
413 WebInspector.SearchScope = function()
414 {
415 }
416
417 WebInspector.SearchScope.prototype = {
418     /**
419      * @param {!WebInspector.SearchConfig} searchConfig
420      * @param {!WebInspector.Progress} progress
421      * @param {function(!WebInspector.FileBasedSearchResult)} searchResultCallback
422      * @param {function(boolean)} searchFinishedCallback
423      */
424     performSearch: function(searchConfig, progress, searchResultCallback, searchFinishedCallback) { },
425
426     /**
427      * @param {!WebInspector.Progress} progress
428      * @param {function(boolean)} callback
429      */
430     performIndexing: function(progress, callback) { },
431
432     stopSearch: function() { },
433
434     /**
435      * @param {!WebInspector.ProjectSearchConfig} searchConfig
436      * @return {!WebInspector.SearchResultsPane}
437      */
438     createSearchResultsPane: function(searchConfig) { }
439 }
440
441 importScript("FileBasedSearchResultsPane.js");
442 importScript("SourcesSearchScope.js");