| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** @typedef {{id: number, rawQuery: ?string, regExp: ?RegExp}} */ | |
| 6 var SearchContext; | |
| 7 | |
| 8 cr.define('settings', function() { | 5 cr.define('settings', function() { |
| 9 /** @const {string} */ | 6 /** @const {string} */ |
| 10 var WRAPPER_CSS_CLASS = 'search-highlight-wrapper'; | 7 var WRAPPER_CSS_CLASS = 'search-highlight-wrapper'; |
| 11 | 8 |
| 12 /** @const {string} */ | 9 /** @const {string} */ |
| 13 var HIT_CSS_CLASS = 'search-highlight-hit'; | 10 var HIT_CSS_CLASS = 'search-highlight-hit'; |
| 14 | 11 |
| 15 /** | 12 /** |
| 16 * List of elements types that should not be searched at all. | 13 * List of elements types that should not be searched at all. |
| 17 * The only DOM-MODULE node is in <body> which is not searched, therefore | 14 * The only DOM-MODULE node is in <body> which is not searched, therefore |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 } | 93 } |
| 97 } | 94 } |
| 98 } | 95 } |
| 99 | 96 |
| 100 /** | 97 /** |
| 101 * Traverses the entire DOM (including Shadow DOM), finds text nodes that | 98 * Traverses the entire DOM (including Shadow DOM), finds text nodes that |
| 102 * match the given regular expression and applies the highlight UI. It also | 99 * match the given regular expression and applies the highlight UI. It also |
| 103 * ensures that <settings-section> instances become visible if any matches | 100 * ensures that <settings-section> instances become visible if any matches |
| 104 * occurred under their subtree. | 101 * occurred under their subtree. |
| 105 * | 102 * |
| 106 * @param {!SearchContext} context | 103 * @param {!SearchRequest} request |
| 107 * @param {!Node} root The root of the sub-tree to be searched | 104 * @param {!Node} root The root of the sub-tree to be searched |
| 108 * @private | 105 * @private |
| 109 */ | 106 */ |
| 110 function findAndHighlightMatches_(context, root) { | 107 function findAndHighlightMatches_(request, root) { |
| 108 var foundMatches = false; |
| 111 function doSearch(node) { | 109 function doSearch(node) { |
| 112 if (node.nodeName == 'TEMPLATE' && node.hasAttribute('name') && | 110 if (node.nodeName == 'TEMPLATE' && node.hasAttribute('name') && |
| 113 !node.if) { | 111 !node.if) { |
| 114 getSearchManager().queue_.addRenderTask( | 112 getSearchManager().queue_.addRenderTask( |
| 115 new RenderTask(context, node)); | 113 new RenderTask(request, node)); |
| 116 return; | 114 return; |
| 117 } | 115 } |
| 118 | 116 |
| 119 if (IGNORED_ELEMENTS.has(node.nodeName)) | 117 if (IGNORED_ELEMENTS.has(node.nodeName)) |
| 120 return; | 118 return; |
| 121 | 119 |
| 122 if (node.nodeType == Node.TEXT_NODE) { | 120 if (node.nodeType == Node.TEXT_NODE) { |
| 123 var textContent = node.nodeValue.trim(); | 121 var textContent = node.nodeValue.trim(); |
| 124 if (textContent.length == 0) | 122 if (textContent.length == 0) |
| 125 return; | 123 return; |
| 126 | 124 |
| 127 if (context.regExp.test(textContent)) { | 125 if (request.regExp.test(textContent)) { |
| 126 foundMatches = true; |
| 128 revealParentSection_(node); | 127 revealParentSection_(node); |
| 129 highlight_(node, textContent.split(context.regExp)); | 128 highlight_(node, textContent.split(request.regExp)); |
| 130 } | 129 } |
| 131 // Returning early since TEXT_NODE nodes never have children. | 130 // Returning early since TEXT_NODE nodes never have children. |
| 132 return; | 131 return; |
| 133 } | 132 } |
| 134 | 133 |
| 135 var child = node.firstChild; | 134 var child = node.firstChild; |
| 136 while (child !== null) { | 135 while (child !== null) { |
| 137 // Getting a reference to the |nextSibling| before calling doSearch() | 136 // Getting a reference to the |nextSibling| before calling doSearch() |
| 138 // because |child| could be removed from the DOM within doSearch(). | 137 // because |child| could be removed from the DOM within doSearch(). |
| 139 var nextSibling = child.nextSibling; | 138 var nextSibling = child.nextSibling; |
| 140 doSearch(child); | 139 doSearch(child); |
| 141 child = nextSibling; | 140 child = nextSibling; |
| 142 } | 141 } |
| 143 | 142 |
| 144 var shadowRoot = node.shadowRoot; | 143 var shadowRoot = node.shadowRoot; |
| 145 if (shadowRoot) | 144 if (shadowRoot) |
| 146 doSearch(shadowRoot); | 145 doSearch(shadowRoot); |
| 147 } | 146 } |
| 148 | 147 |
| 149 doSearch(root); | 148 doSearch(root); |
| 149 return foundMatches; |
| 150 } | 150 } |
| 151 | 151 |
| 152 /** | 152 /** |
| 153 * Finds and makes visible the <settings-section> parent of |node|. | 153 * Finds and makes visible the <settings-section> parent of |node|. |
| 154 * @param {!Node} node | 154 * @param {!Node} node |
| 155 */ | 155 */ |
| 156 function revealParentSection_(node) { | 156 function revealParentSection_(node) { |
| 157 // Find corresponding SETTINGS-SECTION parent and make it visible. | 157 // Find corresponding SETTINGS-SECTION parent and make it visible. |
| 158 var parent = node; | 158 var parent = node; |
| 159 while (parent && parent.nodeName !== 'SETTINGS-SECTION') { | 159 while (parent && parent.nodeName !== 'SETTINGS-SECTION') { |
| 160 parent = parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? | 160 parent = parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? |
| 161 parent.host : parent.parentNode; | 161 parent.host : parent.parentNode; |
| 162 } | 162 } |
| 163 if (parent) | 163 if (parent) |
| 164 parent.hidden = false; | 164 parent.hidden = false; |
| 165 } | 165 } |
| 166 | 166 |
| 167 /** | 167 /** |
| 168 * @constructor | 168 * @constructor |
| 169 * | 169 * |
| 170 * @param {!SearchContext} context | 170 * @param {!SearchRequest} request |
| 171 * @param {!Node} node | 171 * @param {!Node} node |
| 172 */ | 172 */ |
| 173 function Task(context, node) { | 173 function Task(request, node) { |
| 174 /** @protected {!SearchContext} */ | 174 /** @protected {!SearchRequest} */ |
| 175 this.context = context; | 175 this.request = request; |
| 176 | 176 |
| 177 /** @protected {!Node} */ | 177 /** @protected {!Node} */ |
| 178 this.node = node; | 178 this.node = node; |
| 179 } | 179 } |
| 180 | 180 |
| 181 Task.prototype = { | 181 Task.prototype = { |
| 182 /** | 182 /** |
| 183 * @abstract | 183 * @abstract |
| 184 * @return {!Promise} | 184 * @return {!Promise} |
| 185 */ | 185 */ |
| 186 exec: function() {}, | 186 exec: function() {}, |
| 187 }; | 187 }; |
| 188 | 188 |
| 189 /** | 189 /** |
| 190 * A task that takes a <template is="dom-if">...</template> node corresponding | 190 * A task that takes a <template is="dom-if">...</template> node corresponding |
| 191 * to a setting subpage and renders it. A SearchAndHighlightTask is posted for | 191 * to a setting subpage and renders it. A SearchAndHighlightTask is posted for |
| 192 * the newly rendered subtree, once rendering is done. | 192 * the newly rendered subtree, once rendering is done. |
| 193 * @constructor | 193 * @constructor |
| 194 * @extends {Task} | 194 * @extends {Task} |
| 195 * | 195 * |
| 196 * @param {!SearchContext} context | 196 * @param {!SearchRequest} request |
| 197 * @param {!Node} node | 197 * @param {!Node} node |
| 198 */ | 198 */ |
| 199 function RenderTask(context, node) { | 199 function RenderTask(request, node) { |
| 200 Task.call(this, context, node); | 200 Task.call(this, request, node); |
| 201 } | 201 } |
| 202 | 202 |
| 203 RenderTask.prototype = { | 203 RenderTask.prototype = { |
| 204 /** @override */ | 204 /** @override */ |
| 205 exec: function() { | 205 exec: function() { |
| 206 var subpageTemplate = | 206 var subpageTemplate = |
| 207 this.node['_content'].querySelector('settings-subpage'); | 207 this.node['_content'].querySelector('settings-subpage'); |
| 208 subpageTemplate.id = subpageTemplate.id || this.node.getAttribute('name'); | 208 subpageTemplate.id = subpageTemplate.id || this.node.getAttribute('name'); |
| 209 assert(!this.node.if); | 209 assert(!this.node.if); |
| 210 this.node.if = true; | 210 this.node.if = true; |
| 211 | 211 |
| 212 return new Promise(function(resolve, reject) { | 212 return new Promise(function(resolve, reject) { |
| 213 var parent = this.node.parentNode; | 213 var parent = this.node.parentNode; |
| 214 parent.async(function() { | 214 parent.async(function() { |
| 215 var renderedNode = parent.querySelector('#' + subpageTemplate.id); | 215 var renderedNode = parent.querySelector('#' + subpageTemplate.id); |
| 216 // Register a SearchAndHighlightTask for the part of the DOM that was | 216 // Register a SearchAndHighlightTask for the part of the DOM that was |
| 217 // just rendered. | 217 // just rendered. |
| 218 getSearchManager().queue_.addSearchAndHighlightTask( | 218 getSearchManager().queue_.addSearchAndHighlightTask( |
| 219 new SearchAndHighlightTask(this.context, assert(renderedNode))); | 219 new SearchAndHighlightTask(this.request, assert(renderedNode))); |
| 220 resolve(); | 220 resolve(); |
| 221 }.bind(this)); | 221 }.bind(this)); |
| 222 }.bind(this)); | 222 }.bind(this)); |
| 223 }, | 223 }, |
| 224 }; | 224 }; |
| 225 | 225 |
| 226 /** | 226 /** |
| 227 * @constructor | 227 * @constructor |
| 228 * @extends {Task} | 228 * @extends {Task} |
| 229 * | 229 * |
| 230 * @param {!SearchContext} context | 230 * @param {!SearchRequest} request |
| 231 * @param {!Node} node | 231 * @param {!Node} node |
| 232 */ | 232 */ |
| 233 function SearchAndHighlightTask(context, node) { | 233 function SearchAndHighlightTask(request, node) { |
| 234 Task.call(this, context, node); | 234 Task.call(this, request, node); |
| 235 } | 235 } |
| 236 | 236 |
| 237 SearchAndHighlightTask.prototype = { | 237 SearchAndHighlightTask.prototype = { |
| 238 /** @override */ | 238 /** @override */ |
| 239 exec: function() { | 239 exec: function() { |
| 240 findAndHighlightMatches_(this.context, this.node); | 240 var foundMatches = findAndHighlightMatches_(this.request, this.node); |
| 241 this.request.updateMatches(foundMatches); |
| 241 return Promise.resolve(); | 242 return Promise.resolve(); |
| 242 }, | 243 }, |
| 243 }; | 244 }; |
| 244 | 245 |
| 245 /** | 246 /** |
| 246 * @constructor | 247 * @constructor |
| 247 * @extends {Task} | 248 * @extends {Task} |
| 248 * | 249 * |
| 249 * @param {!SearchContext} context | 250 * @param {!SearchRequest} request |
| 250 * @param {!Node} page | 251 * @param {!Node} page |
| 251 */ | 252 */ |
| 252 function TopLevelSearchTask(context, page) { | 253 function TopLevelSearchTask(request, page) { |
| 253 Task.call(this, context, page); | 254 Task.call(this, request, page); |
| 254 } | 255 } |
| 255 | 256 |
| 256 TopLevelSearchTask.prototype = { | 257 TopLevelSearchTask.prototype = { |
| 257 /** @override */ | 258 /** @override */ |
| 258 exec: function() { | 259 exec: function() { |
| 259 findAndRemoveHighlights_(this.node); | 260 findAndRemoveHighlights_(this.node); |
| 260 | 261 |
| 261 var shouldSearch = this.context.regExp !== null; | 262 var shouldSearch = this.request.regExp !== null; |
| 262 this.setSectionsVisibility_(!shouldSearch); | 263 this.setSectionsVisibility_(!shouldSearch); |
| 263 if (shouldSearch) | 264 if (shouldSearch) { |
| 264 findAndHighlightMatches_(this.context, this.node); | 265 var foundMatches = findAndHighlightMatches_(this.request, this.node); |
| 266 this.request.updateMatches(foundMatches); |
| 267 } |
| 265 | 268 |
| 266 return Promise.resolve(); | 269 return Promise.resolve(); |
| 267 }, | 270 }, |
| 268 | 271 |
| 269 /** | 272 /** |
| 270 * @param {boolean} visible | 273 * @param {boolean} visible |
| 271 * @private | 274 * @private |
| 272 */ | 275 */ |
| 273 setSectionsVisibility_: function(visible) { | 276 setSectionsVisibility_: function(visible) { |
| 274 var sections = Polymer.dom( | 277 var sections = Polymer.dom( |
| (...skipping 10 matching lines...) Expand all Loading... |
| 285 /** | 288 /** |
| 286 * @private {{ | 289 * @private {{ |
| 287 * high: !Array<!Task>, | 290 * high: !Array<!Task>, |
| 288 * middle: !Array<!Task>, | 291 * middle: !Array<!Task>, |
| 289 * low: !Array<!Task> | 292 * low: !Array<!Task> |
| 290 * }} | 293 * }} |
| 291 */ | 294 */ |
| 292 this.queues_; | 295 this.queues_; |
| 293 this.reset(); | 296 this.reset(); |
| 294 | 297 |
| 298 /** @private {?Function} */ |
| 299 this.onEmptyCallback_ = null; |
| 300 |
| 295 /** | 301 /** |
| 296 * Whether a task is currently running. | 302 * Whether a task is currently running. |
| 297 * @private {boolean} | 303 * @private {boolean} |
| 298 */ | 304 */ |
| 299 this.running_ = false; | 305 this.running_ = false; |
| 300 } | 306 } |
| 301 | 307 |
| 302 TaskQueue.prototype = { | 308 TaskQueue.prototype = { |
| 303 /** Drops all tasks. */ | 309 /** Drops all tasks. */ |
| 304 reset: function() { | 310 reset: function() { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 317 this.consumePending_(); | 323 this.consumePending_(); |
| 318 }, | 324 }, |
| 319 | 325 |
| 320 /** @param {!RenderTask} task */ | 326 /** @param {!RenderTask} task */ |
| 321 addRenderTask: function(task) { | 327 addRenderTask: function(task) { |
| 322 this.queues_.low.push(task); | 328 this.queues_.low.push(task); |
| 323 this.consumePending_(); | 329 this.consumePending_(); |
| 324 }, | 330 }, |
| 325 | 331 |
| 326 /** | 332 /** |
| 333 * Registers a callback to be called every time the queue becomes empty. |
| 334 * @param {function():void} onEmptyCallback |
| 335 */ |
| 336 onEmpty: function(onEmptyCallback) { |
| 337 this.onEmptyCallback_ = onEmptyCallback; |
| 338 }, |
| 339 |
| 340 /** |
| 327 * @return {!Task|undefined} | 341 * @return {!Task|undefined} |
| 328 * @private | 342 * @private |
| 329 */ | 343 */ |
| 330 popNextTask_: function() { | 344 popNextTask_: function() { |
| 331 return this.queues_.high.shift() || | 345 return this.queues_.high.shift() || |
| 332 this.queues_.middle.shift() || | 346 this.queues_.middle.shift() || |
| 333 this.queues_.low.shift(); | 347 this.queues_.low.shift(); |
| 334 }, | 348 }, |
| 335 | 349 |
| 336 /** @private */ | 350 /** @private */ |
| 337 consumePending_: function() { | 351 consumePending_: function() { |
| 338 if (this.running_) | 352 if (this.running_) |
| 339 return; | 353 return; |
| 340 | 354 |
| 341 while (1) { | 355 while (1) { |
| 342 var task = this.popNextTask_(); | 356 var task = this.popNextTask_(); |
| 343 if (!task) { | 357 if (!task) { |
| 344 this.running_ = false; | 358 this.running_ = false; |
| 345 getSearchManager().notifyCallback(false); | 359 if (this.onEmptyCallback_) |
| 360 this.onEmptyCallback_(); |
| 346 return; | 361 return; |
| 347 } | 362 } |
| 348 | 363 |
| 349 this.running_ = true; | 364 this.running_ = true; |
| 350 window.requestIdleCallback(function() { | 365 window.requestIdleCallback(function() { |
| 351 function startNextTask() { | 366 function startNextTask() { |
| 352 this.running_ = false; | 367 this.running_ = false; |
| 353 this.consumePending_(); | 368 this.consumePending_(); |
| 354 } | 369 } |
| 355 if (task.context.id == | 370 if (task.request.id == |
| 356 getSearchManager().activeContext_.id) { | 371 getSearchManager().activeRequest_.id) { |
| 357 task.exec().then(startNextTask.bind(this)); | 372 task.exec().then(startNextTask.bind(this)); |
| 358 } else { | 373 } else { |
| 359 // Dropping this task without ever executing it, since a new search | 374 // Dropping this task without ever executing it, since a new search |
| 360 // has been issued since this task was queued. | 375 // has been issued since this task was queued. |
| 361 startNextTask.call(this); | 376 startNextTask.call(this); |
| 362 } | 377 } |
| 363 }.bind(this)); | 378 }.bind(this)); |
| 364 return; | 379 return; |
| 365 } | 380 } |
| 366 }, | 381 }, |
| 367 }; | 382 }; |
| 368 | 383 |
| 369 /** | 384 /** |
| 370 * @constructor | 385 * @constructor |
| 371 */ | 386 */ |
| 387 var SearchRequest = function(rawQuery) { |
| 388 /** @type {number} */ |
| 389 this.id = SearchRequest.nextId_++; |
| 390 |
| 391 /** @private {string} */ |
| 392 this.rawQuery_ = rawQuery; |
| 393 |
| 394 /** @type {?RegExp} */ |
| 395 this.regExp = this.generateRegExp_(); |
| 396 |
| 397 /** |
| 398 * Whether this request was fully processed. |
| 399 * @type {boolean} |
| 400 */ |
| 401 this.finished = false; |
| 402 |
| 403 /** @private {boolean} */ |
| 404 this.foundMatches_ = false; |
| 405 |
| 406 /** @type {!PromiseResolver} */ |
| 407 this.resolver = new PromiseResolver(); |
| 408 }; |
| 409 |
| 410 /** @private {number} */ |
| 411 SearchRequest.nextId_ = 0; |
| 412 |
| 413 /** @private {!RegExp} */ |
| 414 SearchRequest.SANITIZE_REGEX_ = /[-[\]{}()*+?.,\\^$|#\s]/g; |
| 415 |
| 416 SearchRequest.prototype = { |
| 417 /** |
| 418 * @return {?RegExp} |
| 419 * @private |
| 420 */ |
| 421 generateRegExp_: function() { |
| 422 var regExp = null; |
| 423 |
| 424 // Generate search text by escaping any characters that would be |
| 425 // problematic for regular expressions. |
| 426 var searchText = this.rawQuery_.trim().replace( |
| 427 SearchRequest.SANITIZE_REGEX_, '\\$&'); |
| 428 if (searchText.length > 0) |
| 429 regExp = new RegExp('(' + searchText + ')', 'i'); |
| 430 |
| 431 return regExp; |
| 432 }, |
| 433 |
| 434 /** |
| 435 * @param {string} rawQuery |
| 436 * @return {boolean} Whether this SearchRequest refers to an identical |
| 437 * query. |
| 438 */ |
| 439 isSame: function(rawQuery) { |
| 440 return this.rawQuery_ == rawQuery; |
| 441 }, |
| 442 |
| 443 /** |
| 444 * Updates the result for this search request. |
| 445 * @param {boolean} found |
| 446 */ |
| 447 updateMatches: function(found) { |
| 448 this.foundMatches_ = this.foundMatches_ || found; |
| 449 }, |
| 450 |
| 451 /** @return {boolean} Whether any matches were found. */ |
| 452 didFindMatches: function() { |
| 453 return this.foundMatches_; |
| 454 }, |
| 455 }; |
| 456 |
| 457 /** |
| 458 * @constructor |
| 459 */ |
| 372 var SearchManager = function() { | 460 var SearchManager = function() { |
| 461 /** @private {?SearchRequest} */ |
| 462 this.activeRequest_ = null; |
| 463 |
| 373 /** @private {!TaskQueue} */ | 464 /** @private {!TaskQueue} */ |
| 374 this.queue_ = new TaskQueue(); | 465 this.queue_ = new TaskQueue(); |
| 375 | 466 this.queue_.onEmpty(function() { |
| 376 /** @private {!SearchContext} */ | 467 this.activeRequest_.finished = true; |
| 377 this.activeContext_ = {id: 0, rawQuery: null, regExp: null}; | 468 this.activeRequest_.resolver.resolve(this.activeRequest_); |
| 378 | 469 this.activeRequest_ = null; |
| 379 /** @private {?function(boolean):void} */ | 470 }.bind(this)); |
| 380 this.callbackFn_ = null; | |
| 381 }; | 471 }; |
| 382 cr.addSingletonGetter(SearchManager); | 472 cr.addSingletonGetter(SearchManager); |
| 383 | 473 |
| 384 /** @private @const {!RegExp} */ | |
| 385 SearchManager.SANITIZE_REGEX_ = /[-[\]{}()*+?.,\\^$|#\s]/g; | |
| 386 | |
| 387 SearchManager.prototype = { | 474 SearchManager.prototype = { |
| 388 /** | 475 /** |
| 389 * Registers a callback function that will be called every time search | |
| 390 * starts/finishes. | |
| 391 * @param {?function(boolean):void} callbackFn | |
| 392 */ | |
| 393 setCallback: function(callbackFn) { | |
| 394 this.callbackFn_ = callbackFn; | |
| 395 }, | |
| 396 | |
| 397 /** @param {boolean} isRunning */ | |
| 398 notifyCallback: function(isRunning) { | |
| 399 if (this.callbackFn_) | |
| 400 this.callbackFn_(isRunning); | |
| 401 }, | |
| 402 | |
| 403 /** | |
| 404 * @param {string} text The text to search for. | 476 * @param {string} text The text to search for. |
| 405 * @param {!Node} page | 477 * @param {!Node} page |
| 478 * @return {!Promise<!SearchRequest>} A signal indicating that searching |
| 479 * finished. |
| 406 */ | 480 */ |
| 407 search: function(text, page) { | 481 search: function(text, page) { |
| 408 if (this.activeContext_.rawQuery != text) { | 482 // Creating a new request only if the |text| changed. |
| 409 var newId = this.activeContext_.id + 1; | 483 if (!this.activeRequest_ || !this.activeRequest_.isSame(text)) { |
| 484 // Resolving previous search request without marking it as |
| 485 // 'finisthed', if any, and droping all pending tasks. |
| 486 this.queue_.reset(); |
| 487 if (this.activeRequest_) |
| 488 this.activeRequest_.resolver.resolve(this.activeRequest_); |
| 410 | 489 |
| 411 var regExp = null; | 490 this.activeRequest_ = new SearchRequest(text); |
| 412 // Generate search text by escaping any characters that would be | |
| 413 // problematic for regular expressions. | |
| 414 var searchText = text.trim().replace( | |
| 415 SearchManager.SANITIZE_REGEX_, '\\$&'); | |
| 416 if (searchText.length > 0) | |
| 417 regExp = new RegExp('(' + searchText + ')', 'i'); | |
| 418 | |
| 419 this.activeContext_ = {id: newId, rawQuery: text, regExp: regExp}; | |
| 420 | |
| 421 // Drop all previously scheduled tasks, since a new search was just | |
| 422 // issued. | |
| 423 this.queue_.reset(); | |
| 424 this.notifyCallback(true); | |
| 425 } | 491 } |
| 426 | 492 |
| 427 this.queue_.addTopLevelSearchTask( | 493 this.queue_.addTopLevelSearchTask( |
| 428 new TopLevelSearchTask(this.activeContext_, page)); | 494 new TopLevelSearchTask(this.activeRequest_, page)); |
| 495 |
| 496 return this.activeRequest_.resolver.promise; |
| 429 }, | 497 }, |
| 430 }; | 498 }; |
| 431 | 499 |
| 432 /** @return {!SearchManager} */ | 500 /** @return {!SearchManager} */ |
| 433 function getSearchManager() { | 501 function getSearchManager() { |
| 434 return SearchManager.getInstance(); | 502 return SearchManager.getInstance(); |
| 435 } | 503 } |
| 436 | 504 |
| 437 return { | 505 return { |
| 438 getSearchManager: getSearchManager, | 506 getSearchManager: getSearchManager, |
| 439 }; | 507 }; |
| 440 }); | 508 }); |
| OLD | NEW |