Modified: trunk/Source/WebCore/inspector/front-end/AdvancedSearchController.js (98104 => 98105)
--- trunk/Source/WebCore/inspector/front-end/AdvancedSearchController.js 2011-10-21 16:42:19 UTC (rev 98104)
+++ trunk/Source/WebCore/inspector/front-end/AdvancedSearchController.js 2011-10-21 16:58:58 UTC (rev 98105)
@@ -83,6 +83,10 @@
if (searchId !== this._searchId)
return;
+ this._searchView.addSearchResult(searchResult);
+ if (!searchResult.searchMatches.length)
+ return;
+
if (!this._searchResultsPane)
this._searchResultsPane = this._currentSearchScope.createSearchResultsPane(this._searchConfig);
this._searchView.resultsPane = this._searchResultsPane;
@@ -91,8 +95,9 @@
/**
* @param {number} searchId
+ * @param {boolean} finished
*/
- _onSearchFinished: function(searchId)
+ _onSearchFinished: function(searchId, finished)
{
if (searchId !== this._searchId)
return;
@@ -100,7 +105,7 @@
if (!this._searchResultsPane)
this._searchView.nothingFound();
- this._searchView.searchFinished();
+ this._searchView.searchFinished(finished);
},
/**
@@ -108,20 +113,29 @@
*/
startSearch: function(searchConfig)
{
- this.stopSearch();
+ this.resetSearch();
+ ++this._searchId;
this._searchConfig = searchConfig;
// FIXME: this._currentSearchScope should be initialized based on searchConfig
this._currentSearchScope = this._searchScope;
- this._searchView.searchStarted();
- this._currentSearchScope.performSearch(searchConfig, this._onSearchResult.bind(this, this._searchId), this._onSearchFinished.bind(this, this._searchId));
+ var totalSearchResultsCount = this._currentSearchScope.performSearch(searchConfig, this._onSearchResult.bind(this, this._searchId), this._onSearchFinished.bind(this, this._searchId));
+ this._searchView.searchStarted(totalSearchResultsCount);
},
+ resetSearch: function()
+ {
+ this.stopSearch();
+
+ if (this._searchResultsPane) {
+ this._searchView.resetResults();
+ delete this._searchResultsPane;
+ }
+ },
+
stopSearch: function()
{
- ++this._searchId;
- delete this._searchResultsPane;
if (this._currentSearchScope)
this._currentSearchScope.stopSearch();
}
@@ -162,7 +176,6 @@
this._ignoreCaseCheckbox.addStyleClass("search-config-checkbox");
this._ignoreCaseLabel.appendChild(document.createTextNode(WebInspector.UIString("Ignore case")));
-
this._regexLabel = this._searchPanelElement.createChild("label");
this._regexLabel.addStyleClass("search-config-label");
this._regexCheckbox = this._regexLabel.createChild("input");
@@ -170,6 +183,22 @@
this._regexCheckbox.addStyleClass("search-config-checkbox");
this._regexLabel.appendChild(document.createTextNode(WebInspector.UIString("Regular _expression_")));
+ this._searchStatusBarElement = document.createElement("div");
+ this._searchStatusBarElement.className = "search-status-bar-item";
+ this._searchMessageElement = this._searchStatusBarElement.createChild("div");
+ this._searchMessageElement.className = "search-status-bar-message";
+ this._searchProgressElement = document.createElement("progress");
+ this._searchProgressElement.className = "search-status-bar-progress";
+
+ this._searchStopButtonItem = document.createElement("div");
+ this._searchStopButtonItem.className = "search-status-bar-stop-button-item";
+ this._searchStopStatusBarButton = new WebInspector.StatusBarButton(WebInspector.UIString("Stop search"), "search-status-bar-stop-button");
+ this._searchStopButtonItem.appendChild(this._searchStopStatusBarButton.element);
+ this._searchStopStatusBarButton.addEventListener("click", this._searchStopButtonPressed, this);
+
+ this._searchResultsMessageElement = document.createElement("span");
+ this._searchResultsMessageElement.className = "search-results-status-bar-message";
+
this._load();
}
@@ -178,6 +207,22 @@
WebInspector.SearchView.prototype = {
/**
+ * @type {Array.<Element>}
+ */
+ get statusBarItems()
+ {
+ return [this._searchStatusBarElement];
+ },
+
+ /**
+ * @type {Element}
+ */
+ get counterElement()
+ {
+ return this._searchResultsMessageElement;
+ },
+
+ /**
* @type {WebInspector.SearchConfig}
*/
get searchConfig()
@@ -194,31 +239,89 @@
*/
set resultsPane(resultsPane)
{
- this._searchResultsElement.removeChildren();
+ this.resetResults();
this._searchResultsElement.appendChild(resultsPane.element);
},
- searchStarted: function()
+ /**
+ * @param {number} totalSearchResultsCount
+ */
+ searchStarted: function(totalSearchResultsCount)
{
- // FIXME: This needs better UI.
- var searchingView = new WebInspector.EmptyView(WebInspector.UIString("Searching..."))
- this._searchResultsElement.removeChildren();
+ this.resetResults();
+ this._resetCounters();
+
+ this._totalSearchResultsCount = totalSearchResultsCount;
+
+ this._searchMessageElement.textContent = WebInspector.UIString("Searching...");
+ this._searchStatusBarElement.appendChild(this._searchProgressElement);
+ this._searchStatusBarElement.appendChild(this._searchStopButtonItem);
+ this._updateSearchProgress();
+
+ this._updateSearchResultsMessage();
+
+ var searchingView = new WebInspector.EmptyView(WebInspector.UIString("Searching..."));
searchingView.show(this._searchResultsElement);
},
+ _updateSearchResultsMessage: function()
+ {
+ if (this._searchMatchesCount && this._searchResultsCount)
+ this._searchResultsMessageElement.textContent = WebInspector.UIString("Found %d matches in %d files.", this._searchMatchesCount, this._nonEmptySearchResultsCount);
+ else
+ this._searchResultsMessageElement.textContent = "";
+ },
+
+ _updateSearchProgress: function()
+ {
+ this._searchProgressElement.setAttribute("max", this._totalSearchResultsCount);
+ this._searchProgressElement.setAttribute("value", this._searchResultsCount);
+ },
+
+ resetResults: function()
+ {
+ this._searchResultsElement.removeChildren();
+ },
+
+ _resetCounters: function()
+ {
+ this._searchMatchesCount = 0;
+ this._searchResultsCount = 0;
+ this._nonEmptySearchResultsCount = 0;
+ },
+
nothingFound: function()
{
- // FIXME: This needs better UI.
- var notFoundView = new WebInspector.EmptyView(WebInspector.UIString("Nothing found"))
- this._searchResultsElement.removeChildren();
+ this.resetResults();
+
+ var notFoundView = new WebInspector.EmptyView(WebInspector.UIString("No matches found."));
notFoundView.show(this._searchResultsElement);
+ this._searchResultsMessageElement.textContent = WebInspector.UIString("No matches found.");
},
- searchFinished: function()
+ /**
+ * @param {Object} searchResult
+ */
+ addSearchResult: function(searchResult)
{
- // FIXME: add message to drawer status bar
+ this._searchMatchesCount += searchResult.searchMatches.length;
+ this._searchResultsCount++;
+ if (searchResult.searchMatches.length)
+ this._nonEmptySearchResultsCount++;
+ this._updateSearchResultsMessage();
+ this._updateSearchProgress();
},
+ /**
+ * @param {boolean} finished
+ */
+ searchFinished: function(finished)
+ {
+ this._searchMessageElement.textContent = finished ? WebInspector.UIString("Search finished.") : WebInspector.UIString("Search interrupted.");
+ this._searchStatusBarElement.removeChild(this._searchProgressElement);
+ this._searchStatusBarElement.removeChild(this._searchStopButtonItem);
+ },
+
focus: function()
{
WebInspector.currentFocusElement = this._search;
@@ -258,6 +361,12 @@
this._regexCheckbox.checked = searchConfig.isRegex;
},
+ _searchStopButtonPressed: function()
+ {
+ this._controller.stopSearch();
+ this.focus();
+ },
+
_onAction: function()
{
this._save();
@@ -290,6 +399,8 @@
WebInspector.SearchScope.prototype = {
/**
* @param {WebInspector.SearchConfig} searchConfig
+ * @param {function(Object)} searchResultCallback
+ * @param {function(boolean)} searchFinishedCallback
*/
performSearch: function(searchConfig, searchResultCallback, searchFinishedCallback) { },
@@ -342,10 +453,16 @@
this._treeOutlineElement = document.createElement("ol");
this._treeOutlineElement.className = "outline-disclosure";
+ this._treeOutlineElement.addStyleClass("search-results-outline-disclosure");
this.element.appendChild(this._treeOutlineElement);
this._treeOutline = new TreeOutline(this._treeOutlineElement);
+
+ this._matchesExpandedCount = 0;
}
+WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount = 20;
+WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce = 20;
+
WebInspector.FileBasedSearchResultsPane.prototype = {
/**
* @param {Object} file
@@ -354,13 +471,13 @@
* @return {Element}
*/
createAnchor: function(file, lineNumber, columnNumber) { },
-
+
/**
* @param {Object} file
* @return {string}
*/
fileName: function(file) { },
-
+
/**
* @param {Object} searchResult
*/
@@ -370,12 +487,43 @@
var file = searchResult.file;
var fileName = this.fileName(file);
var searchMatches = searchResult.searchMatches;
-
- // Expand first file with matches only.
- var fileTreeElement = this._addFileTreeElement(fileName, searchMatches.length, this._searchResults.length === 1);
+
+ var fileTreeElement = this._addFileTreeElement(fileName, searchMatches.length, this._searchResults.length - 1);
+ },
+
+ /**
+ * @param {Object} searchResult
+ * @param {TreeElement} fileTreeElement
+ */
+ _fileTreeElementExpanded: function(searchResult, fileTreeElement)
+ {
+ if (fileTreeElement._initialized)
+ return;
+ var toIndex = Math.min(searchResult.searchMatches.length, WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce);
+ if (toIndex < searchResult.searchMatches.length) {
+ this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex - 1);
+ this._appendShowMoreMatchesElement(fileTreeElement, searchResult, toIndex - 1);
+ } else
+ this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex);
+
+ fileTreeElement._initialized = true;
+ },
+
+ /**
+ * @param {TreeElement} fileTreeElement
+ * @param {Object} searchResult
+ * @param {number} fromIndex
+ * @param {number} toIndex
+ */
+ _appendSearchMatches: function(fileTreeElement, searchResult, fromIndex, toIndex)
+ {
+ var file = searchResult.file;
+ var fileName = this.fileName(file);
+ var searchMatches = searchResult.searchMatches;
+
var regex = createSearchRegex(this._searchConfig.query, !this._searchConfig.ignoreCase, this._searchConfig.isRegex);
- for (var i = 0; i < searchMatches.length; i++) {
+ for (var i = fromIndex; i < toIndex; ++i) {
var lineNumber = searchMatches[i].lineNumber;
var lineContent = searchMatches[i].lineContent;
var matchRanges = this._regexMatchRanges(lineContent, regex);
@@ -398,16 +546,42 @@
searchMatchElement.listItemElement.appendChild(anchor);
}
},
-
+
/**
+ * @param {TreeElement} fileTreeElement
+ * @param {Object} searchResult
+ * @param {number} startMatchIndex
+ */
+ _appendShowMoreMatchesElement: function(fileTreeElement, searchResult, startMatchIndex)
+ {
+ var matchesLeftCount = searchResult.searchMatches.length - startMatchIndex;
+ var showMoreMatchesText = WebInspector.UIString("Show all matches (%d more).", matchesLeftCount);
+ var showMoreMatchesElement = new TreeElement(showMoreMatchesText, null, false);
+ fileTreeElement.appendChild(showMoreMatchesElement);
+ showMoreMatchesElement.listItemElement.addStyleClass("show-more-matches");
+ showMoreMatchesElement._onselect_ = this._showMoreMatchesElementSelected.bind(this, searchResult, startMatchIndex);
+ },
+
+ /**
+ * @param {Object} searchResult
+ * @param {number} startMatchIndex
+ * @param {TreeElement} showMoreMatchesElement
+ */
+ _showMoreMatchesElementSelected: function(searchResult, startMatchIndex, showMoreMatchesElement)
+ {
+ var fileTreeElement = showMoreMatchesElement.parent;
+ fileTreeElement.removeChild(showMoreMatchesElement);
+ this._appendSearchMatches(fileTreeElement, searchResult, startMatchIndex, searchResult.searchMatches.length);
+ },
+
+ /**
* @param {string} fileName
* @param {number} searchMatchesCount
- * @param {boolean} expanded
+ * @param {number} searchResultIndex
*/
- _addFileTreeElement: function(fileName, searchMatchesCount, expanded)
+ _addFileTreeElement: function(fileName, searchMatchesCount, searchResultIndex)
{
var fileTreeElement = new TreeElement("", null, true);
- fileTreeElement.expanded = expanded;
fileTreeElement.toggleOnClick = true;
fileTreeElement.selectable = false;
@@ -428,6 +602,14 @@
fileTreeElement.listItemElement.appendChild(matchesCountSpan);
+ var searchResult = this._searchResults[searchResultIndex];
+ fileTreeElement._onexpand_ = this._fileTreeElementExpanded.bind(this, searchResult);
+
+ // Expand until at least certain amount of matches is expanded.
+ if (this._matchesExpandedCount < WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount)
+ fileTreeElement.expand();
+ this._matchesExpandedCount += searchResult.searchMatches.length;
+
return fileTreeElement;
},
@@ -442,7 +624,7 @@
var match;
var offset = 0;
var matchRanges = [];
- while (match = regex.exec(lineContent))
+ while ((regex.lastIndex < lineContent.length) && (match = regex.exec(lineContent)))
matchRanges.push({ offset: match.index, length: match[0].length });
return matchRanges;
Modified: trunk/Source/WebCore/inspector/front-end/ScriptsSearchScope.js (98104 => 98105)
--- trunk/Source/WebCore/inspector/front-end/ScriptsSearchScope.js 2011-10-21 16:42:19 UTC (rev 98104)
+++ trunk/Source/WebCore/inspector/front-end/ScriptsSearchScope.js 2011-10-21 16:58:58 UTC (rev 98105)
@@ -34,53 +34,60 @@
{
// FIXME: Add title once it is used by search controller.
WebInspector.SearchScope.call(this)
+ this._searchId = 0;
}
WebInspector.ScriptsSearchScope.prototype = {
/**
* @param {WebInspector.SearchConfig} searchConfig
* @param {function(Object)} searchResultCallback
- * @param {function()} searchFinishedCallback
+ * @param {function(boolean)} searchFinishedCallback
*/
performSearch: function(searchConfig, searchResultCallback, searchFinishedCallback)
{
- var callbacksLeft = 0;
-
- function maybeSearchFinished()
+ this.stopSearch();
+
+ var uiSourceCodes = this._sortedUISourceCodes();
+ var uiSourceCodeIndex = 0;
+
+ function filterOutContentScripts(uiSourceCode)
{
- if (callbacksLeft === 0)
- searchFinishedCallback();
+ return !uiSourceCode.isContentScript;
}
- function searchCallbackWrapper(uiSourceCode, searchMatches)
+ // FIXME: Add setting to search in content scripts as well.
+ uiSourceCodes.filter(filterOutContentScripts);
+
+ function continueSearch()
{
- if (searchMatches.length) {
- var searchResult = new WebInspector.FileBasedSearchResultsPane.SearchResult(uiSourceCode, searchMatches);
- searchResultCallback(searchResult);
+ // FIXME: Enable support for counting matches for incremental search.
+ // FIXME: Enable support for bounding search results/matches number to keep inspector responsive.
+ if (uiSourceCodeIndex < uiSourceCodes.length) {
+ var uiSourceCode = uiSourceCodes[uiSourceCodeIndex++];
+ uiSourceCode.searchInContent(searchConfig.query, !searchConfig.ignoreCase, searchConfig.isRegex, searchCallbackWrapper.bind(this, this._searchId, uiSourceCode));
+ } else
+ searchFinishedCallback(true);
+ }
+
+ function searchCallbackWrapper(searchId, uiSourceCode, searchMatches)
+ {
+ if (searchId !== this._searchId) {
+ searchFinishedCallback(false);
+ return;
}
- --callbacksLeft;
- maybeSearchFinished();
+
+ var searchResult = new WebInspector.FileBasedSearchResultsPane.SearchResult(uiSourceCode, searchMatches);
+ searchResultCallback(searchResult);
+ continueSearch.call(this);
}
- var uiSourceCodes = this._sortedUISourceCodes();
- // FIXME: Enable support for counting matches for incremental search.
- // FIXME: Enable support for bounding search results/matches number to keep inspector responsive.
- for (var i = 0; i < uiSourceCodes.length; i++) {
- var uiSourceCode = uiSourceCodes[i];
- // FIXME: Add setting to search in content scripts as well.
- if (!uiSourceCode.isContentScript) {
- // Increase callbacksLeft first because searchInContent call could be synchronous.
- callbacksLeft++;
- // FIXME: We should not request next searchInContent unless previous one is already finished.
- uiSourceCode.searchInContent(searchConfig.query, !searchConfig.ignoreCase, searchConfig.isRegex, searchCallbackWrapper.bind(this, uiSourceCode));
- }
- }
- maybeSearchFinished();
+ continueSearch.call(this);
+ return uiSourceCodes.length;
},
stopSearch: function()
{
- // FIXME: Implement search so that it could be stopped.
+ ++this._searchId;
},
/**
Modified: trunk/Source/WebCore/inspector/front-end/inspector.css (98104 => 98105)
--- trunk/Source/WebCore/inspector/front-end/inspector.css 2011-10-21 16:42:19 UTC (rev 98104)
+++ trunk/Source/WebCore/inspector/front-end/inspector.css 2011-10-21 16:58:58 UTC (rev 98105)
@@ -4159,6 +4159,43 @@
margin-bottom: 6px;
}
+#drawer-status-bar .search-status-bar-item {
+ cursor: pointer;
+ font-size: 11px;
+ height: 23px;
+}
+
+#drawer-status-bar .search-status-bar-message {
+ margin-left:5px;
+ margin-right:5px;
+ margin-top:6px;
+ float:left;
+}
+
+#drawer-status-bar .search-status-bar-progress {
+ height: 10px;
+ width: 100px;
+ margin-top: 8px;
+ float: left;
+}
+
+#drawer-status-bar .search-status-bar-stop-button-item {
+ width: 19px;
+ height: 24px;
+ overflow: hidden;
+}
+
+#drawer-status-bar .search-status-bar-stop-button .glyph {
+ -webkit-mask-position: -96px -48px;
+ background-color: rgb(216, 0, 0) !important;
+}
+
+#drawer-status-bar .search-results-status-bar-message {
+ margin-right: 10px;
+ cursor: default;
+ font-size: 11px;
+}
+
.search-view .search-results {
position: absolute;
top: 35px;
@@ -4166,15 +4203,25 @@
left: 0;
right: 0;
overflow-y: auto;
-
+}
+
+#search-results-pane-file-based .search-results-outline-disclosure {
padding-bottom: 5px;
}
#search-results-pane-file-based .search-result {
font-size: 12px;
margin-top: 3px;
+ word-wrap: normal;
+ white-space: pre;
+ cursor: pointer;
}
+#search-results-pane-file-based .search-result:hover {
+ background-color: rgba(121, 121, 121, 0.1);
+ -webkit-border-radius: 5px;
+}
+
#search-results-pane-file-based .search-result:first-child {
margin-top: 1px;
}
@@ -4190,6 +4237,17 @@
color: #333;
}
+#search-results-pane-file-based .show-more-matches {
+ margin-left: 5px;
+ color: #333;
+ cursor: pointer;
+}
+
+#search-results-pane-file-based .show-more-matches:hover {
+ text-decoration: underline;
+}
+
+
#search-results-pane-file-based .search-match {
font-family: 'dejavu sans mono', monospace;
font-size: 11px;
@@ -4208,7 +4266,7 @@
#search-results-pane-file-based .search-match:hover {
background-color: rgba(56, 121, 217, 0.1);
- -webkit-border-radius: 5px;*/
+ -webkit-border-radius: 5px;
}
#search-results-pane-file-based .search-match .highlighted-match {