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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js

Issue 2256873002: Revert of DevTools: fix stick to bottom in console viewport (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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 | « third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js ('k') | 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 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 this._provider = provider; 52 this._provider = provider;
53 this.element.addEventListener("scroll", this._onScroll.bind(this), false); 53 this.element.addEventListener("scroll", this._onScroll.bind(this), false);
54 this.element.addEventListener("copy", this._onCopy.bind(this), false); 54 this.element.addEventListener("copy", this._onCopy.bind(this), false);
55 this.element.addEventListener("dragstart", this._onDragStart.bind(this), fal se); 55 this.element.addEventListener("dragstart", this._onDragStart.bind(this), fal se);
56 56
57 this._firstVisibleIndex = 0; 57 this._firstVisibleIndex = 0;
58 this._lastVisibleIndex = -1; 58 this._lastVisibleIndex = -1;
59 this._renderedItems = []; 59 this._renderedItems = [];
60 this._anchorSelection = null; 60 this._anchorSelection = null;
61 this._headSelection = null; 61 this._headSelection = null;
62 this._stickToBottom = false;
63 this._scrolledToBottom = true;
62 this._itemCount = 0; 64 this._itemCount = 0;
63
64 // Listen for any changes to descendants and trigger a refresh. This ensures
65 // that items updated asynchronously will not break stick-to-bottom behavior
66 // if they change the scroll height.
67 this._observer = new MutationObserver(this.refresh.bind(this));
68 this._observerConfig = { childList: true, subtree: true };
69 } 65 }
70 66
71 /** 67 /**
72 * @interface 68 * @interface
73 */ 69 */
74 WebInspector.ViewportControl.Provider = function() 70 WebInspector.ViewportControl.Provider = function()
75 { 71 {
76 } 72 }
77 73
78 WebInspector.ViewportControl.Provider.prototype = { 74 WebInspector.ViewportControl.Provider.prototype = {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 element: function() 138 element: function()
143 { 139 {
144 return this._element; 140 return this._element;
145 }, 141 },
146 } 142 }
147 143
148 WebInspector.ViewportControl.prototype = { 144 WebInspector.ViewportControl.prototype = {
149 /** 145 /**
150 * @return {boolean} 146 * @return {boolean}
151 */ 147 */
152 stickToBottom: function() 148 scrolledToBottom: function()
153 { 149 {
154 return this._stickToBottom; 150 return this._scrolledToBottom;
155 }, 151 },
156 152
157 /** 153 /**
158 * @param {boolean} value 154 * @param {boolean} value
159 */ 155 */
160 setStickToBottom: function(value) 156 setStickToBottom: function(value)
161 { 157 {
162 this._stickToBottom = value; 158 this._stickToBottom = value;
163 if (this._stickToBottom)
164 this._observer.observe(this._contentElement, this._observerConfig);
165 else
166 this._observer.disconnect();
167 }, 159 },
168 160
169 /** 161 /**
170 * @param {!Event} event 162 * @param {!Event} event
171 */ 163 */
172 _onCopy: function(event) 164 _onCopy: function(event)
173 { 165 {
174 var text = this._selectedText(); 166 var text = this._selectedText();
175 if (!text) 167 if (!text)
176 return; 168 return;
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 else if (this._headSelection.item > this._lastVisibleIndex) 369 else if (this._headSelection.item > this._lastVisibleIndex)
378 headElement = this._bottomGapElement; 370 headElement = this._bottomGapElement;
379 headOffset = this._selectionIsBackward ? 0 : 1; 371 headOffset = this._selectionIsBackward ? 0 : 1;
380 } 372 }
381 373
382 selection.setBaseAndExtent(anchorElement, anchorOffset, headElement, hea dOffset); 374 selection.setBaseAndExtent(anchorElement, anchorOffset, headElement, hea dOffset);
383 }, 375 },
384 376
385 refresh: function() 377 refresh: function()
386 { 378 {
387 this._observer.disconnect();
388 this._innerRefresh();
389 if (this._stickToBottom)
390 this._observer.observe(this._contentElement, this._observerConfig);
391 },
392
393 _innerRefresh: function()
394 {
395 if (!this._visibleHeight()) 379 if (!this._visibleHeight())
396 return; // Do nothing for invisible controls. 380 return; // Do nothing for invisible controls.
397 381
398 if (!this._itemCount) { 382 if (!this._itemCount) {
399 for (var i = 0; i < this._renderedItems.length; ++i) 383 for (var i = 0; i < this._renderedItems.length; ++i)
400 this._renderedItems[i].willHide(); 384 this._renderedItems[i].willHide();
401 this._renderedItems = []; 385 this._renderedItems = [];
402 this._contentElement.removeChildren(); 386 this._contentElement.removeChildren();
403 this._topGapElement.style.height = "0px"; 387 this._topGapElement.style.height = "0px";
404 this._bottomGapElement.style.height = "0px"; 388 this._bottomGapElement.style.height = "0px";
405 this._firstVisibleIndex = -1; 389 this._firstVisibleIndex = -1;
406 this._lastVisibleIndex = -1; 390 this._lastVisibleIndex = -1;
407 return; 391 return;
408 } 392 }
409 393
410 var selection = this.element.getComponentSelection(); 394 var selection = this.element.getComponentSelection();
411 var shouldRestoreSelection = this._updateSelectionModel(selection); 395 var shouldRestoreSelection = this._updateSelectionModel(selection);
412 396
413 var visibleFrom = this.element.scrollTop; 397 var visibleFrom = this.element.scrollTop;
414 var visibleHeight = this._visibleHeight(); 398 var visibleHeight = this._visibleHeight();
399 this._scrolledToBottom = this.element.isScrolledToBottom();
415 var isInvalidating = !this._cumulativeHeights; 400 var isInvalidating = !this._cumulativeHeights;
416 401
417 for (var i = 0; i < this._renderedItems.length; ++i) { 402 for (var i = 0; i < this._renderedItems.length; ++i) {
418 // Tolerate 1-pixel error due to double-to-integer rounding errors. 403 // Tolerate 1-pixel error due to double-to-integer rounding errors.
419 if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this. _firstVisibleIndex + i) - this._renderedItems[i].element().offsetHeight) > 1) 404 if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this. _firstVisibleIndex + i) - this._renderedItems[i].element().offsetHeight) > 1)
420 delete this._cumulativeHeights; 405 delete this._cumulativeHeights;
421 } 406 }
422 this._rebuildCumulativeHeightsIfNeeded(); 407 this._rebuildCumulativeHeightsIfNeeded();
423 var oldFirstVisibleIndex = this._firstVisibleIndex; 408 var oldFirstVisibleIndex = this._firstVisibleIndex;
424 var oldLastVisibleIndex = this._lastVisibleIndex; 409 var oldLastVisibleIndex = this._lastVisibleIndex;
425 410
426 // When the viewport is scrolled to the bottom, using the cumulative hei ghts estimate is not 411 var shouldStickToBottom = this._stickToBottom && this._scrolledToBottom;
427 // precise enough to determine next visible indices. This stickToBottom check avoids extra 412
428 // calls to refresh in those cases. 413 if (shouldStickToBottom) {
429 if (this._stickToBottom) { 414 this._lastVisibleIndex = this._itemCount - 1;
430 this._firstVisibleIndex = Math.max(this._itemCount - Math.ceil(visib leHeight / this._provider.minimumRowHeight()), 0); 415 this._firstVisibleIndex = Math.max(this._itemCount - Math.ceil(visib leHeight / this._provider.minimumRowHeight()), 0);
431 this._lastVisibleIndex = this._itemCount - 1;
432 } else { 416 } else {
433 this._firstVisibleIndex = Math.max(Array.prototype.lowerBound.call(t his._cumulativeHeights, visibleFrom + 1), 0); 417 this._firstVisibleIndex = Math.max(Array.prototype.lowerBound.call(t his._cumulativeHeights, visibleFrom + 1), 0);
434 // Proactively render more rows in case some of them will be collaps ed without triggering refresh. @see crbug.com/390169 418 // Proactively render more rows in case some of them will be collaps ed without triggering refresh. @see crbug.com/390169
435 this._lastVisibleIndex = this._firstVisibleIndex + Math.ceil(visible Height / this._provider.minimumRowHeight()) - 1; 419 this._lastVisibleIndex = this._firstVisibleIndex + Math.ceil(visible Height / this._provider.minimumRowHeight()) - 1;
436 this._lastVisibleIndex = Math.min(this._lastVisibleIndex, this._item Count - 1); 420 this._lastVisibleIndex = Math.min(this._lastVisibleIndex, this._item Count - 1);
437 } 421 }
438
439 var topGapHeight = this._cumulativeHeights[this._firstVisibleIndex - 1] || 0; 422 var topGapHeight = this._cumulativeHeights[this._firstVisibleIndex - 1] || 0;
440 var bottomGapHeight = this._cumulativeHeights[this._cumulativeHeights.le ngth - 1] - this._cumulativeHeights[this._lastVisibleIndex]; 423 var bottomGapHeight = this._cumulativeHeights[this._cumulativeHeights.le ngth - 1] - this._cumulativeHeights[this._lastVisibleIndex];
441 424
442 /** 425 /**
443 * @this {WebInspector.ViewportControl} 426 * @this {WebInspector.ViewportControl}
444 */ 427 */
445 function prepare() 428 function prepare()
446 { 429 {
447 this._topGapElement.style.height = topGapHeight + "px"; 430 this._topGapElement.style.height = topGapHeight + "px";
448 this._bottomGapElement.style.height = bottomGapHeight + "px"; 431 this._bottomGapElement.style.height = bottomGapHeight + "px";
449 this._topGapElement._active = !!topGapHeight; 432 this._topGapElement._active = !!topGapHeight;
450 this._bottomGapElement._active = !!bottomGapHeight; 433 this._bottomGapElement._active = !!bottomGapHeight;
451 this._contentElement.style.setProperty("height", "10000000px"); 434 this._contentElement.style.setProperty("height", "10000000px");
452 } 435 }
453 436
454 if (isInvalidating) 437 if (isInvalidating)
455 this._fullViewportUpdate(prepare.bind(this)); 438 this._fullViewportUpdate(prepare.bind(this));
456 else 439 else
457 this._partialViewportUpdate(oldFirstVisibleIndex, oldLastVisibleInde x, prepare.bind(this)); 440 this._partialViewportUpdate(oldFirstVisibleIndex, oldLastVisibleInde x, prepare.bind(this));
458 this._contentElement.style.removeProperty("height"); 441 this._contentElement.style.removeProperty("height");
459 // Should be the last call in the method as it might force layout. 442 // Should be the last call in the method as it might force layout.
460 if (shouldRestoreSelection) 443 if (shouldRestoreSelection)
461 this._restoreSelection(selection); 444 this._restoreSelection(selection);
462 if (this._stickToBottom) 445 if (shouldStickToBottom)
463 this.element.scrollTop = 10000000; 446 this.element.scrollTop = 10000000;
464 }, 447 },
465 448
466 /** 449 /**
467 * @param {function()} prepare 450 * @param {function()} prepare
468 */ 451 */
469 _fullViewportUpdate: function(prepare) 452 _fullViewportUpdate: function(prepare)
470 { 453 {
471 for (var i = 0; i < this._renderedItems.length; ++i) 454 for (var i = 0; i < this._renderedItems.length; ++i)
472 this._renderedItems[i].willHide(); 455 this._renderedItems[i].willHide();
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 this.forceScrollItemToBeFirst(index); 605 this.forceScrollItemToBeFirst(index);
623 else if (index >= this._lastVisibleIndex) 606 else if (index >= this._lastVisibleIndex)
624 this.forceScrollItemToBeLast(index); 607 this.forceScrollItemToBeLast(index);
625 }, 608 },
626 609
627 /** 610 /**
628 * @param {number} index 611 * @param {number} index
629 */ 612 */
630 forceScrollItemToBeFirst: function(index) 613 forceScrollItemToBeFirst: function(index)
631 { 614 {
632 this.setStickToBottom(false);
633 this._rebuildCumulativeHeightsIfNeeded(); 615 this._rebuildCumulativeHeightsIfNeeded();
634 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0; 616 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0;
635 if (this.element.isScrolledToBottom())
636 this.setStickToBottom(true);
637 this.refresh(); 617 this.refresh();
638 }, 618 },
639 619
640 /** 620 /**
641 * @param {number} index 621 * @param {number} index
642 */ 622 */
643 forceScrollItemToBeLast: function(index) 623 forceScrollItemToBeLast: function(index)
644 { 624 {
645 this.setStickToBottom(false);
646 this._rebuildCumulativeHeightsIfNeeded(); 625 this._rebuildCumulativeHeightsIfNeeded();
647 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleH eight(); 626 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleH eight();
648 if (this.element.isScrolledToBottom())
649 this.setStickToBottom(true);
650 this.refresh(); 627 this.refresh();
651 }, 628 },
652 629
653 /** 630 /**
654 * @return {number} 631 * @return {number}
655 */ 632 */
656 _visibleHeight: function() 633 _visibleHeight: function()
657 { 634 {
658 // Use offsetHeight instead of clientHeight to avoid being affected by h orizontal scroll. 635 // Use offsetHeight instead of clientHeight to avoid being affected by h orizontal scroll.
659 return this.element.offsetHeight; 636 return this.element.offsetHeight;
660 } 637 }
661 } 638 }
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698