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

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

Issue 2592433003: [DevTools] Replace ViewportControl with ListControl. (Closed)
Patch Set: Created 3 years, 12 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
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 * @unrestricted 5 * @unrestricted
6 */ 6 */
7 UI.ViewportControl = class { 7 UI.ViewportControl = class {
8 /** 8 /**
9 * @param {!UI.ViewportControl.Provider} provider 9 * @param {!UI.ViewportProvider} provider
10 */ 10 */
11 constructor(provider) { 11 constructor(provider) {
12 this.element = createElement('div'); 12 this.element = createElement('div');
13 this.element.style.overflow = 'auto'; 13 this.element.style.overflow = 'auto';
14 this._innerElement = this.element.createChild('div'); 14 this._topElement = this.element.createChild('div');
15 this._innerElement.style.height = '0px'; 15 this._bottomElement = this.element.createChild('div');
16 this._innerElement.style.position = 'relative';
17 this._innerElement.style.overflow = 'hidden';
18
19 this._provider = provider; 16 this._provider = provider;
20 this.element.addEventListener('scroll', this._update.bind(this), false); 17 this._firstIndex = 0;
21 this._itemCount = 0; 18 this._lastIndex = 0;
22 this._indexSymbol = Symbol('UI.ViewportControl._indexSymbol'); 19 this.element.addEventListener('scroll', this._onScroll.bind(this), false);
20 this._update(0);
21 }
22
23 /**
24 * @param {number} from
25 * @param {number} to
26 */
27 spliced(from, to) {
28 var scrollTop = this.element.scrollTop;
29 var totalHeight = this._provider.totalHeight();
30 if (this._totalHeight < this.element.offsetHeight) {
31 this.refresh();
32 return;
33 }
34 if (to <= this._firstIndex) {
35 var topHeight = this._topHeight + totalHeight - this._totalHeight;
36 this._topElement.style.height = topHeight + 'px';
37 this.element.scrollTop = scrollTop + totalHeight - this._totalHeight;
38 this._topHeight = topHeight;
39 this._totalHeight = totalHeight;
40 return;
41 }
42 if (from >= this._lastIndex) {
43 var bottomHeight = this._bottomHeight + totalHeight - this._totalHeight;
44 this._bottomElement.style.height = bottomHeight + 'px';
45 this.element.scrollTop = scrollTop + totalHeight - this._totalHeight;
46 this._bottomHeight = bottomHeight;
47 this._totalHeight = totalHeight;
48 return;
49 }
50 this.refresh();
23 } 51 }
24 52
25 refresh() { 53 refresh() {
26 this._itemCount = this._provider.itemCount(); 54 this._firstIndex = 0;
27 this._innerElement.removeChildren(); 55 this._lastIndex = 0;
28 56 this.element.removeChildren();
29 var height = 0; 57 this.element.appendChild(this._topElement);
30 this._cumulativeHeights = new Int32Array(this._itemCount); 58 this.element.appendChild(this._bottomElement);
31 for (var i = 0; i < this._itemCount; ++i) { 59 this._update(0);
32 height += this._provider.fastItemHeight(i); 60 }
33 this._cumulativeHeights[i] = height; 61
34 } 62 _onScroll() {
35 this._innerElement.style.height = height + 'px'; 63 this._update(this.element.scrollTop);
36 64 }
37 this._update(); 65
38 } 66 /**
39 67 * @param {number} scrollTop
40 _update() { 68 */
41 if (!this._cumulativeHeights) { 69 _update(scrollTop) {
42 this.refresh(); 70 var totalHeight = this._provider.totalHeight();
43 return; 71 if (!totalHeight) {
44 } 72 this._firstIndex = 0;
45 73 this._lastIndex = 0;
46 var visibleHeight = this._visibleHeight(); 74 this._topHeight = 0;
47 var visibleFrom = this.element.scrollTop; 75 this._bottomHeight = 0;
48 var activeHeight = visibleHeight * 2; 76 this._totalHeight = 0;
49 var firstActiveIndex = Math.max( 77 this._topElement.style.height = '0px';
50 Array.prototype.lowerBound.call(this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2), 78 this._bottomElement.style.height = '0px';
51 0); 79 return;
52 var lastActiveIndex = Math.min( 80 }
53 Array.prototype.lowerBound.call( 81
54 this._cumulativeHeights, visibleFrom + visibleHeight + (activeHeight - visibleHeight) / 2), 82 var height = this.element.offsetHeight;
55 this._itemCount - 1); 83 var firstIndex = this._provider.indexAtOffset(Math.max(0, scrollTop - height ));
56 84 var lastIndex = this._provider.indexAtOffset(Math.min(totalHeight, scrollTop + 2 * height)) + 1;
57 var children = this._innerElement.children; 85
58 for (var i = children.length - 1; i >= 0; --i) { 86 for (var index = this._firstIndex; index < firstIndex; index++) {
59 var element = children[i]; 87 var element = this._provider.elementAtIndex(index);
60 if (element[this._indexSymbol] < firstActiveIndex || element[this._indexSy mbol] > lastActiveIndex) 88 element.remove();
61 element.remove(); 89 this._firstIndex++;
62 } 90 }
63 91 for (var index = this._lastIndex - 1; index >= lastIndex; index--) {
64 for (var i = firstActiveIndex; i <= lastActiveIndex; ++i) 92 var element = this._provider.elementAtIndex(index);
65 this._insertElement(i); 93 element.remove();
66 } 94 this._lastIndex--;
67 95 }
68 /** 96 this._firstIndex = Math.min(this._firstIndex, lastIndex);
69 * @param {number} index 97 this._lastIndex = Math.max(this._lastIndex, firstIndex);
70 */ 98 for (var index = this._firstIndex - 1; index >= firstIndex; index--) {
71 _insertElement(index) { 99 var element = this._provider.elementAtIndex(index);
72 var element = this._provider.itemElement(index); 100 this.element.insertBefore(element, this._topElement.nextSibling);
73 if (!element || element.parentElement === this._innerElement) 101 }
74 return; 102 for (var index = this._lastIndex; index < lastIndex; index++) {
75 103 var element = this._provider.elementAtIndex(index);
76 element.style.position = 'absolute'; 104 this.element.insertBefore(element, this._bottomElement);
77 element.style.top = (this._cumulativeHeights[index - 1] || 0) + 'px'; 105 }
78 element.style.left = '0'; 106
79 element.style.right = '0'; 107 this._firstIndex = firstIndex;
80 element[this._indexSymbol] = index; 108 this._lastIndex = lastIndex;
81 this._innerElement.appendChild(element); 109 this._totalHeight = totalHeight;
82 } 110 this._topHeight = this._provider.offsetAtIndex(firstIndex);
83 111 this._topElement.style.height = this._topHeight + 'px';
84 /** 112 this._bottomHeight = (totalHeight - this._provider.offsetAtIndex(lastIndex)) ;
85 * @return {number} 113 this._bottomElement.style.height = this._bottomHeight + 'px';
86 */ 114 this.element.scrollTop = scrollTop;
87 firstVisibleIndex() { 115 }
88 return Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, thi s.element.scrollTop + 1), 0); 116
89 } 117 /**
90 118 * @param {number} index
91 /** 119 */
92 * @return {number} 120 scrollItemIntoView(index) {
93 */ 121 var top = this._provider.offsetAtIndex(index);
94 lastVisibleIndex() { 122 var bottom = this._provider.offsetAtIndex(index + 1);
95 return Math.min( 123 var scrollTop = this.element.scrollTop;
96 Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.sc rollTop + this._visibleHeight()), 124 var height = this.element.offsetHeight;
97 this._itemCount); 125 if (top < scrollTop)
98 } 126 this._update(top);
99 127 else if (bottom > scrollTop + height)
100 /** 128 this._update(bottom - height);
101 * @param {number} index
102 * @param {boolean=} makeLast
103 */
104 scrollItemIntoView(index, makeLast) {
105 var firstVisibleIndex = this.firstVisibleIndex();
106 var lastVisibleIndex = this.lastVisibleIndex();
107 if (index > firstVisibleIndex && index < lastVisibleIndex)
108 return;
109 if (makeLast)
110 this.forceScrollItemToBeLast(index);
111 else if (index <= firstVisibleIndex)
112 this.forceScrollItemToBeFirst(index);
113 else if (index >= lastVisibleIndex)
114 this.forceScrollItemToBeLast(index);
115 }
116
117 /**
118 * @param {number} index
119 */
120 forceScrollItemToBeFirst(index) {
121 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0;
122 this._update();
123 }
124
125 /**
126 * @param {number} index
127 */
128 forceScrollItemToBeLast(index) {
129 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeigh t();
130 this._update();
131 }
132
133 /**
134 * @return {number}
135 */
136 _visibleHeight() {
137 return this.element.offsetHeight;
138 } 129 }
139 }; 130 };
140 131
141 /** 132 /**
142 * @interface 133 * @interface
143 */ 134 */
144 UI.ViewportControl.Provider = function() {}; 135 UI.ViewportProvider = function() {};
145 136
146 UI.ViewportControl.Provider.prototype = { 137 UI.ViewportProvider.prototype = {
147 /** 138 /**
148 * @param {number} index 139 * @param {number} height
149 * @return {number} 140 * @return {number}
150 */ 141 */
151 fastItemHeight(index) { 142 indexAtOffset(height) {},
pfeldman 2016/12/20 01:23:51 I understand the former API, but don't get the new
152 return 0; 143
153 }, 144 /**
154 145 * @return {number}
155 /** 146 */
156 * @return {number} 147 totalHeight() {},
157 */ 148
158 itemCount() { 149 /**
159 return 0; 150 * @param {number} index
160 }, 151 * @return {!Element}
161 152 */
162 /** 153 elementAtIndex(index) {},
163 * @param {number} index 154
164 * @return {?Element} 155 /**
165 */ 156 * @param {number} index
166 itemElement(index) { 157 * @return {number}
167 return null; 158 */
168 } 159 offsetAtIndex(index) {},
169 }; 160 };
161
162 /**
163 * @implements {UI.ViewportProvider}
164 */
165 UI.SimpleViewport = class {
166 /**
167 * @param {function(number):!Element} elementsFactory
168 */
169 constructor(elementsFactory) {
170 this._elementsFactory = elementsFactory;
171 /** @type {!Array<?Element>} */
172 this._elements = [];
173 /** @type {number} */
174 this._height = 0;
175 this._length = 0;
176 this._viewport = new UI.ViewportControl(this);
177 this.element = this._viewport.element;
178 }
179
180 /**
181 * @param {number} length
182 */
183 refresh(length) {
184 this._elements = [];
185 var oldLength = this._length;
186 this._length = length;
187 this._viewport.spliced(0, oldLength);
188 }
189
190 /**
191 * @return {number}
192 */
193 elementHeight() {
194 if (!this._height)
195 this._height = UI.measurePreferredSize(this.elementAtIndex(0), this._viewp ort.element).height;
196 return this._height;
197 }
198
199 resetElementHeight() {
200 this._height = 0;
201 }
202
203 /**
204 * @return {number}
205 */
206 elementsPerViewport() {
207 if (!this._length)
208 return 0;
209 return Math.floor(this._viewport.element.offsetHeight / this.elementHeight() );
210 }
211
212 /**
213 * @param {number} index
214 */
215 scrollItemIntoView(index) {
216 this._viewport.scrollItemIntoView(index);
217 }
218
219 /**
220 * @override
221 * @param {number} height
222 * @return {number}
223 */
224 indexAtOffset(height) {
225 if (!this._length)
226 return 0;
227 var index = Math.floor(height / this.elementHeight());
228 if (index >= this._length)
229 return this._length - 1;
230 return index;
231 }
232
233 /**
234 * @override
235 * @return {number}
236 */
237 totalHeight() {
238 if (!this._length)
239 return 0;
240 return this._length * this.elementHeight();
241 }
242
243 /**
244 * @override
245 * @param {number} index
246 * @return {!Element}
247 */
248 elementAtIndex(index) {
249 var element = this._elements[index];
250 if (!element) {
251 element = this._elementsFactory.call(null, index);
252 this._elements[index] = element;
253 }
254 return element;
255 }
256
257 /**
258 * @override
259 * @param {number} index
260 * @return {number}
261 */
262 offsetAtIndex(index) {
263 if (!this._length)
264 return 0;
265 return index * this.elementHeight();
266 }
267 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698