summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorAnna Koskinen <Ansku@users.noreply.github.com>2018-01-30 11:53:10 +0200
committerIlia Motornyi <elmot@vaadin.com>2018-01-30 11:53:10 +0200
commit5b9d0b9175f9ce2f20d728db844b6fd03fea1461 (patch)
tree8d876b620e6d741fec8c76976f2dd96388561135 /client
parent9999cef04290eb3f025e2fad885905b5c34e62e1 (diff)
downloadvaadin-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.java39
-rw-r--r--client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java88
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());