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 |