Index: chrome/browser/resources/settings/search_settings.js |
diff --git a/chrome/browser/resources/settings/search_settings.js b/chrome/browser/resources/settings/search_settings.js |
index 78960bbf4448944de9d990a8bc82a03f3ce7f95a..30e03de6daeb4ac55a816529e032b0979a42e3a4 100644 |
--- a/chrome/browser/resources/settings/search_settings.js |
+++ b/chrome/browser/resources/settings/search_settings.js |
@@ -2,6 +2,20 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+cr.exportPath('settings'); |
+ |
+/** |
+ * A data structure used by callers to combine the results of multiple search |
+ * requests. |
+ * |
+ * @typedef {{ |
+ * canceled: Boolean, |
+ * didFindMatches: Boolean, |
+ * wasClearSearch: Boolean, |
+ * }} |
+ */ |
+settings.SearchResult; |
+ |
cr.define('settings', function() { |
/** @const {string} */ |
var WRAPPER_CSS_CLASS = 'search-highlight-wrapper'; |
@@ -125,8 +139,7 @@ cr.define('settings', function() { |
function doSearch(node) { |
if (node.nodeName == 'TEMPLATE' && node.hasAttribute('route-path') && |
!node.if && !node.hasAttribute(SKIP_SEARCH_CSS_ATTRIBUTE)) { |
- getSearchManager().queue_.addRenderTask( |
- new RenderTask(request, node)); |
+ request.queue_.addRenderTask(new RenderTask(request, node)); |
return; |
} |
@@ -304,7 +317,7 @@ cr.define('settings', function() { |
parent.querySelector('[route-path="' + routePath + '"]'); |
// Register a SearchAndHighlightTask for the part of the DOM that was |
// just rendered. |
- getSearchManager().queue_.addSearchAndHighlightTask( |
+ this.request.queue_.addSearchAndHighlightTask( |
new SearchAndHighlightTask(this.request, assert(renderedNode))); |
resolve(); |
}.bind(this)); |
@@ -372,8 +385,12 @@ cr.define('settings', function() { |
/** |
* @constructor |
+ * @param {!settings.SearchRequest} request |
*/ |
- function TaskQueue() { |
+ function TaskQueue(request) { |
+ /** @private {!settings.SearchRequest} */ |
+ this.request_ = request; |
+ |
/** |
* @private {{ |
* high: !Array<!Task>, |
@@ -452,18 +469,14 @@ cr.define('settings', function() { |
this.running_ = true; |
window.requestIdleCallback(function() { |
- function startNextTask() { |
- this.running_ = false; |
- this.consumePending_(); |
- } |
- if (task.request.id == |
- getSearchManager().activeRequest_.id) { |
- task.exec().then(startNextTask.bind(this)); |
- } else { |
- // Dropping this task without ever executing it, since a new search |
- // has been issued since this task was queued. |
- startNextTask.call(this); |
+ if (!this.request_.canceled) { |
+ task.exec().then(function() { |
+ this.running_ = false; |
+ this.consumePending_(); |
+ }.bind(this)); |
} |
+ // Nothing to do otherwise. Since the request corresponding to this |
+ // queue was canceled, the queue is disposed along with the request. |
}.bind(this)); |
return; |
} |
@@ -472,38 +485,52 @@ cr.define('settings', function() { |
/** |
* @constructor |
+ * |
+ * @param {string} rawQuery |
+ * @param {!HTMLElement} root |
*/ |
- var SearchRequest = function(rawQuery) { |
- /** @type {number} */ |
- this.id = SearchRequest.nextId_++; |
- |
+ var SearchRequest = function(rawQuery, root) { |
/** @private {string} */ |
this.rawQuery_ = rawQuery; |
+ /** @private {!HTMLElement} */ |
+ this.root_ = root; |
+ |
/** @type {?RegExp} */ |
this.regExp = this.generateRegExp_(); |
/** |
- * Whether this request was fully processed. |
+ * Whether this request was canceled before completing. |
* @type {boolean} |
*/ |
- this.finished = false; |
+ this.canceled = false; |
/** @private {boolean} */ |
this.foundMatches_ = false; |
/** @type {!PromiseResolver} */ |
this.resolver = new PromiseResolver(); |
- }; |
- /** @private {number} */ |
- SearchRequest.nextId_ = 0; |
+ /** @private {!TaskQueue} */ |
+ this.queue_ = new TaskQueue(this); |
+ this.queue_.onEmpty(function() { |
+ this.resolver.resolve(this); |
+ }.bind(this)); |
+ }; |
/** @private {!RegExp} */ |
SearchRequest.SANITIZE_REGEX_ = /[-[\]{}()*+?.,\\^$|#\s]/g; |
SearchRequest.prototype = { |
/** |
+ * Fires this search request. |
+ */ |
+ start: function() { |
+ this.queue_.addTopLevelSearchTask( |
+ new TopLevelSearchTask(this, this.root_)); |
+ }, |
+ |
+ /** |
* @return {?RegExp} |
* @private |
*/ |
@@ -561,37 +588,36 @@ cr.define('settings', function() { |
* @implements {SearchManager} |
*/ |
var SearchManagerImpl = function() { |
- /** @private {?settings.SearchRequest} */ |
- this.activeRequest_ = null; |
+ /** @private {!Set<!settings.SearchRequest>} */ |
+ this.activeRequests_ = new Set(); |
- /** @private {!TaskQueue} */ |
- this.queue_ = new TaskQueue(); |
- this.queue_.onEmpty(function() { |
- this.activeRequest_.finished = true; |
- this.activeRequest_.resolver.resolve(this.activeRequest_); |
- this.activeRequest_ = null; |
- }.bind(this)); |
+ /** @private {?string} */ |
+ this.lastSearchedText_ = null; |
}; |
cr.addSingletonGetter(SearchManagerImpl); |
SearchManagerImpl.prototype = { |
/** @override */ |
search: function(text, page) { |
- // Creating a new request only if the |text| changed. |
- if (!this.activeRequest_ || !this.activeRequest_.isSame(text)) { |
- // Resolving previous search request without marking it as |
- // 'finished', if any, and dropping all pending tasks. |
- this.queue_.reset(); |
- if (this.activeRequest_) |
- this.activeRequest_.resolver.resolve(this.activeRequest_); |
- |
- this.activeRequest_ = new SearchRequest(text); |
+ // Cancel any pending requests if a request with different text is |
+ // submitted. |
+ if (text != this.lastSearchedText_) { |
+ this.activeRequests_.forEach(function(request) { |
+ request.canceled = true; |
+ request.resolver.resolve(request); |
+ }); |
+ this.activeRequests_.clear(); |
} |
- this.queue_.addTopLevelSearchTask( |
- new TopLevelSearchTask(this.activeRequest_, page)); |
- |
- return this.activeRequest_.resolver.promise; |
+ this.lastSearchedText_ = text; |
+ var request = new SearchRequest(text, page); |
+ this.activeRequests_.add(request); |
+ request.start(); |
+ return request.resolver.promise.then(function() { |
+ // Stop tracking requests that finished. |
+ this.activeRequests_.delete(request); |
+ return request; |
+ }.bind(this)); |
}, |
}; |