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

Unified Diff: third_party/WebKit/Source/devtools/front_end/ui/StaticViewportControl.js

Issue 2371393002: DevTools: Add lightweight StaticViewportControl (Closed)
Patch Set: Created 4 years, 3 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 side-by-side diff with in-line comments
Download patch
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; }
+}

Powered by Google App Engine
This is Rietveld 408576698