| 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 | |
| 5 /** | 4 /** |
| 6 * @constructor | 5 * @unrestricted |
| 7 * @param {!WebInspector.StaticViewportControl.Provider} provider | |
| 8 */ | 6 */ |
| 9 WebInspector.StaticViewportControl = function(provider) | 7 WebInspector.StaticViewportControl = class { |
| 10 { | 8 /** |
| 11 this.element = createElement("div"); | 9 * @param {!WebInspector.StaticViewportControl.Provider} provider |
| 12 this.element.style.overflow = "auto"; | 10 */ |
| 13 this._innerElement = this.element.createChild("div"); | 11 constructor(provider) { |
| 14 this._innerElement.style.height = "0px"; | 12 this.element = createElement('div'); |
| 15 this._innerElement.style.position = "relative"; | 13 this.element.style.overflow = 'auto'; |
| 16 this._innerElement.style.overflow = "hidden"; | 14 this._innerElement = this.element.createChild('div'); |
| 15 this._innerElement.style.height = '0px'; |
| 16 this._innerElement.style.position = 'relative'; |
| 17 this._innerElement.style.overflow = 'hidden'; |
| 17 | 18 |
| 18 this._provider = provider; | 19 this._provider = provider; |
| 19 this.element.addEventListener("scroll", this._update.bind(this), false); | 20 this.element.addEventListener('scroll', this._update.bind(this), false); |
| 20 this._itemCount = 0; | 21 this._itemCount = 0; |
| 21 this._indexSymbol = Symbol("WebInspector.StaticViewportControl._indexSymbol"
); | 22 this._indexSymbol = Symbol('WebInspector.StaticViewportControl._indexSymbol'
); |
| 22 }; | 23 } |
| 23 | 24 |
| 24 WebInspector.StaticViewportControl.prototype = { | 25 refresh() { |
| 25 refresh: function() | 26 this._itemCount = this._provider.itemCount(); |
| 26 { | 27 this._innerElement.removeChildren(); |
| 27 this._itemCount = this._provider.itemCount(); | |
| 28 this._innerElement.removeChildren(); | |
| 29 | 28 |
| 30 var height = 0; | 29 var height = 0; |
| 31 this._cumulativeHeights = new Int32Array(this._itemCount); | 30 this._cumulativeHeights = new Int32Array(this._itemCount); |
| 32 for (var i = 0; i < this._itemCount; ++i) { | 31 for (var i = 0; i < this._itemCount; ++i) { |
| 33 height += this._provider.fastItemHeight(i); | 32 height += this._provider.fastItemHeight(i); |
| 34 this._cumulativeHeights[i] = height; | 33 this._cumulativeHeights[i] = height; |
| 35 } | 34 } |
| 36 this._innerElement.style.height = height + "px"; | 35 this._innerElement.style.height = height + 'px'; |
| 37 | 36 |
| 38 this._update(); | 37 this._update(); |
| 39 }, | 38 } |
| 40 | 39 |
| 41 _update: function() | 40 _update() { |
| 42 { | 41 if (!this._cumulativeHeights) { |
| 43 if (!this._cumulativeHeights) { | 42 this.refresh(); |
| 44 this.refresh(); | 43 return; |
| 45 return; | 44 } |
| 46 } | |
| 47 | 45 |
| 48 var visibleHeight = this._visibleHeight(); | 46 var visibleHeight = this._visibleHeight(); |
| 49 var visibleFrom = this.element.scrollTop; | 47 var visibleFrom = this.element.scrollTop; |
| 50 var activeHeight = visibleHeight * 2; | 48 var activeHeight = visibleHeight * 2; |
| 51 var firstActiveIndex = Math.max(Array.prototype.lowerBound.call(this._cu
mulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2), 0); | 49 var firstActiveIndex = Math.max( |
| 52 var lastActiveIndex = Math.min(Array.prototype.lowerBound.call(this._cum
ulativeHeights, visibleFrom + visibleHeight + (activeHeight - visibleHeight) / 2
), this._itemCount - 1); | 50 Array.prototype.lowerBound.call(this._cumulativeHeights, visibleFrom + 1
- (activeHeight - visibleHeight) / 2), |
| 51 0); |
| 52 var lastActiveIndex = Math.min( |
| 53 Array.prototype.lowerBound.call( |
| 54 this._cumulativeHeights, visibleFrom + visibleHeight + (activeHeight
- visibleHeight) / 2), |
| 55 this._itemCount - 1); |
| 53 | 56 |
| 54 var children = this._innerElement.children; | 57 var children = this._innerElement.children; |
| 55 for (var i = children.length - 1; i >= 0; --i) { | 58 for (var i = children.length - 1; i >= 0; --i) { |
| 56 var element = children[i]; | 59 var element = children[i]; |
| 57 if (element[this._indexSymbol] < firstActiveIndex || element[this._i
ndexSymbol] > lastActiveIndex) | 60 if (element[this._indexSymbol] < firstActiveIndex || element[this._indexSy
mbol] > lastActiveIndex) |
| 58 element.remove(); | 61 element.remove(); |
| 59 } | 62 } |
| 60 | 63 |
| 61 for (var i = firstActiveIndex; i <= lastActiveIndex; ++i) | 64 for (var i = firstActiveIndex; i <= lastActiveIndex; ++i) |
| 62 this._insertElement(i); | 65 this._insertElement(i); |
| 63 }, | 66 } |
| 64 | 67 |
| 65 /** | 68 /** |
| 66 * @param {number} index | 69 * @param {number} index |
| 67 */ | 70 */ |
| 68 _insertElement: function(index) | 71 _insertElement(index) { |
| 69 { | 72 var element = this._provider.itemElement(index); |
| 70 var element = this._provider.itemElement(index); | 73 if (!element || element.parentElement === this._innerElement) |
| 71 if (!element || element.parentElement === this._innerElement) | 74 return; |
| 72 return; | |
| 73 | 75 |
| 74 element.style.position = "absolute"; | 76 element.style.position = 'absolute'; |
| 75 element.style.top = (this._cumulativeHeights[index - 1] || 0) + "px"; | 77 element.style.top = (this._cumulativeHeights[index - 1] || 0) + 'px'; |
| 76 element.style.left = "0"; | 78 element.style.left = '0'; |
| 77 element.style.right = "0"; | 79 element.style.right = '0'; |
| 78 element[this._indexSymbol] = index; | 80 element[this._indexSymbol] = index; |
| 79 this._innerElement.appendChild(element); | 81 this._innerElement.appendChild(element); |
| 80 }, | 82 } |
| 81 | 83 |
| 82 /** | 84 /** |
| 83 * @return {number} | 85 * @return {number} |
| 84 */ | 86 */ |
| 85 firstVisibleIndex: function() | 87 firstVisibleIndex() { |
| 86 { | 88 return Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, thi
s.element.scrollTop + 1), 0); |
| 87 return Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights,
this.element.scrollTop + 1), 0); | 89 } |
| 88 }, | |
| 89 | 90 |
| 90 /** | 91 /** |
| 91 * @return {number} | 92 * @return {number} |
| 92 */ | 93 */ |
| 93 lastVisibleIndex: function() | 94 lastVisibleIndex() { |
| 94 { | 95 return Math.min( |
| 95 return Math.min(Array.prototype.lowerBound.call(this._cumulativeHeights,
this.element.scrollTop + this._visibleHeight()), this._itemCount); | 96 Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.sc
rollTop + this._visibleHeight()), |
| 96 }, | 97 this._itemCount); |
| 98 } |
| 97 | 99 |
| 98 /** | 100 /** |
| 99 * @param {number} index | 101 * @param {number} index |
| 100 * @param {boolean=} makeLast | 102 * @param {boolean=} makeLast |
| 101 */ | 103 */ |
| 102 scrollItemIntoView: function(index, makeLast) | 104 scrollItemIntoView(index, makeLast) { |
| 103 { | 105 var firstVisibleIndex = this.firstVisibleIndex(); |
| 104 var firstVisibleIndex = this.firstVisibleIndex(); | 106 var lastVisibleIndex = this.lastVisibleIndex(); |
| 105 var lastVisibleIndex = this.lastVisibleIndex(); | 107 if (index > firstVisibleIndex && index < lastVisibleIndex) |
| 106 if (index > firstVisibleIndex && index < lastVisibleIndex) | 108 return; |
| 107 return; | 109 if (makeLast) |
| 108 if (makeLast) | 110 this.forceScrollItemToBeLast(index); |
| 109 this.forceScrollItemToBeLast(index); | 111 else if (index <= firstVisibleIndex) |
| 110 else if (index <= firstVisibleIndex) | 112 this.forceScrollItemToBeFirst(index); |
| 111 this.forceScrollItemToBeFirst(index); | 113 else if (index >= lastVisibleIndex) |
| 112 else if (index >= lastVisibleIndex) | 114 this.forceScrollItemToBeLast(index); |
| 113 this.forceScrollItemToBeLast(index); | 115 } |
| 114 }, | |
| 115 | 116 |
| 116 /** | 117 /** |
| 117 * @param {number} index | 118 * @param {number} index |
| 118 */ | 119 */ |
| 119 forceScrollItemToBeFirst: function(index) | 120 forceScrollItemToBeFirst(index) { |
| 120 { | 121 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0; |
| 121 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1]
: 0; | 122 this._update(); |
| 122 this._update(); | 123 } |
| 123 }, | |
| 124 | 124 |
| 125 /** | 125 /** |
| 126 * @param {number} index | 126 * @param {number} index |
| 127 */ | 127 */ |
| 128 forceScrollItemToBeLast: function(index) | 128 forceScrollItemToBeLast(index) { |
| 129 { | 129 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeigh
t(); |
| 130 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleH
eight(); | 130 this._update(); |
| 131 this._update(); | 131 } |
| 132 }, | |
| 133 | 132 |
| 134 /** | 133 /** |
| 135 * @return {number} | 134 * @return {number} |
| 136 */ | 135 */ |
| 137 _visibleHeight: function() | 136 _visibleHeight() { |
| 138 { | 137 return this.element.offsetHeight; |
| 139 return this.element.offsetHeight; | 138 } |
| 140 } | |
| 141 }; | 139 }; |
| 142 | 140 |
| 143 /** | 141 /** |
| 144 * @interface | 142 * @interface |
| 145 */ | 143 */ |
| 146 WebInspector.StaticViewportControl.Provider = function() | 144 WebInspector.StaticViewportControl.Provider = function() {}; |
| 147 { | |
| 148 }; | |
| 149 | 145 |
| 150 WebInspector.StaticViewportControl.Provider.prototype = { | 146 WebInspector.StaticViewportControl.Provider.prototype = { |
| 151 /** | 147 /** |
| 152 * @param {number} index | 148 * @param {number} index |
| 153 * @return {number} | 149 * @return {number} |
| 154 */ | 150 */ |
| 155 fastItemHeight: function(index) { return 0; }, | 151 fastItemHeight: function(index) { |
| 152 return 0; |
| 153 }, |
| 156 | 154 |
| 157 /** | 155 /** |
| 158 * @return {number} | 156 * @return {number} |
| 159 */ | 157 */ |
| 160 itemCount: function() { return 0; }, | 158 itemCount: function() { |
| 159 return 0; |
| 160 }, |
| 161 | 161 |
| 162 /** | 162 /** |
| 163 * @param {number} index | 163 * @param {number} index |
| 164 * @return {?Element} | 164 * @return {?Element} |
| 165 */ | 165 */ |
| 166 itemElement: function(index) { return null; } | 166 itemElement: function(index) { |
| 167 return null; |
| 168 } |
| 167 }; | 169 }; |
| OLD | NEW |