Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js b/third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..dfbfb0d65d0e81c40e6516d597c0eddafe06053d |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js |
| @@ -0,0 +1,172 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +/** |
| + * @constructor |
| + * @param {!WebInspector.StaticViewportControl.Provider} provider |
| + */ |
| +WebInspector.StaticViewportControl = function(provider) |
| +{ |
| + this.element = createElement("div"); |
| + this.element.style.overflow = "auto"; |
| + this._innerElement = this.element.createChild("div"); |
| + this._innerElement.style.height = "0px"; |
| + this._innerElement.style.position = "relative"; |
| + this._innerElement.style.overflow = "hidden"; |
| + this._provider = provider; |
| + this.element.addEventListener("scroll", this.refresh.bind(this), false); |
| + |
| + this._firstActiveIndex = 0; |
| + this._lastActiveIndex = -1; |
| + this._itemCount = 0; |
| +} |
| + |
| +WebInspector.StaticViewportControl.prototype = { |
| + invalidate: function() |
| + { |
| + this._itemCount = this._provider.itemCount(); |
| + this._innerElement.removeChildren(); |
| + this.refresh(); |
| + }, |
| + |
| + refresh: function() |
|
dgozman
2016/09/28 16:50:06
What's the difference from invalidate? Let's have
einbinder
2016/09/28 19:19:42
invalidate rebuilds the contents inside the viewpo
dgozman
2016/09/28 20:56:18
As a client of viewport, I still don't understand
einbinder
2016/09/29 01:04:20
Merged invalidate into refresh.
|
| + { |
| + if (!this._visibleHeight()) |
| + return; // Do nothing for invisible controls. |
| + |
| + var height = 0; |
| + this._cumulativeHeights = new Int32Array(this._itemCount); |
| + for (var i = 0; i < this._itemCount; ++i) |
| + this._cumulativeHeights[i] = height += this._provider.fastHeight(i); |
|
dgozman
2016/09/28 16:50:05
style: this should be two lines
einbinder
2016/09/28 19:19:42
Done.
|
| + this._innerElement.style.height = height + "px"; |
| + |
| + this._update(); |
| + }, |
| + |
| + _update: function() |
| + { |
| + if (!this._cumulativeHeights) |
| + return this.refresh(); |
|
dgozman
2016/09/28 16:50:05
refresh does not return anything
einbinder
2016/09/28 19:19:42
Done.
|
| + |
| + var visibleHeight = this._visibleHeight(); |
| + var visibleFrom = this.element.scrollTop; |
| + var activeHeight = visibleHeight * 2; |
| + this._firstActiveIndex = Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2), 0); |
| + this._lastActiveIndex = Math.min(Array.prototype.lowerBound.call(this._cumulativeHeights, visibleFrom + visibleHeight + (activeHeight - visibleHeight) / 2), this._itemCount - 1); |
| + |
| + for (var i = this._innerElement.children.length - 1; i >= 0; --i) { |
| + var element = this._innerElement.children[i]; |
| + if (element.__insertedAt < this._firstActiveIndex || element.__insertedAt > this._lastActiveIndex) |
| + element.remove(); |
|
dgozman
2016/09/28 16:50:06
Remove/nullify element.__insertedAt
einbinder
2016/09/28 19:19:42
I'd have to do that above where I call this._inner
dgozman
2016/09/28 20:56:18
Nothing prevents me from moving my element to anot
einbinder
2016/09/29 01:04:20
Gave each instance of StaticViewportControl its ow
|
| + } |
| + |
| + for (var i = this._firstActiveIndex; i <= this._lastActiveIndex; ++i) |
| + this._insertElement(i); |
| + }, |
| + |
| + /** |
| + * @param {number} index |
| + */ |
| + _insertElement: function(index) |
| + { |
| + var element = this._provider.itemElement(index); |
| + if (!element || element.parentElement) |
| + return; |
| + |
| + element.style.position = "absolute"; |
| + element.style.top = (this._cumulativeHeights[index - 1] || 0) + "px"; |
| + element.style.left = "0"; |
| + element.style.right = "0"; |
| + element.__insertedAt = index; |
|
dgozman
2016/09/28 16:50:06
Use symbol.
einbinder
2016/09/28 19:19:42
Done.
|
| + this._innerElement.appendChild(element); |
| + }, |
| + |
| + /** |
| + * @return {number} |
| + */ |
| + firstVisibleIndex: function() |
| + { |
| + var firstVisibleIndex = Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + 1), 0); |
| + return Math.max(firstVisibleIndex, this._firstActiveIndex); |
|
dgozman
2016/09/28 16:50:06
I don't get why we use this._firstActiveIndex.
|
| + }, |
| + |
| + /** |
| + * @return {number} |
| + */ |
| + lastVisibleIndex: function() |
| + { |
| + var lastVisibleIndex = Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + this._visibleHeight()), 0); |
| + return Math.min(lastVisibleIndex, this._lastActiveIndex); |
|
dgozman
2016/09/28 16:50:05
ditto
einbinder
2016/09/28 19:19:42
If the viewport has very few items, lastVisibleInd
dgozman
2016/09/28 20:56:18
Thanks for explaining.
This is the only place we u
einbinder
2016/09/29 01:04:20
Done.
|
| + }, |
| + |
| + /** |
| + * @param {number} index |
| + * @param {boolean=} makeLast |
| + */ |
| + scrollItemIntoView: function(index, makeLast) |
| + { |
| + var firstVisibleIndex = this.firstVisibleIndex(); |
| + var lastVisibleIndex = this.lastVisibleIndex(); |
| + if (index > firstVisibleIndex && index < lastVisibleIndex) |
| + return; |
| + if (makeLast) |
| + this.forceScrollItemToBeLast(index); |
| + else if (index <= firstVisibleIndex) |
| + this.forceScrollItemToBeFirst(index); |
| + else if (index >= lastVisibleIndex) |
| + this.forceScrollItemToBeLast(index); |
| + }, |
| + |
| + /** |
| + * @param {number} index |
| + */ |
| + forceScrollItemToBeFirst: function(index) |
| + { |
| + this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0; |
| + this._update(); |
| + }, |
| + |
| + /** |
| + * @param {number} index |
| + */ |
| + forceScrollItemToBeLast: function(index) |
| + { |
| + this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeight(); |
| + this._update(); |
| + }, |
| + |
| + /** |
| + * @return {number} |
| + */ |
| + _visibleHeight: function() |
| + { |
| + return this.element.offsetHeight; |
|
dgozman
2016/09/28 16:50:06
Maybe inline?
einbinder
2016/09/28 19:19:42
ViewportControl has a comment here about not using
|
| + } |
| +} |
| + |
| +/** |
| + * @interface |
| + */ |
| +WebInspector.StaticViewportControl.Provider = function() |
| +{ |
| +} |
| + |
| +WebInspector.StaticViewportControl.Provider.prototype = { |
| + /** |
| + * @param {number} index |
| + * @return {number} |
| + */ |
| + fastHeight: function(index) { return 0; }, |
| + |
| + /** |
| + * @return {number} |
| + */ |
| + itemCount: function() { return 0; }, |
| + |
| + /** |
| + * @param {number} index |
| + * @return {?Element} |
| + */ |
| + itemElement: function(index) { return null; } |
| +} |