Index: third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js |
index 7cb25afe43d69abeea683fee6793bab7e874db82..246aa2c5467a1b78368bca1cfb1da60eb5ff235f 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js |
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js |
@@ -4,8 +4,8 @@ |
* found in the LICENSE file. |
*/ |
/** |
- * @implements {UI.ViewportControl.Provider} |
* @unrestricted |
+ * @implements {UI.ListDelegate} |
*/ |
UI.FilteredListWidget = class extends UI.VBox { |
/** |
@@ -35,9 +35,11 @@ UI.FilteredListWidget = class extends UI.VBox { |
this._progressElement = this.contentElement.createChild('div', 'filtered-list-widget-progress'); |
this._progressBarElement = this._progressElement.createChild('div', 'filtered-list-widget-progress-bar'); |
- this._filteredItems = []; |
- this._viewportControl = new UI.ViewportControl(this); |
- this._itemElementsContainer = this._viewportControl.element; |
+ this._rowHeight = 1; |
+ this._measuredHeight = false; |
+ /** @type {!UI.ListControl<number>} */ |
+ this._list = new UI.ListControl(this, false); |
+ this._itemElementsContainer = this._list.element; |
this._itemElementsContainer.classList.add('container'); |
this._itemElementsContainer.addEventListener('click', this._onClick.bind(this), false); |
this.contentElement.appendChild(this._itemElementsContainer); |
@@ -48,10 +50,6 @@ UI.FilteredListWidget = class extends UI.VBox { |
this._delegate.setRefreshCallback(this._itemsLoaded.bind(this)); |
this._itemsLoaded(); |
this._updateShowMatchingItems(); |
- this._viewportControl.refresh(); |
- |
- /** @typedef {!Array.<!Element>} */ |
- this._elements = []; |
} |
/** |
@@ -78,7 +76,6 @@ UI.FilteredListWidget = class extends UI.VBox { |
this._dialog.setPosition(undefined, 22); |
this.show(this._dialog.element); |
this._dialog.show(); |
- this._progressElementWidth = this._progressElement.offsetWidth; |
} |
/** |
@@ -92,6 +89,7 @@ UI.FilteredListWidget = class extends UI.VBox { |
* @override |
*/ |
willHide() { |
+ this._measuredHeight = false; |
this._delegate.dispose(); |
if (this._filterTimer) |
clearTimeout(this._filterTimer); |
@@ -104,14 +102,13 @@ UI.FilteredListWidget = class extends UI.VBox { |
event.preventDefault(); |
if (!this._delegate.itemCount()) |
return; |
- var selectedIndex = this._shouldShowMatchingItems() && this._selectedIndexInFiltered < this._filteredItems.length ? |
- this._filteredItems[this._selectedIndexInFiltered] : |
- null; |
+ var selectedIndexInDelegate = this._shouldShowMatchingItems() ? this._list.selectedItem() : null; |
// Detach dialog before allowing delegate to override focus. |
if (this._dialog) |
this._dialog.detach(); |
- this._delegate.selectItemWithQuery(selectedIndex, this._value()); |
+ if (selectedIndexInDelegate !== null) |
+ this._delegate.selectItemWithQuery(selectedIndexInDelegate, this._value()); |
} |
_itemsLoaded() { |
@@ -126,21 +123,61 @@ UI.FilteredListWidget = class extends UI.VBox { |
} |
/** |
- * @param {number} index |
+ * @override |
+ * @return {?number} |
+ */ |
+ fixedHeight() { |
+ return this._rowHeight; |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {number} item |
* @return {!Element} |
*/ |
- _createItemElement(index) { |
+ createElementForItem(item) { |
var itemElement = createElement('div'); |
itemElement.className = 'filtered-list-widget-item ' + (this._renderAsTwoRows ? 'two-rows' : 'one-row'); |
- itemElement._titleElement = itemElement.createChild('div', 'filtered-list-widget-title'); |
- itemElement._subtitleElement = itemElement.createChild('div', 'filtered-list-widget-subtitle'); |
- itemElement._subtitleElement.textContent = '\u200B'; |
- itemElement._index = index; |
- this._delegate.renderItem(index, this._value(), itemElement._titleElement, itemElement._subtitleElement); |
+ var titleElement = itemElement.createChild('div', 'filtered-list-widget-title'); |
+ var subtitleElement = itemElement.createChild('div', 'filtered-list-widget-subtitle'); |
+ subtitleElement.textContent = '\u200B'; |
+ this._delegate.renderItem(item, this._value(), titleElement, subtitleElement); |
return itemElement; |
} |
/** |
+ * @override |
+ * @param {number} item |
+ * @return {number} |
+ */ |
+ heightForItem(item) { |
+ return this._rowHeight; |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {number} item |
+ * @return {boolean} |
+ */ |
+ isItemSelectable(item) { |
+ return true; |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {?number} from |
+ * @param {?number} to |
+ * @param {?Element} fromElement |
+ * @param {?Element} toElement |
+ */ |
+ selectedItemChanged(from, to, fromElement, toElement) { |
+ if (fromElement) |
+ fromElement.classList.remove('selected'); |
+ if (toElement) |
+ toElement.classList.add('selected'); |
+ } |
+ |
+ /** |
* @param {string} query |
*/ |
setQuery(query) { |
@@ -167,8 +204,8 @@ UI.FilteredListWidget = class extends UI.VBox { |
clearTimeout(this._scoringTimer); |
delete this._scoringTimer; |
- if (this._refreshViewportWithCurrentResult) |
- this._refreshViewportWithCurrentResult(); |
+ if (this._refreshListWithCurrentResult) |
+ this._refreshListWithCurrentResult(); |
} |
this._progressBarElement.style.transform = 'scaleX(0)'; |
@@ -179,8 +216,6 @@ UI.FilteredListWidget = class extends UI.VBox { |
var filterRegex = query ? UI.FilteredListWidget.filterRegex(query) : null; |
- var oldSelectedAbsoluteIndex = |
- this._selectedIndexInFiltered && query ? this._filteredItems[this._selectedIndexInFiltered] : undefined; |
var filteredItems = []; |
var bestScores = []; |
@@ -237,8 +272,7 @@ UI.FilteredListWidget = class extends UI.VBox { |
} |
} |
- this._refreshViewportWithCurrentResult = |
- this._refreshViewport.bind(this, bestItems, overflowItems, filteredItems, oldSelectedAbsoluteIndex); |
+ this._refreshListWithCurrentResult = this._refreshList.bind(this, bestItems, overflowItems, filteredItems); |
// Process everything in chunks. |
if (i < this._delegate.itemCount()) { |
@@ -248,7 +282,7 @@ UI.FilteredListWidget = class extends UI.VBox { |
} |
this._progressBarElement.style.transform = 'scaleX(1)'; |
this._progressBarElement.classList.add('filtered-widget-progress-fade'); |
- this._refreshViewportWithCurrentResult(); |
+ this._refreshListWithCurrentResult(); |
} |
} |
@@ -256,22 +290,20 @@ UI.FilteredListWidget = class extends UI.VBox { |
* @param {!Array<number>} bestItems |
* @param {!Array<number>} overflowItems |
* @param {!Array<number>} filteredItems |
- * @param {number|undefined} selectedAbsoluteIndex |
*/ |
- _refreshViewport(bestItems, overflowItems, filteredItems, selectedAbsoluteIndex) { |
- delete this._refreshViewportWithCurrentResult; |
- this._filteredItems = bestItems.concat(overflowItems).concat(filteredItems); |
- |
- this._selectedIndexInFiltered = 0; |
- for (var i = 0; selectedAbsoluteIndex !== undefined && i < this._filteredItems.length; ++i) { |
- if (this._filteredItems[i] === selectedAbsoluteIndex) { |
- this._selectedIndexInFiltered = i; |
- break; |
- } |
+ _refreshList(bestItems, overflowItems, filteredItems) { |
+ delete this._refreshListWithCurrentResult; |
+ filteredItems = bestItems.concat(overflowItems).concat(filteredItems); |
+ |
+ if (!this._measuredHeight && filteredItems.length) { |
+ this._measuredHeight = true; |
+ this._rowHeight = |
+ UI.measurePreferredSize(this.createElementForItem(filteredItems[0]), this._itemElementsContainer).height; |
+ this._list.reset(this, false); |
} |
- this._elements = []; |
- this._viewportControl.refresh(); |
- this._updateSelection(this._selectedIndexInFiltered, false); |
+ this._list.replaceAllItems(filteredItems); |
+ if (filteredItems.length) |
+ this._list.selectItemAtIndex(0, true); |
this._itemsFilteredForTest(); |
} |
@@ -293,38 +325,15 @@ UI.FilteredListWidget = class extends UI.VBox { |
} |
/** |
- * @return {number} |
+ * @param {!Event} event |
*/ |
- _rowsPerViewport() { |
- return Math.floor(this._viewportControl.element.clientHeight / this._rowHeight); |
- } |
- |
_onKeyDown(event) { |
- var newSelectedIndex = this._selectedIndexInFiltered; |
+ if (this._list.onKeyDown(event)) { |
+ event.consume(true); |
+ return; |
+ } |
switch (event.keyCode) { |
- case UI.KeyboardShortcut.Keys.Down.code: |
- if (++newSelectedIndex >= this._filteredItems.length) |
- newSelectedIndex = 0; |
- this._updateSelection(newSelectedIndex, true); |
- event.consume(true); |
- break; |
- case UI.KeyboardShortcut.Keys.Up.code: |
- if (--newSelectedIndex < 0) |
- newSelectedIndex = this._filteredItems.length - 1; |
- this._updateSelection(newSelectedIndex, false); |
- event.consume(true); |
- break; |
- case UI.KeyboardShortcut.Keys.PageDown.code: |
- newSelectedIndex = Math.min(newSelectedIndex + this._rowsPerViewport(), this._filteredItems.length - 1); |
- this._updateSelection(newSelectedIndex, true); |
- event.consume(true); |
- break; |
- case UI.KeyboardShortcut.Keys.PageUp.code: |
- newSelectedIndex = Math.max(newSelectedIndex - this._rowsPerViewport(), 0); |
- this._updateSelection(newSelectedIndex, false); |
- event.consume(true); |
- break; |
case UI.KeyboardShortcut.Keys.Enter.code: |
this._onEnter(event); |
break; |
@@ -342,63 +351,18 @@ UI.FilteredListWidget = class extends UI.VBox { |
} |
/** |
- * @param {number} index |
- * @param {boolean} makeLast |
+ * @param {!Event} event |
*/ |
- _updateSelection(index, makeLast) { |
- if (!this._filteredItems.length) |
- return; |
- if (this._selectedElement) |
- this._selectedElement.classList.remove('selected'); |
- this._viewportControl.scrollItemIntoView(index, makeLast); |
- this._selectedIndexInFiltered = index; |
- this._selectedElement = this._elements[index]; |
- if (this._selectedElement) |
- this._selectedElement.classList.add('selected'); |
- } |
- |
_onClick(event) { |
- var itemElement = event.target.enclosingNodeOrSelfWithClass('filtered-list-widget-item'); |
- if (!itemElement) |
- return; |
- |
- // Detach dialog before allowing delegate to override focus. |
- if (this._dialog) |
- this._dialog.detach(); |
- this._delegate.selectItemWithQuery(itemElement._index, this._value()); |
- } |
- |
- /** |
- * @override |
- * @return {number} |
- */ |
- itemCount() { |
- return this._filteredItems.length; |
- } |
- |
- /** |
- * @override |
- * @param {number} index |
- * @return {number} |
- */ |
- fastItemHeight(index) { |
- if (!this._rowHeight) { |
- var delegateIndex = this._filteredItems[index]; |
- var element = this._createItemElement(delegateIndex); |
- this._rowHeight = UI.measurePreferredSize(element, this._itemElementsContainer).height; |
+ if (this._list.onClick(event)) { |
+ event.consume(true); |
+ // Detach dialog before allowing delegate to override focus. |
+ if (this._dialog) |
+ this._dialog.detach(); |
+ var selectedIndexInDelegate = this._list.selectedItem(); |
+ console.assert(selectedIndexInDelegate !== null); |
+ this._delegate.selectItemWithQuery(/** @type {number} */ (selectedIndexInDelegate), this._value()); |
} |
- return this._rowHeight; |
- } |
- |
- /** |
- * @override |
- * @param {number} index |
- * @return {!Element} |
- */ |
- itemElement(index) { |
- if (!this._elements[index]) |
- this._elements[index] = this._createItemElement(this._filteredItems[index]); |
- return this._elements[index]; |
} |
}; |