From acb889336f80227d609b194e56ac6ae3ead0d338 Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Thu, 8 Jan 2015 09:48:49 +0200 Subject: Redesign ComboBox filtering, highlighting and selection behaviour. (#15502, #9369) Changes: - When opening the popup, the first suggestion is always highlighted by default unless adding new items is allowed. - When filter matches currently selected item, that item will be highlighted instead of the first item. - Hitting enter or tab will always select the highlighted item. - Closing the suggestions list by clicking outside the list no longer selects an item to prevent accidental selections. Test changes: - Extended ComboBoxElement to help test filtering. - Updated and tweaked ComboBoxResetValueTest, ComboBoxIdenticalItemsTest and ComboboxScrollableWindowTest. - Added ComboBoxSelectingTest and ComboBoxSelectingWithNewItemsAllowedTest. - Updated some tests that were using keyboard navigation. Change-Id: Ia7745b624bdb0b1a1bb498157ebcb37bee219d76 --- client/src/com/vaadin/client/ui/VFilterSelect.java | 60 +++++++++------------- .../client/ui/combobox/ComboBoxConnector.java | 7 ++- 2 files changed, 30 insertions(+), 37 deletions(-) (limited to 'client') diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index c0575b1ea5..c99ed49c91 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -813,6 +813,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, clearItems(); final Iterator it = suggestions.iterator(); + boolean isFirstIteration = true; while (it.hasNext()) { final FilterSelectSuggestion s = it.next(); final MenuItem mi = new MenuItem(s.getDisplayString(), true, s); @@ -821,9 +822,21 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, WidgetUtil.sinkOnloadForImages(mi.getElement()); this.addItem(mi); - if (s == currentSuggestion) { + + // By default, first item on the list is always highlighted, + // unless adding new items is allowed. + if (isFirstIteration && !allowNewItem) { + selectItem(mi); + } + + // If the filter matches the current selection, highlight that + // instead of the first item. + if (tb.getText().equals(s.getReplacementString()) + && s == currentSuggestion) { selectItem(mi); } + + isFirstIteration = false; } } @@ -1178,8 +1191,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, /** For internal use only. May be removed or replaced in the future. */ public boolean updateSelectionWhenReponseIsReceived = false; - private boolean tabPressedWhenPopupOpen = false; - /** For internal use only. May be removed or replaced in the future. */ public boolean initDone = false; @@ -1421,8 +1432,10 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, return; } if (!filter.equals(lastFilter)) { - // we are on subsequent page and text has changed -> reset page - if ("".equals(filter)) { + // when filtering, let the server decide the page unless we've + // set the filter to empty and explicitly said that we want to see + // the results starting from page 0. + if ("".equals(filter) && page != 0) { // let server decide page = -1; } else { @@ -1437,7 +1450,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, lastFilter = filter; currentPage = page; - } /** For internal use only. May be removed or replaced in the future. */ @@ -1768,16 +1780,12 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, selectPrevPage(); event.stopPropagation(); break; - case KeyCodes.KEY_TAB: - tabPressedWhenPopupOpen = true; - filterOptions(currentPage); - // onBlur() takes care of the rest - break; case KeyCodes.KEY_ESCAPE: reset(); DOM.eventPreventDefault(DOM.eventGetCurrentEvent()); event.stopPropagation(); break; + case KeyCodes.KEY_TAB: case KeyCodes.KEY_ENTER: if (suggestionPopup.menu.getKeyboardSelectedItem() == null) { /* @@ -1785,17 +1793,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * text (causes popup to open) and then pressing enter. */ if (!allowNewItem) { - /* - * New items are not allowed: If there is only one - * suggestion, select that. If there is more than one - * suggestion Enter key should work as Escape key. Otherwise - * do nothing. - */ - if (currentSuggestions.size() == 1) { - onSuggestionSelected(currentSuggestions.get(0)); - } else if (currentSuggestions.size() > 1) { - reset(); - } + onSuggestionSelected(currentSuggestions + .get(suggestionPopup.menu.getSelectedIndex())); } else { // Handle addition of new items. suggestionPopup.menu.doSelectedItemAction(); @@ -1863,7 +1862,9 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, break; default: if (textInputEnabled) { - filterOptions(currentPage); + // when filtering, we always want to see the results on the + // first page first. + filterOptions(0); } break; } @@ -2069,19 +2070,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, focused = false; if (!readonly) { - // much of the TAB handling takes place here - if (tabPressedWhenPopupOpen) { - tabPressedWhenPopupOpen = false; - waitingForFilteringResponse = false; - suggestionPopup.menu.doSelectedItemAction(); - suggestionPopup.hide(); - } else if ((!suggestionPopup.isAttached() && waitingForFilteringResponse) - || suggestionPopup.isJustClosed()) { - // typing so fast the popup was never opened, or it's just - // closed - waitingForFilteringResponse = false; - suggestionPopup.menu.doSelectedItemAction(); - } if (selectedOptionKey == null) { setPromptingOn(); } else if (currentSuggestion != null) { diff --git a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java index 461181e18a..8757f46e71 100644 --- a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java +++ b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java @@ -166,7 +166,12 @@ public class ComboBoxConnector extends AbstractFieldConnector implements ) { String[] selectedKeys = uidl.getStringArrayVariable("selected"); - if (selectedKeys.length > 0) { + + // when filtering with empty filter, server sets the selected key + // to "", which we don't select here. Otherwise we won't be able to + // reset back to the item that was selected before filtering + // started. + if (selectedKeys.length > 0 && !selectedKeys[0].equals("")) { performSelection(selectedKeys[0]); } else { resetSelection(); -- cgit v1.2.3