diff options
author | Anna Koskinen <Ansku@users.noreply.github.com> | 2018-01-30 11:53:10 +0200 |
---|---|---|
committer | Ilia Motornyi <elmot@vaadin.com> | 2018-01-30 11:53:10 +0200 |
commit | 5b9d0b9175f9ce2f20d728db844b6fd03fea1461 (patch) | |
tree | 8d876b620e6d741fec8c76976f2dd96388561135 /client | |
parent | 9999cef04290eb3f025e2fad885905b5c34e62e1 (diff) | |
download | vaadin-framework-5b9d0b9175f9ce2f20d728db844b6fd03fea1461.tar.gz vaadin-framework-5b9d0b9175f9ce2f20d728db844b6fd03fea1461.zip |
Selection handling fix when adding new item to ComboBox. (#10445)
Fixes #10284
Diffstat (limited to 'client')
-rw-r--r-- | client/src/main/java/com/vaadin/client/ui/VComboBox.java | 39 | ||||
-rw-r--r-- | client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java | 88 |
2 files changed, 121 insertions, 6 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/VComboBox.java b/client/src/main/java/com/vaadin/client/ui/VComboBox.java index bd0c0809b4..863b56decc 100644 --- a/client/src/main/java/com/vaadin/client/ui/VComboBox.java +++ b/client/src/main/java/com/vaadin/client/ui/VComboBox.java @@ -1040,6 +1040,8 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, } }); + private String handledNewItem = null; + /** * Default constructor */ @@ -1134,7 +1136,11 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, public void actOnEnteredValueAfterFiltering(String enteredItemValue) { debug("VComboBox.SM: doPostFilterSelectedItemAction()"); final MenuItem item = getSelectedItem(); - + boolean handledOnServer = handledNewItem == enteredItemValue; + if (handledOnServer) { + // clear value to mark it as handled + handledNewItem = null; + } // check for exact match in menu int p = getItems().size(); if (p > 0) { @@ -1151,13 +1157,17 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, doItemAction(potentialExactMatch, true); } suggestionPopup.hide(); + lastNewItemString = null; + connector.clearNewItemHandlingIfMatch(enteredItemValue); return; } } } - if ("".equals(enteredItemValue) && nullSelectionAllowed) { + + if (!handledOnServer && "".equals(enteredItemValue) + && nullSelectionAllowed) { onNullSelected(); - } else if (allowNewItems) { + } else if (!handledOnServer && allowNewItems) { if (!enteredItemValue.equals(lastNewItemString)) { // Store last sent new item string to avoid double sends lastNewItemString = enteredItemValue; @@ -1182,6 +1192,10 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, } } suggestionPopup.hide(); + + if (handledOnServer || !allowNewItems) { + lastNewItemString = null; + } } private static final String SUBPART_PREFIX = "item"; @@ -1319,6 +1333,10 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, } } } + + public void markNewItemsHandled(String handledNewItem) { + this.handledNewItem = handledNewItem; + } } private String getSuggestionKey(MenuItem item) { @@ -1442,9 +1460,15 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, waitingForFilteringResponse = false; if (pendingUserInput != null) { + boolean pendingHandled = suggestionPopup.menu.handledNewItem == pendingUserInput; suggestionPopup.menu .actOnEnteredValueAfterFiltering(pendingUserInput); - pendingUserInput = null; + if (!allowNewItems || (pendingHandled + && suggestionPopup.menu.handledNewItem == null)) { + pendingUserInput = null; + } else { + waitingForFilteringResponse = true; + } } else if (popupOpenerClicked) { // make sure the current item is selected in the popup suggestionPopup.menu.highlightSelectedItem(); @@ -1474,6 +1498,10 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, filterOptions(0, value); } + public boolean isPending(String value) { + return value != null && value.equals(pendingUserInput); + } + /* * This method navigates to the proper item in the combobox page. This * should be executed after setSuggestions() method which is called from @@ -1541,7 +1569,6 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, */ public void serverReplyHandled() { popupOpenerClicked = false; - lastNewItemString = null; // if (!initDone) { // debug("VComboBox: init done, updating widths"); @@ -2542,7 +2569,7 @@ public class VComboBox extends Composite implements Field, KeyDownHandler, // Send new items when clicking out with the mouse. if (!readonly) { if (textInputEnabled && allowNewItems - && (currentSuggestion == null || tb.getText().equals( + && (currentSuggestion == null || !tb.getText().equals( currentSuggestion.getReplacementString()))) { dataReceivedHandler.reactOnInputWhenReady(tb.getText()); } else { diff --git a/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java b/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java index dd13e36205..334b630724 100644 --- a/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java @@ -35,6 +35,7 @@ import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.data.DataCommunicatorConstants; import com.vaadin.shared.data.selection.SelectionServerRpc; import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.combobox.ComboBoxClientRpc; import com.vaadin.shared.ui.combobox.ComboBoxConstants; import com.vaadin.shared.ui.combobox.ComboBoxServerRpc; import com.vaadin.shared.ui.combobox.ComboBoxState; @@ -55,10 +56,27 @@ public class ComboBoxConnector extends AbstractListingConnector private Registration dataChangeHandlerRegistration; + /** + * new item value that has been sent to server but selection handling hasn't + * been performed for it yet + */ + private String pendingNewItemValue = null; + @Override protected void init() { super.init(); getWidget().connector = this; + registerRpc(ComboBoxClientRpc.class, new ComboBoxClientRpc() { + @Override + public void newItemNotAdded(String itemValue) { + if (itemValue != null && itemValue.equals(pendingNewItemValue) + && isNewItemStillPending()) { + // handled but not added, perform (de-)selection handling + // immediately + completeNewItemHandling(); + } + } + }); } @Override @@ -158,6 +176,11 @@ public class ComboBoxConnector extends AbstractListingConnector * user entered string value for the new item */ public void sendNewItem(String itemValue) { + if (itemValue != null && !itemValue.equals(pendingNewItemValue)) { + // clear any previous handling as outdated + clearNewItemHandling(); + } + pendingNewItemValue = itemValue; rpc.createNewItem(itemValue); getDataReceivedHandler().clearPendingNavigation(); } @@ -181,6 +204,19 @@ public class ComboBoxConnector extends AbstractListingConnector } /** + * Confirm with the widget that the pending new item value is still pending. + * + * This method is for internal use only and may be removed in future + * versions. + * + * @return {@code true} if the value is still pending, {@code false} if + * there is no pending value or it doesn't match + */ + private boolean isNewItemStillPending() { + return getDataReceivedHandler().isPending(pendingNewItemValue); + } + + /** * Send a message to the server to request a page of items with the current * filter. * @@ -377,6 +413,58 @@ public class ComboBoxConnector extends AbstractListingConnector } } + /** + * If previous calls to refreshData haven't sorted out the selection yet, + * enforce it. + * + * This method is for internal use only and may be removed in future + * versions. + */ + private void completeNewItemHandling() { + // ensure the widget hasn't got a new selection in the meantime + if (isNewItemStillPending()) { + // mark new item for selection handling on the widget + getWidget().suggestionPopup.menu + .markNewItemsHandled(pendingNewItemValue); + // clear pending value + pendingNewItemValue = null; + // trigger the final selection handling + refreshData(); + } else { + clearNewItemHandling(); + } + } + + /** + * Clears the pending new item value if the widget's pending value no longer + * matches. + * + * This method is for internal use only and may be removed in future + * versions. + */ + private void clearNewItemHandling() { + // never clear pending value before it has been handled + if (!isNewItemStillPending()) { + pendingNewItemValue = null; + } + } + + /** + * Clears the new item handling variables if the given value matches the + * pending value. + * + * This method is for internal use only and may be removed in future + * versions. + * + * @param value + * already handled value + */ + public void clearNewItemHandlingIfMatch(String value) { + if (value != null && value.equals(pendingNewItemValue)) { + pendingNewItemValue = null; + } + } + private static final Logger LOGGER = Logger .getLogger(ComboBoxConnector.class.getName()); |