Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(217)

Side by Side Diff: chrome/browser/resources/settings/search_settings.js

Issue 2940233002: WebUI: Allow using ES6 classes in the styleguide. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 cr.exportPath('settings'); 5 cr.exportPath('settings');
6 6
7 /** 7 /**
8 * A data structure used by callers to combine the results of multiple search 8 * A data structure used by callers to combine the results of multiple search
9 * requests. 9 * requests.
10 * 10 *
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 } 253 }
254 if (parent) 254 if (parent)
255 parent.hiddenBySearch = false; 255 parent.hiddenBySearch = false;
256 256
257 // Need to add the search bubble after the parent SETTINGS-SECTION has 257 // Need to add the search bubble after the parent SETTINGS-SECTION has
258 // become visible, otherwise |offsetWidth| returns zero. 258 // become visible, otherwise |offsetWidth| returns zero.
259 if (associatedControl) 259 if (associatedControl)
260 highlightAssociatedControl_(associatedControl, rawQuery); 260 highlightAssociatedControl_(associatedControl, rawQuery);
261 } 261 }
262 262
263 /** 263 /** @abstract */
264 * @constructor 264 class Task {
265 * 265 /**
266 * @param {!settings.SearchRequest} request 266 * @param {!settings.SearchRequest} request
267 * @param {!Node} node 267 * @param {!Node} node
268 */ 268 */
269 function Task(request, node) { 269 constructor(request, node) {
270 /** @protected {!settings.SearchRequest} */ 270 /** @protected {!settings.SearchRequest} */
271 this.request = request; 271 this.request = request;
272 272
273 /** @protected {!Node} */ 273 /** @protected {!Node} */
274 this.node = node; 274 this.node = node;
275 } 275 }
276 276
277 Task.prototype = {
278 /** 277 /**
279 * @abstract 278 * @abstract
280 * @return {!Promise} 279 * @return {!Promise}
281 */ 280 */
282 exec: function() {}, 281 exec() {}
283 };
284
285 /**
286 * A task that takes a <template is="dom-if">...</template> node corresponding
287 * to a setting subpage and renders it. A SearchAndHighlightTask is posted for
288 * the newly rendered subtree, once rendering is done.
289 * @constructor
290 * @extends {Task}
291 *
292 * @param {!settings.SearchRequest} request
293 * @param {!Node} node
294 */
295 function RenderTask(request, node) {
296 Task.call(this, request, node);
297 } 282 }
298 283
299 RenderTask.prototype = { 284 class RenderTask extends Task {
285 /**
286 * A task that takes a <template is="dom-if">...</template> node
287 * corresponding to a setting subpage and renders it. A
288 * SearchAndHighlightTask is posted for the newly rendered subtree, once
289 * rendering is done.
290 *
291 * @param {!settings.SearchRequest} request
292 * @param {!Node} node
293 */
294 constructor(request, node) {
295 super(request, node);
296 }
297
300 /** @override */ 298 /** @override */
301 exec: function() { 299 exec() {
302 var routePath = this.node.getAttribute('route-path'); 300 var routePath = this.node.getAttribute('route-path');
303 var subpageTemplate = 301 var subpageTemplate =
304 this.node['_content'].querySelector('settings-subpage'); 302 this.node['_content'].querySelector('settings-subpage');
305 subpageTemplate.setAttribute('route-path', routePath); 303 subpageTemplate.setAttribute('route-path', routePath);
306 assert(!this.node.if); 304 assert(!this.node.if);
307 this.node.if = true; 305 this.node.if = true;
308 306
309 return new Promise(function(resolve, reject) { 307 return new Promise(function(resolve, reject) {
310 var parent = this.node.parentNode; 308 var parent = this.node.parentNode;
311 parent.async(function() { 309 parent.async(function() {
312 var renderedNode = 310 var renderedNode =
313 parent.querySelector('[route-path="' + routePath + '"]'); 311 parent.querySelector('[route-path="' + routePath + '"]');
314 // Register a SearchAndHighlightTask for the part of the DOM that was 312 // Register a SearchAndHighlightTask for the part of the DOM that was
315 // just rendered. 313 // just rendered.
316 this.request.queue_.addSearchAndHighlightTask( 314 this.request.queue_.addSearchAndHighlightTask(
317 new SearchAndHighlightTask(this.request, assert(renderedNode))); 315 new SearchAndHighlightTask(this.request, assert(renderedNode)));
318 resolve(); 316 resolve();
319 }.bind(this)); 317 }.bind(this));
320 }.bind(this)); 318 }.bind(this));
321 }, 319 }
322 };
323
324 /**
325 * @constructor
326 * @extends {Task}
327 *
328 * @param {!settings.SearchRequest} request
329 * @param {!Node} node
330 */
331 function SearchAndHighlightTask(request, node) {
332 Task.call(this, request, node);
333 } 320 }
334 321
335 SearchAndHighlightTask.prototype = { 322 class SearchAndHighlightTask extends Task {
323 /**
324 * @param {!settings.SearchRequest} request
325 * @param {!Node} node
326 */
327 constructor(request, node) {
328 super(request, node);
329 }
330
336 /** @override */ 331 /** @override */
337 exec: function() { 332 exec() {
338 var foundMatches = findAndHighlightMatches_(this.request, this.node); 333 var foundMatches = findAndHighlightMatches_(this.request, this.node);
339 this.request.updateMatches(foundMatches); 334 this.request.updateMatches(foundMatches);
340 return Promise.resolve(); 335 return Promise.resolve();
341 }, 336 }
342 };
343
344 /**
345 * @constructor
346 * @extends {Task}
347 *
348 * @param {!settings.SearchRequest} request
349 * @param {!Node} page
350 */
351 function TopLevelSearchTask(request, page) {
352 Task.call(this, request, page);
353 } 337 }
354 338
355 TopLevelSearchTask.prototype = { 339 class TopLevelSearchTask extends Task {
340 /**
341 * @param {!settings.SearchRequest} request
342 * @param {!Node} page
343 */
344 constructor(request, page) {
345 super(request, page);
346 }
347
356 /** @override */ 348 /** @override */
357 exec: function() { 349 exec() {
358 findAndRemoveHighlights_(this.node); 350 findAndRemoveHighlights_(this.node);
359 351
360 var shouldSearch = this.request.regExp !== null; 352 var shouldSearch = this.request.regExp !== null;
361 this.setSectionsVisibility_(!shouldSearch); 353 this.setSectionsVisibility_(!shouldSearch);
362 if (shouldSearch) { 354 if (shouldSearch) {
363 var foundMatches = findAndHighlightMatches_(this.request, this.node); 355 var foundMatches = findAndHighlightMatches_(this.request, this.node);
364 this.request.updateMatches(foundMatches); 356 this.request.updateMatches(foundMatches);
365 } 357 }
366 358
367 return Promise.resolve(); 359 return Promise.resolve();
368 }, 360 }
369 361
370 /** 362 /**
371 * @param {boolean} visible 363 * @param {boolean} visible
372 * @private 364 * @private
373 */ 365 */
374 setSectionsVisibility_: function(visible) { 366 setSectionsVisibility_(visible) {
375 var sections = this.node.querySelectorAll('settings-section'); 367 var sections = this.node.querySelectorAll('settings-section');
376 368
377 for (var i = 0; i < sections.length; i++) 369 for (var i = 0; i < sections.length; i++)
378 sections[i].hiddenBySearch = !visible; 370 sections[i].hiddenBySearch = !visible;
379 }, 371 }
380 };
381
382 /**
383 * @constructor
384 * @param {!settings.SearchRequest} request
385 */
386 function TaskQueue(request) {
387 /** @private {!settings.SearchRequest} */
388 this.request_ = request;
389
390 /**
391 * @private {{
392 * high: !Array<!Task>,
393 * middle: !Array<!Task>,
394 * low: !Array<!Task>
395 * }}
396 */
397 this.queues_;
398 this.reset();
399
400 /** @private {?Function} */
401 this.onEmptyCallback_ = null;
402
403 /**
404 * Whether a task is currently running.
405 * @private {boolean}
406 */
407 this.running_ = false;
408 } 372 }
409 373
410 TaskQueue.prototype = { 374 class TaskQueue {
375 /** @param {!settings.SearchRequest} request */
376 constructor(request) {
377 /** @private {!settings.SearchRequest} */
378 this.request_ = request;
379
380 /**
381 * @private {{
382 * high: !Array<!Task>,
383 * middle: !Array<!Task>,
384 * low: !Array<!Task>
385 * }}
386 */
387 this.queues_;
388 this.reset();
389
390 /** @private {?Function} */
391 this.onEmptyCallback_ = null;
392
393 /**
394 * Whether a task is currently running.
395 * @private {boolean}
396 */
397 this.running_ = false;
398 }
399
411 /** Drops all tasks. */ 400 /** Drops all tasks. */
412 reset: function() { 401 reset() {
413 this.queues_ = {high: [], middle: [], low: []}; 402 this.queues_ = {high: [], middle: [], low: []};
414 }, 403 }
415 404
416 /** @param {!TopLevelSearchTask} task */ 405 /** @param {!TopLevelSearchTask} task */
417 addTopLevelSearchTask: function(task) { 406 addTopLevelSearchTask(task) {
418 this.queues_.high.push(task); 407 this.queues_.high.push(task);
419 this.consumePending_(); 408 this.consumePending_();
420 }, 409 }
421 410
422 /** @param {!SearchAndHighlightTask} task */ 411 /** @param {!SearchAndHighlightTask} task */
423 addSearchAndHighlightTask: function(task) { 412 addSearchAndHighlightTask(task) {
424 this.queues_.middle.push(task); 413 this.queues_.middle.push(task);
425 this.consumePending_(); 414 this.consumePending_();
426 }, 415 }
427 416
428 /** @param {!RenderTask} task */ 417 /** @param {!RenderTask} task */
429 addRenderTask: function(task) { 418 addRenderTask(task) {
430 this.queues_.low.push(task); 419 this.queues_.low.push(task);
431 this.consumePending_(); 420 this.consumePending_();
432 }, 421 }
433 422
434 /** 423 /**
435 * Registers a callback to be called every time the queue becomes empty. 424 * Registers a callback to be called every time the queue becomes empty.
436 * @param {function():void} onEmptyCallback 425 * @param {function():void} onEmptyCallback
437 */ 426 */
438 onEmpty: function(onEmptyCallback) { 427 onEmpty(onEmptyCallback) {
439 this.onEmptyCallback_ = onEmptyCallback; 428 this.onEmptyCallback_ = onEmptyCallback;
440 }, 429 }
441 430
442 /** 431 /**
443 * @return {!Task|undefined} 432 * @return {!Task|undefined}
444 * @private 433 * @private
445 */ 434 */
446 popNextTask_: function() { 435 popNextTask_() {
447 return this.queues_.high.shift() || 436 return this.queues_.high.shift() ||
448 this.queues_.middle.shift() || 437 this.queues_.middle.shift() ||
449 this.queues_.low.shift(); 438 this.queues_.low.shift();
450 }, 439 }
451 440
452 /** @private */ 441 /** @private */
453 consumePending_: function() { 442 consumePending_() {
454 if (this.running_) 443 if (this.running_)
455 return; 444 return;
456 445
457 while (1) { 446 while (1) {
458 var task = this.popNextTask_(); 447 var task = this.popNextTask_();
459 if (!task) { 448 if (!task) {
460 this.running_ = false; 449 this.running_ = false;
461 if (this.onEmptyCallback_) 450 if (this.onEmptyCallback_)
462 this.onEmptyCallback_(); 451 this.onEmptyCallback_();
463 return; 452 return;
464 } 453 }
465 454
466 this.running_ = true; 455 this.running_ = true;
467 window.requestIdleCallback(function() { 456 window.requestIdleCallback(function() {
468 if (!this.request_.canceled) { 457 if (!this.request_.canceled) {
469 task.exec().then(function() { 458 task.exec().then(function() {
470 this.running_ = false; 459 this.running_ = false;
471 this.consumePending_(); 460 this.consumePending_();
472 }.bind(this)); 461 }.bind(this));
473 } 462 }
474 // Nothing to do otherwise. Since the request corresponding to this 463 // Nothing to do otherwise. Since the request corresponding to this
475 // queue was canceled, the queue is disposed along with the request. 464 // queue was canceled, the queue is disposed along with the request.
476 }.bind(this)); 465 }.bind(this));
477 return; 466 return;
478 } 467 }
479 }, 468 }
480 }; 469 }
481 470
482 /** 471 class SearchRequest {
483 * @constructor 472 /**
484 * 473 * @param {string} rawQuery
485 * @param {string} rawQuery 474 * @param {!HTMLElement} root
486 * @param {!HTMLElement} root 475 */
487 */ 476 constructor(rawQuery, root) {
488 var SearchRequest = function(rawQuery, root) { 477 /** @private {string} */
489 /** @private {string} */ 478 this.rawQuery_ = rawQuery;
490 this.rawQuery_ = rawQuery;
491 479
492 /** @private {!HTMLElement} */ 480 /** @private {!HTMLElement} */
493 this.root_ = root; 481 this.root_ = root;
494 482
495 /** @type {?RegExp} */ 483 /** @type {?RegExp} */
496 this.regExp = this.generateRegExp_(); 484 this.regExp = this.generateRegExp_();
497 485
498 /** 486 /**
499 * Whether this request was canceled before completing. 487 * Whether this request was canceled before completing.
500 * @type {boolean} 488 * @type {boolean}
501 */ 489 */
502 this.canceled = false; 490 this.canceled = false;
503 491
504 /** @private {boolean} */ 492 /** @private {boolean} */
505 this.foundMatches_ = false; 493 this.foundMatches_ = false;
506 494
507 /** @type {!PromiseResolver} */ 495 /** @type {!PromiseResolver} */
508 this.resolver = new PromiseResolver(); 496 this.resolver = new PromiseResolver();
509 497
510 /** @private {!TaskQueue} */ 498 /** @private {!TaskQueue} */
511 this.queue_ = new TaskQueue(this); 499 this.queue_ = new TaskQueue(this);
512 this.queue_.onEmpty(function() { 500 this.queue_.onEmpty(function() {
513 this.resolver.resolve(this); 501 this.resolver.resolve(this);
514 }.bind(this)); 502 }.bind(this));
515 }; 503 }
516 504
517 /** @private {!RegExp} */
518 SearchRequest.SANITIZE_REGEX_ = /[-[\]{}()*+?.,\\^$|#\s]/g;
519
520 SearchRequest.prototype = {
521 /** 505 /**
522 * Fires this search request. 506 * Fires this search request.
523 */ 507 */
524 start: function() { 508 start() {
525 this.queue_.addTopLevelSearchTask( 509 this.queue_.addTopLevelSearchTask(
526 new TopLevelSearchTask(this, this.root_)); 510 new TopLevelSearchTask(this, this.root_));
527 }, 511 }
528 512
529 /** 513 /**
530 * @return {?RegExp} 514 * @return {?RegExp}
531 * @private 515 * @private
532 */ 516 */
533 generateRegExp_: function() { 517 generateRegExp_() {
534 var regExp = null; 518 var regExp = null;
535 519
536 // Generate search text by escaping any characters that would be 520 // Generate search text by escaping any characters that would be
537 // problematic for regular expressions. 521 // problematic for regular expressions.
538 var searchText = this.rawQuery_.trim().replace( 522 var searchText = this.rawQuery_.trim().replace(
539 SearchRequest.SANITIZE_REGEX_, '\\$&'); 523 SearchRequest.SANITIZE_REGEX_, '\\$&');
540 if (searchText.length > 0) 524 if (searchText.length > 0)
541 regExp = new RegExp('(' + searchText + ')', 'i'); 525 regExp = new RegExp('(' + searchText + ')', 'i');
542 526
543 return regExp; 527 return regExp;
544 }, 528 }
545 529
546 /** 530 /**
547 * @param {string} rawQuery 531 * @param {string} rawQuery
548 * @return {boolean} Whether this SearchRequest refers to an identical 532 * @return {boolean} Whether this SearchRequest refers to an identical
549 * query. 533 * query.
550 */ 534 */
551 isSame: function(rawQuery) { 535 isSame(rawQuery) {
552 return this.rawQuery_ == rawQuery; 536 return this.rawQuery_ == rawQuery;
553 }, 537 }
554 538
555 /** 539 /**
556 * Updates the result for this search request. 540 * Updates the result for this search request.
557 * @param {boolean} found 541 * @param {boolean} found
558 */ 542 */
559 updateMatches: function(found) { 543 updateMatches(found) {
560 this.foundMatches_ = this.foundMatches_ || found; 544 this.foundMatches_ = this.foundMatches_ || found;
561 }, 545 }
562 546
563 /** @return {boolean} Whether any matches were found. */ 547 /** @return {boolean} Whether any matches were found. */
564 didFindMatches: function() { 548 didFindMatches() {
565 return this.foundMatches_; 549 return this.foundMatches_;
566 }, 550 }
567 }; 551 }
552
553 /** @private {!RegExp} */
554 SearchRequest.SANITIZE_REGEX_ = /[-[\]{}()*+?.,\\^$|#\s]/g;
Tyler Breisacher (Chromium) 2017/06/15 22:48:37 nit: Since this isn't Java, you don't have to make
dpapad 2017/06/15 22:57:54 Good suggestion, done. I used 'var' for now, since
568 555
569 /** @interface */ 556 /** @interface */
570 var SearchManager = function() {}; 557 class SearchManager {
571
572 SearchManager.prototype = {
573 /** 558 /**
574 * @param {string} text The text to search for. 559 * @param {string} text The text to search for.
575 * @param {!Node} page 560 * @param {!Node} page
576 * @return {!Promise<!settings.SearchRequest>} A signal indicating that 561 * @return {!Promise<!settings.SearchRequest>} A signal indicating that
577 * searching finished. 562 * searching finished.
578 */ 563 */
579 search: function(text, page) {} 564 search(text, page) {}
580 }; 565 }
581 566
582 /** 567 /** @implements {SearchManager} */
583 * @constructor 568 class SearchManagerImpl {
584 * @implements {SearchManager} 569 constructor() {
585 */ 570 /** @private {!Set<!settings.SearchRequest>} */
586 var SearchManagerImpl = function() { 571 this.activeRequests_ = new Set();
587 /** @private {!Set<!settings.SearchRequest>} */
588 this.activeRequests_ = new Set();
589 572
590 /** @private {?string} */ 573 /** @private {?string} */
591 this.lastSearchedText_ = null; 574 this.lastSearchedText_ = null;
592 }; 575 }
593 cr.addSingletonGetter(SearchManagerImpl);
594 576
595 SearchManagerImpl.prototype = {
596 /** @override */ 577 /** @override */
597 search: function(text, page) { 578 search(text, page) {
598 // Cancel any pending requests if a request with different text is 579 // Cancel any pending requests if a request with different text is
599 // submitted. 580 // submitted.
600 if (text != this.lastSearchedText_) { 581 if (text != this.lastSearchedText_) {
601 this.activeRequests_.forEach(function(request) { 582 this.activeRequests_.forEach(function(request) {
602 request.canceled = true; 583 request.canceled = true;
603 request.resolver.resolve(request); 584 request.resolver.resolve(request);
604 }); 585 });
605 this.activeRequests_.clear(); 586 this.activeRequests_.clear();
606 } 587 }
607 588
608 this.lastSearchedText_ = text; 589 this.lastSearchedText_ = text;
609 var request = new SearchRequest(text, page); 590 var request = new SearchRequest(text, page);
610 this.activeRequests_.add(request); 591 this.activeRequests_.add(request);
611 request.start(); 592 request.start();
612 return request.resolver.promise.then(function() { 593 return request.resolver.promise.then(function() {
613 // Stop tracking requests that finished. 594 // Stop tracking requests that finished.
614 this.activeRequests_.delete(request); 595 this.activeRequests_.delete(request);
615 return request; 596 return request;
616 }.bind(this)); 597 }.bind(this));
617 }, 598 }
618 }; 599 }
600 cr.addSingletonGetter(SearchManagerImpl);
619 601
620 /** @return {!SearchManager} */ 602 /** @return {!SearchManager} */
621 function getSearchManager() { 603 function getSearchManager() {
622 return SearchManagerImpl.getInstance(); 604 return SearchManagerImpl.getInstance();
623 } 605 }
624 606
625 /** 607 /**
626 * Sets the SearchManager singleton instance, useful for testing. 608 * Sets the SearchManager singleton instance, useful for testing.
627 * @param {!SearchManager} searchManager 609 * @param {!SearchManager} searchManager
628 */ 610 */
629 function setSearchManagerForTesting(searchManager) { 611 function setSearchManagerForTesting(searchManager) {
630 SearchManagerImpl.instance_ = searchManager; 612 SearchManagerImpl.instance_ = searchManager;
631 } 613 }
632 614
633 return { 615 return {
634 getSearchManager: getSearchManager, 616 getSearchManager: getSearchManager,
635 setSearchManagerForTesting: setSearchManagerForTesting, 617 setSearchManagerForTesting: setSearchManagerForTesting,
636 SearchRequest: SearchRequest, 618 SearchRequest: SearchRequest,
637 }; 619 };
638 }); 620 });
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698