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

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

Issue 2940233002: WebUI: Allow using ES6 classes in the styleguide. (Closed)
Patch Set: Resolve conflicts. 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 | docs/es6_chromium.md » ('j') | 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() || this.queues_.middle.shift() || 436 return this.queues_.high.shift() || this.queues_.middle.shift() ||
448 this.queues_.low.shift(); 437 this.queues_.low.shift();
449 }, 438 }
450 439
451 /** @private */ 440 /** @private */
452 consumePending_: function() { 441 consumePending_() {
453 if (this.running_) 442 if (this.running_)
454 return; 443 return;
455 444
456 while (1) { 445 while (1) {
457 var task = this.popNextTask_(); 446 var task = this.popNextTask_();
458 if (!task) { 447 if (!task) {
459 this.running_ = false; 448 this.running_ = false;
460 if (this.onEmptyCallback_) 449 if (this.onEmptyCallback_)
461 this.onEmptyCallback_(); 450 this.onEmptyCallback_();
462 return; 451 return;
463 } 452 }
464 453
465 this.running_ = true; 454 this.running_ = true;
466 window.requestIdleCallback(function() { 455 window.requestIdleCallback(function() {
467 if (!this.request_.canceled) { 456 if (!this.request_.canceled) {
468 task.exec().then(function() { 457 task.exec().then(function() {
469 this.running_ = false; 458 this.running_ = false;
470 this.consumePending_(); 459 this.consumePending_();
471 }.bind(this)); 460 }.bind(this));
472 } 461 }
473 // Nothing to do otherwise. Since the request corresponding to this 462 // Nothing to do otherwise. Since the request corresponding to this
474 // queue was canceled, the queue is disposed along with the request. 463 // queue was canceled, the queue is disposed along with the request.
475 }.bind(this)); 464 }.bind(this));
476 return; 465 return;
477 } 466 }
478 }, 467 }
479 }; 468 }
480 469
481 /** 470 class SearchRequest {
482 * @constructor 471 /**
483 * 472 * @param {string} rawQuery
484 * @param {string} rawQuery 473 * @param {!HTMLElement} root
485 * @param {!HTMLElement} root 474 */
486 */ 475 constructor(rawQuery, root) {
487 var SearchRequest = function(rawQuery, root) { 476 /** @private {string} */
488 /** @private {string} */ 477 this.rawQuery_ = rawQuery;
489 this.rawQuery_ = rawQuery;
490 478
491 /** @private {!HTMLElement} */ 479 /** @private {!HTMLElement} */
492 this.root_ = root; 480 this.root_ = root;
493 481
494 /** @type {?RegExp} */ 482 /** @type {?RegExp} */
495 this.regExp = this.generateRegExp_(); 483 this.regExp = this.generateRegExp_();
496 484
497 /** 485 /**
498 * Whether this request was canceled before completing. 486 * Whether this request was canceled before completing.
499 * @type {boolean} 487 * @type {boolean}
500 */ 488 */
501 this.canceled = false; 489 this.canceled = false;
502 490
503 /** @private {boolean} */ 491 /** @private {boolean} */
504 this.foundMatches_ = false; 492 this.foundMatches_ = false;
505 493
506 /** @type {!PromiseResolver} */ 494 /** @type {!PromiseResolver} */
507 this.resolver = new PromiseResolver(); 495 this.resolver = new PromiseResolver();
508 496
509 /** @private {!TaskQueue} */ 497 /** @private {!TaskQueue} */
510 this.queue_ = new TaskQueue(this); 498 this.queue_ = new TaskQueue(this);
511 this.queue_.onEmpty(function() { 499 this.queue_.onEmpty(function() {
512 this.resolver.resolve(this); 500 this.resolver.resolve(this);
513 }.bind(this)); 501 }.bind(this));
514 }; 502 }
515 503
516 /** @private {!RegExp} */
517 SearchRequest.SANITIZE_REGEX_ = /[-[\]{}()*+?.,\\^$|#\s]/g;
518
519 SearchRequest.prototype = {
520 /** 504 /**
521 * Fires this search request. 505 * Fires this search request.
522 */ 506 */
523 start: function() { 507 start() {
524 this.queue_.addTopLevelSearchTask( 508 this.queue_.addTopLevelSearchTask(
525 new TopLevelSearchTask(this, this.root_)); 509 new TopLevelSearchTask(this, this.root_));
526 }, 510 }
527 511
528 /** 512 /**
529 * @return {?RegExp} 513 * @return {?RegExp}
530 * @private 514 * @private
531 */ 515 */
532 generateRegExp_: function() { 516 generateRegExp_() {
533 var regExp = null; 517 var regExp = null;
534 518
535 // Generate search text by escaping any characters that would be 519 // Generate search text by escaping any characters that would be
536 // problematic for regular expressions. 520 // problematic for regular expressions.
537 var searchText = 521 var searchText = this.rawQuery_.trim().replace(SANITIZE_REGEX, '\\$&');
538 this.rawQuery_.trim().replace(SearchRequest.SANITIZE_REGEX_, '\\$&');
539 if (searchText.length > 0) 522 if (searchText.length > 0)
540 regExp = new RegExp('(' + searchText + ')', 'i'); 523 regExp = new RegExp('(' + searchText + ')', 'i');
541 524
542 return regExp; 525 return regExp;
543 }, 526 }
544 527
545 /** 528 /**
546 * @param {string} rawQuery 529 * @param {string} rawQuery
547 * @return {boolean} Whether this SearchRequest refers to an identical 530 * @return {boolean} Whether this SearchRequest refers to an identical
548 * query. 531 * query.
549 */ 532 */
550 isSame: function(rawQuery) { 533 isSame(rawQuery) {
551 return this.rawQuery_ == rawQuery; 534 return this.rawQuery_ == rawQuery;
552 }, 535 }
553 536
554 /** 537 /**
555 * Updates the result for this search request. 538 * Updates the result for this search request.
556 * @param {boolean} found 539 * @param {boolean} found
557 */ 540 */
558 updateMatches: function(found) { 541 updateMatches(found) {
559 this.foundMatches_ = this.foundMatches_ || found; 542 this.foundMatches_ = this.foundMatches_ || found;
560 }, 543 }
561 544
562 /** @return {boolean} Whether any matches were found. */ 545 /** @return {boolean} Whether any matches were found. */
563 didFindMatches: function() { 546 didFindMatches() {
564 return this.foundMatches_; 547 return this.foundMatches_;
565 }, 548 }
566 }; 549 }
550
551 /** @const {!RegExp} */
552 var SANITIZE_REGEX = /[-[\]{}()*+?.,\\^$|#\s]/g;
567 553
568 /** @interface */ 554 /** @interface */
569 var SearchManager = function() {}; 555 class SearchManager {
570
571 SearchManager.prototype = {
572 /** 556 /**
573 * @param {string} text The text to search for. 557 * @param {string} text The text to search for.
574 * @param {!Node} page 558 * @param {!Node} page
575 * @return {!Promise<!settings.SearchRequest>} A signal indicating that 559 * @return {!Promise<!settings.SearchRequest>} A signal indicating that
576 * searching finished. 560 * searching finished.
577 */ 561 */
578 search: function(text, page) {} 562 search(text, page) {}
579 }; 563 }
580 564
581 /** 565 /** @implements {SearchManager} */
582 * @constructor 566 class SearchManagerImpl {
583 * @implements {SearchManager} 567 constructor() {
584 */ 568 /** @private {!Set<!settings.SearchRequest>} */
585 var SearchManagerImpl = function() { 569 this.activeRequests_ = new Set();
586 /** @private {!Set<!settings.SearchRequest>} */
587 this.activeRequests_ = new Set();
588 570
589 /** @private {?string} */ 571 /** @private {?string} */
590 this.lastSearchedText_ = null; 572 this.lastSearchedText_ = null;
591 }; 573 }
592 cr.addSingletonGetter(SearchManagerImpl);
593 574
594 SearchManagerImpl.prototype = {
595 /** @override */ 575 /** @override */
596 search: function(text, page) { 576 search(text, page) {
597 // Cancel any pending requests if a request with different text is 577 // Cancel any pending requests if a request with different text is
598 // submitted. 578 // submitted.
599 if (text != this.lastSearchedText_) { 579 if (text != this.lastSearchedText_) {
600 this.activeRequests_.forEach(function(request) { 580 this.activeRequests_.forEach(function(request) {
601 request.canceled = true; 581 request.canceled = true;
602 request.resolver.resolve(request); 582 request.resolver.resolve(request);
603 }); 583 });
604 this.activeRequests_.clear(); 584 this.activeRequests_.clear();
605 } 585 }
606 586
607 this.lastSearchedText_ = text; 587 this.lastSearchedText_ = text;
608 var request = new SearchRequest(text, page); 588 var request = new SearchRequest(text, page);
609 this.activeRequests_.add(request); 589 this.activeRequests_.add(request);
610 request.start(); 590 request.start();
611 return request.resolver.promise.then(function() { 591 return request.resolver.promise.then(function() {
612 // Stop tracking requests that finished. 592 // Stop tracking requests that finished.
613 this.activeRequests_.delete(request); 593 this.activeRequests_.delete(request);
614 return request; 594 return request;
615 }.bind(this)); 595 }.bind(this));
616 }, 596 }
617 }; 597 }
598 cr.addSingletonGetter(SearchManagerImpl);
618 599
619 /** @return {!SearchManager} */ 600 /** @return {!SearchManager} */
620 function getSearchManager() { 601 function getSearchManager() {
621 return SearchManagerImpl.getInstance(); 602 return SearchManagerImpl.getInstance();
622 } 603 }
623 604
624 /** 605 /**
625 * Sets the SearchManager singleton instance, useful for testing. 606 * Sets the SearchManager singleton instance, useful for testing.
626 * @param {!SearchManager} searchManager 607 * @param {!SearchManager} searchManager
627 */ 608 */
628 function setSearchManagerForTesting(searchManager) { 609 function setSearchManagerForTesting(searchManager) {
629 SearchManagerImpl.instance_ = searchManager; 610 SearchManagerImpl.instance_ = searchManager;
630 } 611 }
631 612
632 return { 613 return {
633 getSearchManager: getSearchManager, 614 getSearchManager: getSearchManager,
634 setSearchManagerForTesting: setSearchManagerForTesting, 615 setSearchManagerForTesting: setSearchManagerForTesting,
635 SearchRequest: SearchRequest, 616 SearchRequest: SearchRequest,
636 }; 617 };
637 }); 618 });
OLDNEW
« no previous file with comments | « no previous file | docs/es6_chromium.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698