Commit c17e290f authored by dgozman's avatar dgozman Committed by Commit bot

[DevTools] Replace ViewportControl with ListControl.

This patch introduces a list control, which maintains an array-like model. This makes
it possible to update model efficiently (not in O(n) all the time).

It also improves fast smooth scrolling of viewport on mac (less flashes)
by using gap elements instead of absolute positioning.

Only supports fixed/measured height elements, variable height is coming next (to be used in treeoutline).

BUG=none

Review-Url: https://codereview.chromium.org/2592433003
Cr-Commit-Position: refs/heads/master@{#440919}
parent 1b2247e8
......@@ -41,10 +41,10 @@ function test() {
function dump()
{
TestRunner.addResult("Query:" + JSON.stringify(filteredSelectionDialog._value()));
var items = filteredSelectionDialog._filteredItems;
var list = filteredSelectionDialog._list;
var output = [];
for (var i = 0; i < items.length; ++i)
output.push(delegate.itemKeyAt(items[i]));
for (var i = 0; i < list.length(); ++i)
output.push(delegate.itemKeyAt(list.itemAtIndex(i)));
TestRunner.addResult("Output:" + JSON.stringify(output));
}
......
Test ListControl rendering and selection for fixed height case.
Adding 0, 1, 2
Creating element for 0
Creating element for 1
Creating element for 2
----list[length=3][height=73]----
[0] top
*[0] 0
*[10] 1
*[20] 2
*[30] bottom
Scrolling to 0
----list[length=3][height=73]----
[0] top
*[0] 0
*[10] 1
*[20] 2
*[30] bottom
Scrolling to 2
----list[length=3][height=73]----
[0] top
*[0] 0
*[10] 1
*[20] 2
*[30] bottom
ArrowDown
Selection changed from null to 0
----list[length=3][height=73]----
[0] top
*[0] 0 (selected)
*[10] 1
*[20] 2
*[30] bottom
Selecting 2
Selection changed from 0 to 2
----list[length=3][height=73]----
[0] top
*[0] 0
*[10] 1
*[20] 2 (selected)
*[30] bottom
PageUp
Selection changed from 2 to 0
----list[length=3][height=73]----
[0] top
*[0] 0 (selected)
*[10] 1
*[20] 2
*[30] bottom
PageDown
Selection changed from 0 to 2
----list[length=3][height=73]----
[0] top
*[0] 0
*[10] 1
*[20] 2 (selected)
*[30] bottom
ArrowDown
Selection changed from 2 to 0
----list[length=3][height=73]----
[0] top
*[0] 0 (selected)
*[10] 1
*[20] 2
*[30] bottom
Replacing 0 with 5, 6, 7
Creating element for 5
Creating element for 6
Creating element for 7
Selection changed from 0 to 2
----list[length=5][height=73]----
[0] top
*[0] 5
*[10] 6
*[20] 7
*[30] 1
*[40] 2 (selected)
*[50] bottom
ArrowUp
Selection changed from 2 to 7
----list[length=5][height=73]----
[0] top
*[0] 5
*[10] 6
*[20] 7 (selected)
*[30] 1
*[40] 2
*[50] bottom
Pushing 10
Creating element for 10
----list[length=6][height=73]----
[0] top
*[0] 5
*[10] 6
*[20] 7 (selected)
*[30] 1
*[40] 2
*[50] 10
*[60] bottom
Selecting 10
Selection changed from 7 to 10
----list[length=6][height=73]----
[0] top
*[0] 5
*[10] 6
*[20] 7
*[30] 1
*[40] 2
*[50] 10 (selected)
*[60] bottom
Popping 10
Selection changed from 10 to 2
----list[length=5][height=73]----
[0] top
*[0] 5
*[10] 6
*[20] 7
*[30] 1
*[40] 2 (selected)
*[50] bottom
Removing 2
Selection changed from 2 to 7
----list[length=4][height=73]----
[0] top
*[0] 5
*[10] 6
*[20] 7 (selected)
*[30] 1
*[40] bottom
Inserting 8
Creating element for 8
----list[length=5][height=73]----
[0] top
*[0] 5
*[10] 8
*[20] 6
*[30] 7 (selected)
*[40] 1
*[50] bottom
Replacing with 0...20
Creating element for 0
Creating element for 1
Creating element for 2
Creating element for 3
Creating element for 4
Creating element for 5
Creating element for 6
Creating element for 7
Creating element for 8
Creating element for 9
Creating element for 10
Creating element for 11
Creating element for 12
Creating element for 13
Creating element for 14
Selection changed from 7 to null
----list[length=20][height=73]----
[0] top
*[0] 0
*[10] 1
*[20] 2
*[30] 3
*[40] 4
*[50] 5
*[60] 6
+[70] 7
[80] 8
[90] 9
[100] 10
[110] 11
[120] 12
[130] 13
[140] 14
[150] bottom
Resizing
Creating element for 15
Creating element for 16
----list[length=20][height=84]----
[0] top
*[0] 0
*[10] 1
*[20] 2
*[30] 3
*[40] 4
*[50] 5
*[60] 6
*[70] 7
+[80] 8
[90] 9
[100] 10
[110] 11
[120] 12
[130] 13
[140] 14
[150] 15
[160] 16
[170] bottom
Scrolling to 19
Creating element for 17
Creating element for 18
Creating element for 19
----list[length=20][height=84]----
[-116] top
[-86] 3
[-76] 4
[-66] 5
[-56] 6
[-46] 7
[-36] 8
[-26] 9
[-16] 10
+[-6] 11
*[4] 12
*[14] 13
*[24] 14
*[34] 15
*[44] 16
*[54] 17
*[64] 18
*[74] 19
[84] bottom
Scrolling to 5
----list[length=20][height=84]----
[-50] top
[-50] 0
[-40] 1
[-30] 2
[-20] 3
[-10] 4
*[0] 5
*[10] 6
*[20] 7
*[30] 8
*[40] 9
*[50] 10
*[60] 11
*[70] 12
+[80] 13
[90] 14
[100] 15
[110] 16
[120] 17
[130] 18
[140] 19
[150] bottom
Scrolling to 12
----list[length=20][height=84]----
[-50] top
[-50] 0
[-40] 1
[-30] 2
[-20] 3
[-10] 4
*[0] 5
*[10] 6
*[20] 7
*[30] 8
*[40] 9
*[50] 10
*[60] 11
*[70] 12
+[80] 13
[90] 14
[100] 15
[110] 16
[120] 17
[130] 18
[140] 19
[150] bottom
Scrolling to 13
----list[length=20][height=84]----
[-56] top
[-56] 0
[-46] 1
[-36] 2
[-26] 3
[-16] 4
+[-6] 5
*[4] 6
*[14] 7
*[24] 8
*[34] 9
*[44] 10
*[54] 11
*[64] 12
*[74] 13
[84] 14
[94] 15
[104] 16
[114] 17
[124] 18
[134] 19
[144] bottom
Changing the item height, switching to measure
Creating element for 0
Creating element for 1
Creating element for 2
Creating element for 3
Creating element for 4
Creating element for 5
Creating element for 6
Creating element for 7
Creating element for 8
Creating element for 9
Creating element for 10
Creating element for 11
Creating element for 12
Creating element for 13
Creating element for 14
----list[length=20][height=84]----
[-56] top
[-56] 0
[-41] 1
[-26] 2
+[-11] 3
*[4] 4
*[19] 5
*[34] 6
*[49] 7
*[64] 8
+[79] 9
[94] 10
[109] 11
[124] 12
[139] 13
[154] 14
[169] bottom
Selecting 7
Selection changed from null to 7
----list[length=20][height=84]----
[-56] top
[-56] 0
[-41] 1
[-26] 2
+[-11] 3
*[4] 4
*[19] 5
*[34] 6
*[49] 7 (selected)
*[64] 8
+[79] 9
[94] 10
[109] 11
[124] 12
[139] 13
[154] 14
[169] bottom
Replacing 7 with 27
Creating element for 27
Selection changed from 7 to 10
----list[length=20][height=84]----
[-56] top
[-56] 0
[-41] 1
[-26] 2
+[-11] 3
*[4] 4
*[19] 5
*[34] 6
*[49] 27
*[64] 8
+[79] 9
[94] 10 (selected)
[109] 11
[124] 12
[139] 13
[154] 14
[169] bottom
Replacing 18, 19 with 28, 29
----list[length=20][height=84]----
[-56] top
[-56] 0
[-41] 1
[-26] 2
+[-11] 3
*[4] 4
*[19] 5
*[34] 6
*[49] 27
*[64] 8
+[79] 9
[94] 10 (selected)
[109] 11
[124] 12
[139] 13
[154] 14
[169] bottom
PageDown
Creating element for 15
Creating element for 16
Creating element for 17
Creating element for 28
Creating element for 29
Selection changed from 10 to 17
----list[length=20][height=84]----
[-186] top
[-96] 6
[-81] 27
[-66] 8
[-51] 9
[-36] 10
[-21] 11
+[-6] 12
*[9] 13
*[24] 14
*[39] 15
*[54] 16
*[69] 17 (selected)
[84] 28
[99] 29
[114] bottom
Replacing 1, 2, 3 with [31-43]
----list[length=30][height=84]----
[-336] top
[-96] 6
[-81] 27
[-66] 8
[-51] 9
[-36] 10
[-21] 11
+[-6] 12
*[9] 13
*[24] 14
*[39] 15
*[54] 16
*[69] 17 (selected)
[84] 28
[99] 29
[114] bottom
ArrowUp
Selection changed from 17 to 15
----list[length=30][height=84]----
[-336] top
[-96] 6
[-81] 27
[-66] 8
[-51] 9
[-36] 10
[-21] 11
+[-6] 12
*[9] 13
*[24] 14
*[39] 15 (selected)
*[54] 16
*[69] 17
[84] 28
[99] 29
[114] bottom
Selecting -1
Selection changed from 15 to null
----list[length=30][height=84]----
[-336] top
[-96] 6
[-81] 27
[-66] 8
[-51] 9
[-36] 10
[-21] 11
+[-6] 12
*[9] 13
*[24] 14
*[39] 15
*[54] 16
*[69] 17
[84] 28
[99] 29
[114] bottom
ArrowUp
Selection changed from null to 17
----list[length=30][height=84]----
[-336] top
[-96] 6
[-81] 27
[-66] 8
[-51] 9
[-36] 10
[-21] 11
+[-6] 12
*[9] 13
*[24] 14
*[39] 15
*[54] 16
*[69] 17 (selected)
[84] 28
[99] 29
[114] bottom
Selecting -1
Selection changed from 17 to null
----list[length=30][height=84]----
[-336] top
[-96] 6
[-81] 27
[-66] 8
[-51] 9
[-36] 10
[-21] 11
+[-6] 12
*[9] 13
*[24] 14
*[39] 15
*[54] 16
*[69] 17
[84] 28
[99] 29
[114] bottom
ArrowDown
Creating element for 41
Creating element for 40
Creating element for 39
Creating element for 38
Creating element for 37
Creating element for 36
Creating element for 35
Creating element for 34
Creating element for 33
Creating element for 32
Creating element for 31
Selection changed from null to 0
----list[length=30][height=84]----
[0] top
*[0] 0 (selected)
*[15] 31
*[30] 32
*[45] 33
*[60] 34
+[75] 35
[90] 36
[105] 37
[120] 38
[135] 39
[150] 40
[165] 41
[180] bottom
Selecting -1
Selection changed from 0 to null
----list[length=30][height=84]----
[0] top
*[0] 0
*[15] 31
*[30] 32
*[45] 33
*[60] 34
+[75] 35
[90] 36
[105] 37
[120] 38
[135] 39
[150] 40
[165] 41
[180] bottom
PageUp
Creating element for 42
Creating element for 43
Selection changed from null to 12
----list[length=30][height=84]----
[-261] top
[-96] 41
[-81] 42
[-66] 43
[-51] 4
[-36] 5
[-21] 6
+[-6] 27
*[9] 8
*[24] 9
*[39] 10
*[54] 11
*[69] 12 (selected)
[84] 13
[99] 14
[114] 15
[129] 16
[144] 17
[159] 28
[174] bottom
Replacing all but 29 with []
Selection changed from 12 to null
----list[length=1][height=84]----
[0] top
*[0] 29
*[15] bottom
ArrowDown
----list[length=1][height=84]----
[0] top
*[0] 29
*[15] bottom
TestRunner.addResult('Test ListControl rendering and selection for fixed height case.');
class Delegate {
constructor() {
this.height = 10;
}
createElementForItem(item) {
TestRunner.addResult('Creating element for ' + item);
var element = document.createElement('div');
element.style.height = this.height + 'px';
element.textContent = item;
return element;
}
heightForItem(item) {
return this.height;
}
isItemSelectable(item) {
return (item % 5 === 0) || (item % 5 === 2);
}
selectedItemChanged(from, to, fromElement, toElement) {
TestRunner.addResult('Selection changed from ' + from + ' to ' + to);
if (fromElement)
fromElement.classList.remove('selected');
if (toElement)
toElement.classList.add('selected');
}
}
var delegate = new Delegate();
var list = new UI.ListControl(delegate);
list.setHeightMode(UI.ListHeightMode.Fixed);
list.element.style.height = '73px';
UI.inspectorView.element.appendChild(list.element);
function dumpList()
{
var height = list.element.offsetHeight;
TestRunner.addResult(`----list[length=${list.length()}][height=${height}]----`);
for (var child of list.element.children) {
var offsetTop = child.getBoundingClientRect().top - list.element.getBoundingClientRect().top;
var offsetBottom = child.getBoundingClientRect().bottom - list.element.getBoundingClientRect().top;
var visible = (offsetBottom <= 0 || offsetTop >= height) ? ' ' :
(offsetTop >= 0 && offsetBottom <= height ? '*' : '+');
var selected = child.classList.contains('selected') ? ' (selected)' : '';
var text = child === list._topElement ? 'top' : (child === list._bottomElement ? 'bottom' : child.textContent);
TestRunner.addResult(`${visible}[${offsetTop}] ${text}${selected}`);
}
TestRunner.addResult('');
}
TestRunner.addResult('Adding 0, 1, 2');
list.replaceAllItems([0, 1, 2]);
dumpList();
TestRunner.addResult('Scrolling to 0');
list.scrollItemAtIndexIntoView(0);
dumpList();
TestRunner.addResult('Scrolling to 2');
list.scrollItemAtIndexIntoView(2);
dumpList();
TestRunner.addResult('ArrowDown');
list.onKeyDown(TestRunner.createKeyEvent('ArrowDown'));
dumpList();
TestRunner.addResult('Selecting 2');
list.selectItemAtIndex(2);
dumpList();
TestRunner.addResult('PageUp');
list.onKeyDown(TestRunner.createKeyEvent('PageUp'));
dumpList();
TestRunner.addResult('PageDown');
list.onKeyDown(TestRunner.createKeyEvent('PageDown'));
dumpList();
TestRunner.addResult('ArrowDown');
list.onKeyDown(TestRunner.createKeyEvent('ArrowDown'));
dumpList();
TestRunner.addResult('Replacing 0 with 5, 6, 7');
list.replaceItemsInRange(0, 1, [5, 6, 7]);
dumpList();
TestRunner.addResult('ArrowUp');
list.onKeyDown(TestRunner.createKeyEvent('ArrowUp'));
dumpList();
TestRunner.addResult('Pushing 10');
list.pushItem(10);
dumpList();
TestRunner.addResult('Selecting 10');
list.selectItemAtIndex(5);
dumpList();
TestRunner.addResult('Popping 10');
list.popItem();
dumpList();
TestRunner.addResult('Removing 2');
list.removeItemAtIndex(4);
dumpList();
TestRunner.addResult('Inserting 8');
list.insertItemAtIndex(1, 8);
dumpList();
TestRunner.addResult('Replacing with 0...20');
list.replaceAllItems([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]);
dumpList();
TestRunner.addResult('Resizing');
list.element.style.height = '84px';
list.viewportResized();
dumpList();
TestRunner.addResult('Scrolling to 19');
list.scrollItemAtIndexIntoView(19);
dumpList();
TestRunner.addResult('Scrolling to 5');
list.scrollItemAtIndexIntoView(5);
dumpList();
TestRunner.addResult('Scrolling to 12');
list.scrollItemAtIndexIntoView(12);
dumpList();
TestRunner.addResult('Scrolling to 13');
list.scrollItemAtIndexIntoView(13);
dumpList();
TestRunner.addResult('Changing the item height, switching to measure');
delegate.height = 15;
list.setHeightMode(UI.ListHeightMode.Measured);
dumpList();
TestRunner.addResult('Selecting 7');
list.selectItemAtIndex(7);
dumpList();
TestRunner.addResult('Replacing 7 with 27');
list.replaceItemsInRange(7, 8, [27]);
dumpList();
TestRunner.addResult('Replacing 18, 19 with 28, 29');
list.replaceItemsInRange(18, 20, [28, 29]);
dumpList();
TestRunner.addResult('PageDown');
list.onKeyDown(TestRunner.createKeyEvent('PageDown'));
dumpList();
TestRunner.addResult('Replacing 1, 2, 3 with [31-43]');
list.replaceItemsInRange(1, 4, [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]);
dumpList();
TestRunner.addResult('ArrowUp');
list.onKeyDown(TestRunner.createKeyEvent('ArrowUp'));
dumpList();
TestRunner.addResult('Selecting -1');
list.selectItemAtIndex(-1);
dumpList();
TestRunner.addResult('ArrowUp');
list.onKeyDown(TestRunner.createKeyEvent('ArrowUp'));
dumpList();
TestRunner.addResult('Selecting -1');
list.selectItemAtIndex(-1);
dumpList();
TestRunner.addResult('ArrowDown');
list.onKeyDown(TestRunner.createKeyEvent('ArrowDown'));
dumpList();
TestRunner.addResult('Selecting -1');
list.selectItemAtIndex(-1);
dumpList();
TestRunner.addResult('PageUp');
list.onKeyDown(TestRunner.createKeyEvent('PageUp'));
dumpList();
TestRunner.addResult('Replacing all but 29 with []');
list.replaceItemsInRange(0, 29, []);
dumpList();
TestRunner.addResult('ArrowDown');
list.onKeyDown(TestRunner.createKeyEvent('ArrowDown'));
dumpList();
TestRunner.completeTest();
This tests if the ViewportControl works properly.
First:0
Last:6
Active Items:11
First:26
Last:32
Active Items:14
First:27
Last:33
Active Items:15
First:27
Last:33
Active Items:15
First:30
Last:36
Active Items:14
First:82
Last:88
Active Items:14
First:83
Last:88
Active Items:11
TestRunner.addResult("This tests if the ViewportControl works properly.");
var items = [];
var heights = [];
for (var i = 0; i < 100; i++){
items[i] = document.createElement("div");
items[i].style.height = (heights[i] = (i % 4) ? 50 : 28) + "px";
items[i].textContent = i;
}
var viewport = new UI.ViewportControl({
fastItemHeight: i => heights[i],
itemCount: _ => items.length,
itemElement: i => items[i]
});
viewport.element.style.height = "300px";
UI.inspectorView.element.appendChild(viewport.element);
viewport.refresh();
dumpViewport();
viewport.forceScrollItemToBeFirst(26);
dumpViewport();
viewport.scrollItemIntoView(33);
dumpViewport();
viewport.scrollItemIntoView(30);
dumpViewport();
viewport.forceScrollItemToBeFirst(30);
dumpViewport();
viewport.forceScrollItemToBeLast(88);
dumpViewport();
for (var i = 0; i < 100; i++)
items[i].style.height = (heights[i] = (i % 2) ? 55 : 63) + "px";
viewport.refresh();
viewport.forceScrollItemToBeLast(88);
dumpViewport();
TestRunner.completeTest();
function dumpViewport()
{
TestRunner.addResult("First:" + viewport.firstVisibleIndex());
TestRunner.addResult("Last:" + viewport.lastVisibleIndex());
TestRunner.addResult("Active Items:" + viewport._innerElement.children.length);
TestRunner.addResult("");
}
\ No newline at end of file
......@@ -600,6 +600,7 @@ all_devtools_files = [
"front_end/ui/InspectorView.js",
"front_end/ui/inspectorViewTabbedPane.css",
"front_end/ui/KeyboardShortcut.js",
"front_end/ui/ListControl.js",
"front_end/ui/listWidget.css",
"front_end/ui/ListWidget.js",
"front_end/ui/module.json",
......@@ -645,7 +646,6 @@ all_devtools_files = [
"front_end/ui/UIUtils.js",
"front_end/ui/View.js",
"front_end/ui/viewContainers.css",
"front_end/ui/ViewportControl.js",
"front_end/ui/Widget.js",
"front_end/ui/ZoomManager.js",
"front_end/unit_test_runner.js",
......
......@@ -100,10 +100,12 @@ Sources.StyleSheetOutlineDialog = class extends UI.FilteredListWidget.Delegate {
/**
* @override
* @param {number} itemIndex
* @param {?number} itemIndex
* @param {string} promptValue
*/
selectItem(itemIndex, promptValue) {
if (itemIndex === null)
return;
var rule = this._rules[itemIndex];
var lineNumber = rule.lineNumber;
if (!isNaN(lineNumber) && lineNumber >= 0)
......
......@@ -118,10 +118,10 @@ TestRunner.loadLazyModules = function(lazyModules) {
/**
* @param {string} key
* @param {boolean} ctrlKey
* @param {boolean} altKey
* @param {boolean} shiftKey
* @param {boolean} metaKey
* @param {boolean=} ctrlKey
* @param {boolean=} altKey
* @param {boolean=} shiftKey
* @param {boolean=} metaKey
* @return {!KeyboardEvent}
*/
TestRunner.createKeyEvent = function(key, ctrlKey, altKey, shiftKey, metaKey) {
......@@ -129,10 +129,10 @@ TestRunner.createKeyEvent = function(key, ctrlKey, altKey, shiftKey, metaKey) {
key: key,
bubbles: true,
cancelable: true,
ctrlKey: ctrlKey,
altKey: altKey,
shiftKey: shiftKey,
metaKey: metaKey
ctrlKey: !!ctrlKey,
altKey: !!altKey,
shiftKey: !!shiftKey,
metaKey: !!metaKey
});
};
......
This diff is collapsed.
......@@ -998,14 +998,14 @@ UI.measurePreferredSize = function(element, containerElement) {
containerElement = containerElement || element.ownerDocument.body;
containerElement.appendChild(element);
element.positionAt(0, 0);
var result = new Size(element.offsetWidth, element.offsetHeight);
var result = element.getBoundingClientRect();
element.positionAt(undefined, undefined);
if (oldParent)
oldParent.insertBefore(element, oldNextSibling);
else
element.remove();
return result;
return new Size(result.width, result.height);
};
/**
......
// 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.
/**
* @unrestricted
*/
UI.ViewportControl = class {
/**
* @param {!UI.ViewportControl.Provider} provider
*/
constructor(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._update.bind(this), false);
this._itemCount = 0;
this._indexSymbol = Symbol('UI.ViewportControl._indexSymbol');
}
refresh() {
this._itemCount = this._provider.itemCount();
this._innerElement.removeChildren();
var height = 0;
this._cumulativeHeights = new Int32Array(this._itemCount);
for (var i = 0; i < this._itemCount; ++i) {
height += this._provider.fastItemHeight(i);
this._cumulativeHeights[i] = height;
}
this._innerElement.style.height = height + 'px';
this._update();
}
_update() {
if (!this._cumulativeHeights) {
this.refresh();
return;
}
var visibleHeight = this._visibleHeight();
var visibleFrom = this.element.scrollTop;
var activeHeight = visibleHeight * 2;
var firstActiveIndex = Math.max(
Array.prototype.lowerBound.call(this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visibleHeight) / 2),
0);
var lastActiveIndex = Math.min(
Array.prototype.lowerBound.call(
this._cumulativeHeights, visibleFrom + visibleHeight + (activeHeight - visibleHeight) / 2),
this._itemCount - 1);
var children = this._innerElement.children;
for (var i = children.length - 1; i >= 0; --i) {
var element = children[i];
if (element[this._indexSymbol] < firstActiveIndex || element[this._indexSymbol] > lastActiveIndex)
element.remove();
}
for (var i = firstActiveIndex; i <= lastActiveIndex; ++i)
this._insertElement(i);
}
/**
* @param {number} index
*/
_insertElement(index) {
var element = this._provider.itemElement(index);
if (!element || element.parentElement === this._innerElement)
return;
element.style.position = 'absolute';
element.style.top = (this._cumulativeHeights[index - 1] || 0) + 'px';
element.style.left = '0';
element.style.right = '0';
element[this._indexSymbol] = index;
this._innerElement.appendChild(element);
}
/**
* @return {number}
*/
firstVisibleIndex() {
return Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + 1), 0);
}
/**
* @return {number}
*/
lastVisibleIndex() {
return Math.min(
Array.prototype.lowerBound.call(this._cumulativeHeights, this.element.scrollTop + this._visibleHeight()),
this._itemCount);
}
/**
* @param {number} index
* @param {boolean=} makeLast
*/
scrollItemIntoView(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(index) {
this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0;
this._update();
}
/**
* @param {number} index
*/
forceScrollItemToBeLast(index) {
this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeight();
this._update();
}
/**
* @return {number}
*/
_visibleHeight() {
return this.element.offsetHeight;
}
};
/**
* @interface
*/
UI.ViewportControl.Provider = function() {};
UI.ViewportControl.Provider.prototype = {
/**
* @param {number} index
* @return {number}
*/
fastItemHeight(index) {
return 0;
},
/**
* @return {number}
*/
itemCount() {
return 0;
},
/**
* @param {number} index
* @return {?Element}
*/
itemElement(index) {
return null;
}
};
......@@ -30,6 +30,7 @@
"InplaceEditor.js",
"TextEditor.js",
"KeyboardShortcut.js",
"ListControl.js",
"ListWidget.js",
"Panel.js",
"Popover.js",
......@@ -50,7 +51,6 @@
"SuggestBox.js",
"TabbedPane.js",
"UIUtils.js",
"ViewportControl.js",
"ZoomManager.js"
],
"resources": [
......
......@@ -225,10 +225,12 @@ UI.CommandMenuDelegate = class extends UI.FilteredListWidget.Delegate {
/**
* @override
* @param {number} itemIndex
* @param {?number} itemIndex
* @param {string} promptValue
*/
selectItem(itemIndex, promptValue) {
if (itemIndex === null)
return;
this._commands[itemIndex].execute();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment