Index: third_party/WebKit/Source/devtools/front_end/ui/ListControl.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js b/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js |
index 6c8c6b3b25acc545f1e4e7137928ccb777c326a4..a76022f03598a1dae20f6b5baac5182dd216d20a 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js |
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ListControl.js |
@@ -59,9 +59,8 @@ UI.ListControl = class { |
this._lastIndex = 0; |
this._renderedHeight = 0; |
this._topHeight = 0; |
- this._topElement.style.height = '0'; |
this._bottomHeight = 0; |
- this._bottomElement.style.height = '0'; |
+ this._clearViewport(); |
/** @type {!Array<T>} */ |
this._items = []; |
@@ -81,6 +80,7 @@ UI.ListControl = class { |
this._delegate = delegate; |
this._heightMode = UI.ListHeightMode.Measured; |
this._fixedHeight = 0; |
+ this._variableOffsets = new Int32Array(0); |
this.element.addEventListener('scroll', this._onScroll.bind(this), false); |
} |
@@ -89,13 +89,11 @@ UI.ListControl = class { |
* @param {!UI.ListHeightMode} mode |
*/ |
setHeightMode(mode) { |
- if (mode === UI.ListHeightMode.Variable) |
- throw 'Variable height is not supported (yet)'; |
this._heightMode = mode; |
this._fixedHeight = 0; |
if (this._items.length) { |
this._itemToElement.clear(); |
- this._refresh(); |
+ this._invalidate(0, this._items.length, this._items.length); |
} |
} |
@@ -206,7 +204,12 @@ UI.ListControl = class { |
} |
viewportResized() { |
- this._refresh(); |
+ // TODO(dgozman): try to keep the visible scrollTop the same |
+ // when invalidating after firstIndex but before first visible element. |
+ var scrollTop = this.element.scrollTop; |
+ var viewportHeight = this.element.offsetHeight; |
+ this._clearViewport(); |
+ this._updateViewport(Number.constrain(scrollTop, 0, this._totalHeight() - viewportHeight), viewportHeight); |
} |
/** |
@@ -216,11 +219,11 @@ UI.ListControl = class { |
var top = this._offsetAtIndex(index); |
var bottom = this._offsetAtIndex(index + 1); |
var scrollTop = this.element.scrollTop; |
- var height = this.element.offsetHeight; |
+ var viewportHeight = this.element.offsetHeight; |
if (top < scrollTop) |
- this._update(top, height); |
- else if (bottom > scrollTop + height) |
- this._update(bottom - height, height); |
+ this._updateViewport(top, viewportHeight); |
+ else if (bottom > scrollTop + viewportHeight) |
+ this._updateViewport(bottom - viewportHeight, viewportHeight); |
} |
/** |
@@ -318,8 +321,10 @@ UI.ListControl = class { |
_indexAtOffset(offset) { |
if (!this._items.length || offset < 0) |
return 0; |
- if (this._heightMode === UI.ListHeightMode.Variable) |
- throw 'Variable height is not supported (yet)'; |
+ if (this._heightMode === UI.ListHeightMode.Variable) { |
+ return Math.min( |
+ this._items.length - 1, this._variableOffsets.lowerBound(offset, undefined, 0, this._items.length)); |
+ } |
if (!this._fixedHeight) |
this._measureHeight(); |
return Math.min(this._items.length - 1, Math.floor(offset / this._fixedHeight)); |
@@ -347,7 +352,7 @@ UI.ListControl = class { |
if (!this._items.length) |
return 0; |
if (this._heightMode === UI.ListHeightMode.Variable) |
- throw 'Variable height is not supported (yet)'; |
+ return this._variableOffsets[index]; |
if (!this._fixedHeight) |
this._measureHeight(); |
return index * this._fixedHeight; |
@@ -417,19 +422,43 @@ UI.ListControl = class { |
} |
/** |
+ * @param {number} length |
+ * @param {number} copyTo |
+ */ |
+ _reallocateVariableOffsets(length, copyTo) { |
+ if (this._variableOffsets.length < length) { |
+ var variableOffsets = new Int32Array(Math.max(length, this._variableOffsets.length * 2)); |
+ variableOffsets.set(this._variableOffsets.slice(0, copyTo), 0); |
+ this._variableOffsets = variableOffsets; |
+ } else if (this._variableOffsets.length >= 2 * length) { |
+ var variableOffsets = new Int32Array(length); |
+ variableOffsets.set(this._variableOffsets.slice(0, copyTo), 0); |
+ this._variableOffsets = variableOffsets; |
+ } |
+ } |
+ |
+ /** |
* @param {number} from |
* @param {number} to |
* @param {number} inserted |
*/ |
_invalidate(from, to, inserted) { |
+ if (this._heightMode === UI.ListHeightMode.Variable) { |
+ this._reallocateVariableOffsets(this._items.length + 1, from + 1); |
+ for (var i = from + 1; i <= this._items.length; i++) |
+ this._variableOffsets[i] = this._variableOffsets[i - 1] + this._delegate.heightForItem(this._items[i - 1]); |
+ } |
+ |
var viewportHeight = this.element.offsetHeight; |
var totalHeight = this._totalHeight(); |
+ var scrollTop = this.element.scrollTop; |
+ |
if (this._renderedHeight < viewportHeight || totalHeight < viewportHeight) { |
- this._refresh(); |
+ this._clearViewport(); |
+ this._updateViewport(Number.constrain(scrollTop, 0, totalHeight - viewportHeight), viewportHeight); |
return; |
} |
- var scrollTop = this.element.scrollTop; |
var heightDelta = totalHeight - this._renderedHeight; |
if (to <= this._firstIndex) { |
var topHeight = this._topHeight + heightDelta; |
@@ -453,32 +482,32 @@ UI.ListControl = class { |
// TODO(dgozman): try to keep the visible scrollTop the same |
// when invalidating after firstIndex but before first visible element. |
- this._refresh(); |
+ this._clearViewport(); |
+ this._updateViewport(Number.constrain(scrollTop, 0, totalHeight - viewportHeight), viewportHeight); |
} |
- _refresh() { |
- var viewportHeight = this.element.offsetHeight; |
- var scrollTop = Number.constrain(this.element.scrollTop, 0, this._totalHeight() - viewportHeight); |
+ _clearViewport() { |
this._firstIndex = 0; |
this._lastIndex = 0; |
this._renderedHeight = 0; |
this._topHeight = 0; |
this._bottomHeight = 0; |
+ this._topElement.style.height = '0'; |
+ this._bottomElement.style.height = '0'; |
this.element.removeChildren(); |
this.element.appendChild(this._topElement); |
this.element.appendChild(this._bottomElement); |
- this._update(scrollTop, viewportHeight); |
} |
_onScroll() { |
- this._update(this.element.scrollTop, this.element.offsetHeight); |
+ this._updateViewport(this.element.scrollTop, this.element.offsetHeight); |
} |
/** |
* @param {number} scrollTop |
* @param {number} viewportHeight |
*/ |
- _update(scrollTop, viewportHeight) { |
+ _updateViewport(scrollTop, viewportHeight) { |
// Note: this method should not force layout. Be careful. |
var totalHeight = this._totalHeight(); |