blob: 5f2aa1333348cfca5fe8525de9e90ee5ee6d42b7 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @unrestricted
*/
Sources.AdvancedSearchView = class extends UI.VBox {
constructor() {
super(true);
this.setMinimumSize(0, 40);
this.registerRequiredCSS('sources/sourcesSearch.css');
this._searchId = 0;
this.contentElement.classList.add('search-view');
this._searchPanelElement = this.contentElement.createChild('div', 'search-drawer-header');
this._searchPanelElement.addEventListener('keydown', this._onKeyDown.bind(this), false);
this._searchPanelElement.addEventListener('input', this._onInput.bind(this), false);
this._searchResultsElement = this.contentElement.createChild('div');
this._searchResultsElement.className = 'search-results';
this._search = UI.HistoryInput.create();
this._searchPanelElement.appendChild(this._search);
this._search.placeholder = Common.UIString('Search all sources (use "file:" to filter by path)\u200e');
this._search.setAttribute('type', 'text');
this._search.classList.add('search-config-search');
this._search.setAttribute('results', '0');
this._search.setAttribute('size', 42);
this._searchPanelElement.createChild('div', 'search-icon');
this._searchInputClearElement = this._searchPanelElement.createChild('div', 'search-cancel-button');
this._searchInputClearElement.hidden = true;
this._searchInputClearElement.addEventListener('click', this._onSearchInputClear.bind(this), false);
this._ignoreCaseLabel = createCheckboxLabel(Common.UIString('Ignore case'));
this._ignoreCaseLabel.classList.add('search-config-label');
this._searchPanelElement.appendChild(this._ignoreCaseLabel);
this._ignoreCaseCheckbox = this._ignoreCaseLabel.checkboxElement;
this._ignoreCaseCheckbox.classList.add('search-config-checkbox');
this._regexLabel = createCheckboxLabel(Common.UIString('Regular expression'));
this._regexLabel.classList.add('search-config-label');
this._searchPanelElement.appendChild(this._regexLabel);
this._regexCheckbox = this._regexLabel.checkboxElement;
this._regexCheckbox.classList.add('search-config-checkbox');
this._searchToolbarElement = this.contentElement.createChild('div', 'search-toolbar-summary');
this._searchMessageElement = this._searchToolbarElement.createChild('div', 'search-message');
this._searchProgressPlaceholderElement = this._searchToolbarElement.createChild('div', 'flex-centered');
this._searchResultsMessageElement = this._searchToolbarElement.createChild('div', 'search-message');
this._advancedSearchConfig = Common.settings.createLocalSetting(
'advancedSearchConfig', new Workspace.SearchConfig('', true, false).toPlainObject());
this._load();
/** @type {!Sources.SearchScope} */
this._searchScope = new Sources.SourcesSearchScope();
}
/**
* @param {string} query
* @param {string=} filePath
*/
static openSearch(query, filePath) {
UI.viewManager.showView('sources.search');
var searchView =
/** @type {!Sources.AdvancedSearchView} */ (self.runtime.sharedInstance(Sources.AdvancedSearchView));
var fileMask = filePath ? ' file:' + filePath : '';
searchView._toggle(query + fileMask);
}
/**
* @return {!Workspace.SearchConfig}
*/
_buildSearchConfig() {
return new Workspace.SearchConfig(
this._search.value, this._ignoreCaseCheckbox.checked, this._regexCheckbox.checked);
}
/**
* @param {string} queryCandidate
*/
_toggle(queryCandidate) {
if (queryCandidate)
this._search.value = queryCandidate;
if (this.isShowing())
this.focus();
else
this._focusOnShow = true;
this._startIndexing();
}
/**
* @override
*/
wasShown() {
if (this._focusOnShow) {
this.focus();
delete this._focusOnShow;
}
}
_onIndexingFinished() {
var finished = !this._progressIndicator.isCanceled();
this._progressIndicator.done();
delete this._progressIndicator;
delete this._isIndexing;
this._indexingFinished(finished);
if (!finished)
delete this._pendingSearchConfig;
if (!this._pendingSearchConfig)
return;
var searchConfig = this._pendingSearchConfig;
delete this._pendingSearchConfig;
this._innerStartSearch(searchConfig);
}
_startIndexing() {
this._isIndexing = true;
if (this._progressIndicator)
this._progressIndicator.done();
this._progressIndicator = new UI.ProgressIndicator();
this._searchMessageElement.textContent = Common.UIString('Indexing\u2026');
this._progressIndicator.show(this._searchProgressPlaceholderElement);
this._searchScope.performIndexing(
new Common.ProgressProxy(this._progressIndicator, this._onIndexingFinished.bind(this)));
}
_onSearchInputClear() {
this._search.value = '';
this.focus();
this._searchInputClearElement.hidden = true;
}
/**
* @param {number} searchId
* @param {!Sources.FileBasedSearchResult} searchResult
*/
_onSearchResult(searchId, searchResult) {
if (searchId !== this._searchId || !this._progressIndicator)
return;
if (this._progressIndicator && this._progressIndicator.isCanceled()) {
this._onIndexingFinished();
return;
}
this._addSearchResult(searchResult);
if (!searchResult.searchMatches.length)
return;
if (!this._searchResultsPane)
this._searchResultsPane = this._searchScope.createSearchResultsPane(this._searchConfig);
this._resetResults();
this._searchResultsElement.appendChild(this._searchResultsPane.element);
this._searchResultsPane.addSearchResult(searchResult);
}
/**
* @param {number} searchId
* @param {boolean} finished
*/
_onSearchFinished(searchId, finished) {
if (searchId !== this._searchId || !this._progressIndicator)
return;
if (!this._searchResultsPane)
this._nothingFound();
this._searchFinished(finished);
delete this._searchConfig;
}
/**
* @param {!Workspace.SearchConfig} searchConfig
*/
_startSearch(searchConfig) {
this._resetSearch();
++this._searchId;
if (!this._isIndexing)
this._startIndexing();
this._pendingSearchConfig = searchConfig;
}
/**
* @param {!Workspace.SearchConfig} searchConfig
*/
_innerStartSearch(searchConfig) {
this._searchConfig = searchConfig;
if (this._progressIndicator)
this._progressIndicator.done();
this._progressIndicator = new UI.ProgressIndicator();
this._searchStarted(this._progressIndicator);
this._searchScope.performSearch(
searchConfig, this._progressIndicator, this._onSearchResult.bind(this, this._searchId),
this._onSearchFinished.bind(this, this._searchId));
}
_resetSearch() {
this._stopSearch();
if (this._searchResultsPane) {
this._resetResults();
delete this._searchResultsPane;
}
}
_stopSearch() {
if (this._progressIndicator && !this._isIndexing)
this._progressIndicator.cancel();
if (this._searchScope)
this._searchScope.stopSearch();
delete this._searchConfig;
}
/**
* @param {!UI.ProgressIndicator} progressIndicator
*/
_searchStarted(progressIndicator) {
this._resetResults();
this._resetCounters();
this._searchMessageElement.textContent = Common.UIString('Searching\u2026');
progressIndicator.show(this._searchProgressPlaceholderElement);
this._updateSearchResultsMessage();
if (!this._searchingView)
this._searchingView = new UI.EmptyWidget(Common.UIString('Searching\u2026'));
this._searchingView.show(this._searchResultsElement);
}
/**
* @param {boolean} finished
*/
_indexingFinished(finished) {
this._searchMessageElement.textContent = finished ? '' : Common.UIString('Indexing interrupted.');
}
_updateSearchResultsMessage() {
if (this._searchMatchesCount && this._searchResultsCount)
this._searchResultsMessageElement.textContent = Common.UIString(
'Found %d matches in %d files.', this._searchMatchesCount, this._nonEmptySearchResultsCount);
else
this._searchResultsMessageElement.textContent = '';
}
_resetResults() {
if (this._searchingView)
this._searchingView.detach();
if (this._notFoundView)
this._notFoundView.detach();
this._searchResultsElement.removeChildren();
}
_resetCounters() {
this._searchMatchesCount = 0;
this._searchResultsCount = 0;
this._nonEmptySearchResultsCount = 0;
}
_nothingFound() {
this._resetResults();
if (!this._notFoundView)
this._notFoundView = new UI.EmptyWidget(Common.UIString('No matches found.'));
this._notFoundView.show(this._searchResultsElement);
this._searchResultsMessageElement.textContent = Common.UIString('No matches found.');
}
/**
* @param {!Sources.FileBasedSearchResult} searchResult
*/
_addSearchResult(searchResult) {
this._searchMatchesCount += searchResult.searchMatches.length;
this._searchResultsCount++;
if (searchResult.searchMatches.length)
this._nonEmptySearchResultsCount++;
this._updateSearchResultsMessage();
}
/**
* @param {boolean} finished
*/
_searchFinished(finished) {
this._searchMessageElement.textContent =
finished ? Common.UIString('Search finished.') : Common.UIString('Search interrupted.');
}
/**
* @override
*/
focus() {
this._search.focus();
this._search.select();
}
/**
* @override
*/
willHide() {
this._stopSearch();
}
/**
* @param {!Event} event
*/
_onKeyDown(event) {
switch (event.keyCode) {
case UI.KeyboardShortcut.Keys.Enter.code:
this._onAction();
break;
}
}
_onInput() {
if (this._search.value && this._search.value.length)
this._searchInputClearElement.hidden = false;
else
this._searchInputClearElement.hidden = true;
}
_save() {
this._advancedSearchConfig.set(this._buildSearchConfig().toPlainObject());
}
_load() {
var searchConfig = Workspace.SearchConfig.fromPlainObject(this._advancedSearchConfig.get());
this._search.value = searchConfig.query();
this._ignoreCaseCheckbox.checked = searchConfig.ignoreCase();
this._regexCheckbox.checked = searchConfig.isRegex();
if (this._search.value && this._search.value.length)
this._searchInputClearElement.hidden = false;
}
_onAction() {
var searchConfig = this._buildSearchConfig();
if (!searchConfig.query() || !searchConfig.query().length)
return;
this._save();
this._startSearch(searchConfig);
}
};
/**
* @unrestricted
*/
Sources.SearchResultsPane = class {
/**
* @param {!Workspace.ProjectSearchConfig} searchConfig
*/
constructor(searchConfig) {
this._searchConfig = searchConfig;
this.element = createElement('div');
}
/**
* @return {!Workspace.ProjectSearchConfig}
*/
get searchConfig() {
return this._searchConfig;
}
/**
* @param {!Sources.FileBasedSearchResult} searchResult
*/
addSearchResult(searchResult) {
}
};
/**
* @implements {UI.ActionDelegate}
* @unrestricted
*/
Sources.AdvancedSearchView.ActionDelegate = class {
/**
* @override
* @param {!UI.Context} context
* @param {string} actionId
* @return {boolean}
*/
handleAction(context, actionId) {
this._showSearch();
return true;
}
_showSearch() {
var selection = UI.inspectorView.element.getDeepSelection();
var queryCandidate = '';
if (selection.rangeCount)
queryCandidate = selection.toString().replace(/\r?\n.*/, '');
Sources.AdvancedSearchView.openSearch(queryCandidate);
}
};
/**
* @unrestricted
*/
Sources.FileBasedSearchResult = class {
/**
* @param {!Workspace.UISourceCode} uiSourceCode
* @param {!Array.<!Object>} searchMatches
*/
constructor(uiSourceCode, searchMatches) {
this.uiSourceCode = uiSourceCode;
this.searchMatches = searchMatches;
}
};
/**
* @interface
*/
Sources.SearchScope = function() {};
Sources.SearchScope.prototype = {
/**
* @param {!Workspace.SearchConfig} searchConfig
* @param {!Common.Progress} progress
* @param {function(!Sources.FileBasedSearchResult)} searchResultCallback
* @param {function(boolean)} searchFinishedCallback
*/
performSearch: function(searchConfig, progress, searchResultCallback, searchFinishedCallback) {},
/**
* @param {!Common.Progress} progress
*/
performIndexing: function(progress) {},
stopSearch: function() {},
/**
* @param {!Workspace.ProjectSearchConfig} searchConfig
* @return {!Sources.SearchResultsPane}
*/
createSearchResultsPane: function(searchConfig) {}
};