| OLD | NEW |
| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 this.element.addEventListener('scroll', this._onScroll.bind(this), false); | 55 this.element.addEventListener('scroll', this._onScroll.bind(this), false); |
| 56 this.element.addEventListener('copy', this._onCopy.bind(this), false); | 56 this.element.addEventListener('copy', this._onCopy.bind(this), false); |
| 57 this.element.addEventListener('dragstart', this._onDragStart.bind(this), fal
se); | 57 this.element.addEventListener('dragstart', this._onDragStart.bind(this), fal
se); |
| 58 | 58 |
| 59 this._firstActiveIndex = 0; | 59 this._firstActiveIndex = 0; |
| 60 this._lastActiveIndex = -1; | 60 this._lastActiveIndex = -1; |
| 61 this._renderedItems = []; | 61 this._renderedItems = []; |
| 62 this._anchorSelection = null; | 62 this._anchorSelection = null; |
| 63 this._headSelection = null; | 63 this._headSelection = null; |
| 64 this._itemCount = 0; | 64 this._itemCount = 0; |
| 65 this._cumulativeHeights = new Int32Array(0); |
| 65 | 66 |
| 66 // Listen for any changes to descendants and trigger a refresh. This ensures | 67 // Listen for any changes to descendants and trigger a refresh. This ensures |
| 67 // that items updated asynchronously will not break stick-to-bottom behavior | 68 // that items updated asynchronously will not break stick-to-bottom behavior |
| 68 // if they change the scroll height. | 69 // if they change the scroll height. |
| 69 this._observer = new MutationObserver(this.refresh.bind(this)); | 70 this._observer = new MutationObserver(this.refresh.bind(this)); |
| 70 this._observerConfig = {childList: true, subtree: true}; | 71 this._observerConfig = {childList: true, subtree: true}; |
| 71 } | 72 } |
| 72 | 73 |
| 73 /** | 74 /** |
| 74 * @return {boolean} | 75 * @return {boolean} |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 } | 114 } |
| 114 | 115 |
| 115 /** | 116 /** |
| 116 * @return {!Element} | 117 * @return {!Element} |
| 117 */ | 118 */ |
| 118 contentElement() { | 119 contentElement() { |
| 119 return this._contentElement; | 120 return this._contentElement; |
| 120 } | 121 } |
| 121 | 122 |
| 122 invalidate() { | 123 invalidate() { |
| 123 delete this._cumulativeHeights; | |
| 124 delete this._cachedProviderElements; | 124 delete this._cachedProviderElements; |
| 125 this._itemCount = this._provider.itemCount(); | 125 this._itemCount = this._provider.itemCount(); |
| 126 this._rebuildCumulativeHeights(); |
| 126 this.refresh(); | 127 this.refresh(); |
| 127 } | 128 } |
| 128 | 129 |
| 129 /** | 130 /** |
| 130 * @param {number} index | 131 * @param {number} index |
| 131 * @return {?Console.ConsoleViewportElement} | 132 * @return {?Console.ConsoleViewportElement} |
| 132 */ | 133 */ |
| 133 _providerElement(index) { | 134 _providerElement(index) { |
| 134 if (!this._cachedProviderElements) | 135 if (!this._cachedProviderElements) |
| 135 this._cachedProviderElements = new Array(this._itemCount); | 136 this._cachedProviderElements = new Array(this._itemCount); |
| 136 var element = this._cachedProviderElements[index]; | 137 var element = this._cachedProviderElements[index]; |
| 137 if (!element) { | 138 if (!element) { |
| 138 element = this._provider.itemElement(index); | 139 element = this._provider.itemElement(index); |
| 139 this._cachedProviderElements[index] = element; | 140 this._cachedProviderElements[index] = element; |
| 140 } | 141 } |
| 141 return element; | 142 return element; |
| 142 } | 143 } |
| 143 | 144 |
| 144 _rebuildCumulativeHeightsIfNeeded() { | 145 _rebuildCumulativeHeights() { |
| 145 if (this._cumulativeHeights) | |
| 146 return; | |
| 147 if (!this._itemCount) | |
| 148 return; | |
| 149 var firstActiveIndex = this._firstActiveIndex; | 146 var firstActiveIndex = this._firstActiveIndex; |
| 150 var lastActiveIndex = this._lastActiveIndex; | 147 var lastActiveIndex = this._lastActiveIndex; |
| 151 var height = 0; | 148 var height = 0; |
| 152 this._cumulativeHeights = new Int32Array(this._itemCount); | 149 this._cumulativeHeights = new Int32Array(this._itemCount); |
| 153 for (var i = 0; i < this._itemCount; ++i) { | 150 for (var i = 0; i < this._itemCount; ++i) { |
| 154 if (firstActiveIndex <= i && i <= lastActiveIndex) | 151 if (firstActiveIndex <= i && i <= lastActiveIndex) |
| 155 height += this._renderedItems[i - firstActiveIndex].element().offsetHeig
ht; | 152 height += this._renderedItems[i - firstActiveIndex].element().offsetHeig
ht; |
| 156 else | 153 else |
| 157 height += this._provider.fastHeight(i); | 154 height += this._provider.fastHeight(i); |
| 158 this._cumulativeHeights[i] = height; | 155 this._cumulativeHeights[i] = height; |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 } | 314 } |
| 318 | 315 |
| 319 var selection = this.element.getComponentSelection(); | 316 var selection = this.element.getComponentSelection(); |
| 320 var shouldRestoreSelection = this._updateSelectionModel(selection); | 317 var shouldRestoreSelection = this._updateSelectionModel(selection); |
| 321 | 318 |
| 322 var visibleFrom = this.element.scrollTop; | 319 var visibleFrom = this.element.scrollTop; |
| 323 var visibleHeight = this._visibleHeight(); | 320 var visibleHeight = this._visibleHeight(); |
| 324 | 321 |
| 325 for (var i = 0; i < this._renderedItems.length; ++i) { | 322 for (var i = 0; i < this._renderedItems.length; ++i) { |
| 326 // Tolerate 1-pixel error due to double-to-integer rounding errors. | 323 // Tolerate 1-pixel error due to double-to-integer rounding errors. |
| 327 if (this._cumulativeHeights && | 324 var cachedItemHeight = this._cachedItemHeight(this._firstActiveIndex + i); |
| 328 Math.abs(this._cachedItemHeight(this._firstActiveIndex + i) - this._re
nderedItems[i].element().offsetHeight) > | 325 if (Math.abs(cachedItemHeight - this._renderedItems[i].element().offsetHei
ght) > 1) { |
| 329 1) | 326 this._rebuildCumulativeHeights(); |
| 330 delete this._cumulativeHeights; | 327 break; |
| 328 } |
| 331 } | 329 } |
| 332 this._rebuildCumulativeHeightsIfNeeded(); | |
| 333 var activeHeight = visibleHeight * 2; | 330 var activeHeight = visibleHeight * 2; |
| 334 // When the viewport is scrolled to the bottom, using the cumulative heights
estimate is not | 331 // When the viewport is scrolled to the bottom, using the cumulative heights
estimate is not |
| 335 // precise enough to determine next visible indices. This stickToBottom chec
k avoids extra | 332 // precise enough to determine next visible indices. This stickToBottom chec
k avoids extra |
| 336 // calls to refresh in those cases. | 333 // calls to refresh in those cases. |
| 337 if (this._stickToBottom) { | 334 if (this._stickToBottom) { |
| 338 this._firstActiveIndex = | 335 this._firstActiveIndex = |
| 339 Math.max(this._itemCount - Math.ceil(activeHeight / this._provider.min
imumRowHeight()), 0); | 336 Math.max(this._itemCount - Math.ceil(activeHeight / this._provider.min
imumRowHeight()), 0); |
| 340 this._lastActiveIndex = this._itemCount - 1; | 337 this._lastActiveIndex = this._itemCount - 1; |
| 341 } else { | 338 } else { |
| 342 this._firstActiveIndex = Math.max( | 339 this._firstActiveIndex = Math.max( |
| 343 Array.prototype.lowerBound.call( | 340 Int32Array.prototype.lowerBound.call( |
| 344 this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visible
Height) / 2), | 341 this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visible
Height) / 2), |
| 345 0); | 342 0); |
| 346 // Proactively render more rows in case some of them will be collapsed wit
hout triggering refresh. @see crbug.com/390169 | 343 // Proactively render more rows in case some of them will be collapsed wit
hout triggering refresh. @see crbug.com/390169 |
| 347 this._lastActiveIndex = this._firstActiveIndex + Math.ceil(activeHeight /
this._provider.minimumRowHeight()) - 1; | 344 this._lastActiveIndex = this._firstActiveIndex + Math.ceil(activeHeight /
this._provider.minimumRowHeight()) - 1; |
| 348 this._lastActiveIndex = Math.min(this._lastActiveIndex, this._itemCount -
1); | 345 this._lastActiveIndex = Math.min(this._lastActiveIndex, this._itemCount -
1); |
| 349 } | 346 } |
| 350 | 347 |
| 351 var topGapHeight = this._cumulativeHeights[this._firstActiveIndex - 1] || 0; | 348 var topGapHeight = this._cumulativeHeights[this._firstActiveIndex - 1] || 0; |
| 352 var bottomGapHeight = | 349 var bottomGapHeight = |
| 353 this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumu
lativeHeights[this._lastActiveIndex]; | 350 this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumu
lativeHeights[this._lastActiveIndex]; |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 */ | 465 */ |
| 469 _onScroll(event) { | 466 _onScroll(event) { |
| 470 this.refresh(); | 467 this.refresh(); |
| 471 } | 468 } |
| 472 | 469 |
| 473 /** | 470 /** |
| 474 * @return {number} | 471 * @return {number} |
| 475 */ | 472 */ |
| 476 firstVisibleIndex() { | 473 firstVisibleIndex() { |
| 477 var firstVisibleIndex = | 474 var firstVisibleIndex = |
| 478 Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.e
lement.scrollTop + 1), 0); | 475 Math.max(Int32Array.prototype.lowerBound.call(this._cumulativeHeights, t
his.element.scrollTop + 1), 0); |
| 479 return Math.max(firstVisibleIndex, this._firstActiveIndex); | 476 return Math.max(firstVisibleIndex, this._firstActiveIndex); |
| 480 } | 477 } |
| 481 | 478 |
| 482 /** | 479 /** |
| 483 * @return {number} | 480 * @return {number} |
| 484 */ | 481 */ |
| 485 lastVisibleIndex() { | 482 lastVisibleIndex() { |
| 486 var lastVisibleIndex; | 483 var lastVisibleIndex; |
| 487 if (this._stickToBottom) { | 484 if (this._stickToBottom) { |
| 488 lastVisibleIndex = this._itemCount - 1; | 485 lastVisibleIndex = this._itemCount - 1; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 519 this.forceScrollItemToBeFirst(index); | 516 this.forceScrollItemToBeFirst(index); |
| 520 else if (index >= lastVisibleIndex) | 517 else if (index >= lastVisibleIndex) |
| 521 this.forceScrollItemToBeLast(index); | 518 this.forceScrollItemToBeLast(index); |
| 522 } | 519 } |
| 523 | 520 |
| 524 /** | 521 /** |
| 525 * @param {number} index | 522 * @param {number} index |
| 526 */ | 523 */ |
| 527 forceScrollItemToBeFirst(index) { | 524 forceScrollItemToBeFirst(index) { |
| 528 this.setStickToBottom(false); | 525 this.setStickToBottom(false); |
| 529 this._rebuildCumulativeHeightsIfNeeded(); | |
| 530 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0; | 526 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0; |
| 531 if (this.element.isScrolledToBottom()) | 527 if (this.element.isScrolledToBottom()) |
| 532 this.setStickToBottom(true); | 528 this.setStickToBottom(true); |
| 533 this.refresh(); | 529 this.refresh(); |
| 534 } | 530 } |
| 535 | 531 |
| 536 /** | 532 /** |
| 537 * @param {number} index | 533 * @param {number} index |
| 538 */ | 534 */ |
| 539 forceScrollItemToBeLast(index) { | 535 forceScrollItemToBeLast(index) { |
| 540 this.setStickToBottom(false); | 536 this.setStickToBottom(false); |
| 541 this._rebuildCumulativeHeightsIfNeeded(); | |
| 542 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeigh
t(); | 537 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeigh
t(); |
| 543 if (this.element.isScrolledToBottom()) | 538 if (this.element.isScrolledToBottom()) |
| 544 this.setStickToBottom(true); | 539 this.setStickToBottom(true); |
| 545 this.refresh(); | 540 this.refresh(); |
| 546 } | 541 } |
| 547 | 542 |
| 548 /** | 543 /** |
| 549 * @return {number} | 544 * @return {number} |
| 550 */ | 545 */ |
| 551 _visibleHeight() { | 546 _visibleHeight() { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 Console.ConsoleViewportElement.prototype = { | 593 Console.ConsoleViewportElement.prototype = { |
| 599 willHide() {}, | 594 willHide() {}, |
| 600 | 595 |
| 601 wasShown() {}, | 596 wasShown() {}, |
| 602 | 597 |
| 603 /** | 598 /** |
| 604 * @return {!Element} | 599 * @return {!Element} |
| 605 */ | 600 */ |
| 606 element() {}, | 601 element() {}, |
| 607 }; | 602 }; |
| OLD | NEW |