aboutsummaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorTarek Oraby <42799254+tarekoraby@users.noreply.github.com>2021-04-28 17:47:32 +0300
committerGitHub <noreply@github.com>2021-04-28 17:47:32 +0300
commit8c11cc6c9210e41b1e9981a04e56dd59d462da91 (patch)
tree9bcbfcf705f3217621144e2b951814401617139f /client
parent83ee08eae1a9997298713a6302dc929cc98dedfc (diff)
downloadvaadin-framework-8c11cc6c9210e41b1e9981a04e56dd59d462da91.tar.gz
vaadin-framework-8c11cc6c9210e41b1e9981a04e56dd59d462da91.zip
Fix validation in non-buffered Grid editor (#12281)
Handle possible race condition by disabling the editor's widget while awaiting validation from the server. Fixes #12270
Diffstat (limited to 'client')
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java12
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java71
-rw-r--r--client/src/main/java/com/vaadin/client/widget/grid/EditorHandler.java7
-rwxr-xr-xclient/src/main/java/com/vaadin/client/widgets/Grid.java9
4 files changed, 91 insertions, 8 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java
index 515bb17915..297a360f8b 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java
@@ -29,7 +29,6 @@ import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.widget.grid.EditorHandler;
import com.vaadin.client.widgets.Grid;
import com.vaadin.client.widgets.Grid.Column;
-import com.vaadin.shared.Range;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.editor.EditorClientRpc;
@@ -104,6 +103,12 @@ public class EditorConnector extends AbstractExtensionConnector {
getParent().getWidget().getEditor()
.setEditorError(errorMessage, errorColumns);
}
+
+ @Override
+ public void confirmValidity(boolean isValid) {
+ getParent().getWidget().getEditor().getEventHandler()
+ .confirmValidity(isValid);
+ }
});
}
@@ -131,6 +136,11 @@ public class EditorConnector extends AbstractExtensionConnector {
}
@Override
+ public void checkValidity() {
+ rpc.checkValidity();
+ }
+
+ @Override
public Widget getWidget(Column<?, JsonObject> column) {
String connId = getState().columnFields
.get(getParent().getColumnId(column));
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java b/client/src/main/java/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java
index 4580f16105..a76760af6e 100644
--- a/client/src/main/java/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java
+++ b/client/src/main/java/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java
@@ -15,6 +15,10 @@
*/
package com.vaadin.client.widget.grid;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
import com.google.gwt.core.client.Duration;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
@@ -30,8 +34,6 @@ import com.vaadin.client.widgets.Grid;
import com.vaadin.client.widgets.Grid.Editor;
import com.vaadin.client.widgets.Grid.EditorDomEvent;
-import java.util.List;
-
/**
* The default handler for Grid editor events. Offers several overridable
* protected methods for easier customization.
@@ -51,6 +53,7 @@ public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> {
private int lastTouchEventX = -1;
private int lastTouchEventY = -1;
private int lastTouchEventRow = -1;
+ private PendingEdit pendingEdit;
/**
* Returns whether the given event is a touch event that should open the
@@ -223,7 +226,16 @@ public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> {
}
}
- editRow(event, rowIndex + delta.rowDelta, colIndex);
+ int newRowIndex = rowIndex + delta.rowDelta;
+ if (newRowIndex != event.getRowIndex()) {
+ triggerValueChangeEvent(event);
+ // disable until validity check is done
+ setWidgetEnabled(event.getEditorWidget(), false);
+ event.getEditor().getHandler().checkValidity();
+ pendingEdit = new PendingEdit(event, newRowIndex, colIndex);
+ } else {
+ editRow(event, newRowIndex, colIndex);
+ }
}
return changed;
@@ -401,10 +413,6 @@ public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> {
// Limit colIndex between 0 and colCount - 1
colIndex = Math.max(0, Math.min(colCount - 1, colIndex));
- if (rowIndex != event.getRowIndex()) {
- triggerValueChangeEvent(event);
- }
-
event.getEditor().editRow(rowIndex, colIndex);
}
@@ -451,4 +459,53 @@ public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> {
return handled || swallowEvent;
}
+
+ @Override
+ public void confirmValidity(boolean isValid) {
+ if (pendingEdit == null) {
+ getLogger().log(Level.SEVERE,
+ "An editor's validation confirmation was received, but"
+ + " no pending edit object was found ");
+ return;
+ }
+ setWidgetEnabled(pendingEdit.pendingEvent.getEditorWidget(), true);
+ if (isValid) {
+ editRow(pendingEdit.pendingEvent, pendingEdit.pendingRowIndex,
+ pendingEdit.pendingColIndex);
+ } else {
+ pendingEdit.pendingEvent.getEditorWidget().getElement().focus();
+ }
+
+ pendingEdit = null;
+ }
+
+ private void setWidgetEnabled(Widget widget, boolean widgetEnabled) {
+ final ComponentConnector connector = Util.findConnectorFor(widget);
+ // only enable widget if it hasn't been disabled programmatically
+ if (connector.getState().enabled) {
+ connector.setWidgetEnabled(widgetEnabled);
+ }
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(DefaultEditorEventHandler.class.getName());
+ }
+
+ private final class PendingEdit {
+ private EditorDomEvent<T> pendingEvent;
+ private int pendingRowIndex;
+ private int pendingColIndex;
+
+ private PendingEdit(EditorDomEvent<T> pendingEvent, int pendingRowIndex,
+ int pendingColIndex) {
+ if (pendingEvent == null) {
+ throw new IllegalArgumentException(
+ "The pending event cannot be null");
+ }
+ this.pendingEvent = pendingEvent;
+ this.pendingRowIndex = pendingRowIndex;
+ this.pendingColIndex = pendingColIndex;
+ }
+
+ }
}
diff --git a/client/src/main/java/com/vaadin/client/widget/grid/EditorHandler.java b/client/src/main/java/com/vaadin/client/widget/grid/EditorHandler.java
index f603ebb5ea..958af5061b 100644
--- a/client/src/main/java/com/vaadin/client/widget/grid/EditorHandler.java
+++ b/client/src/main/java/com/vaadin/client/widget/grid/EditorHandler.java
@@ -189,4 +189,11 @@ public interface EditorHandler<T> {
* editable
*/
public Widget getWidget(Grid.Column<?, T> column);
+
+ /**
+ * Called by the editor's event handler when editing is shifting to a new
+ * row in order to check the validity of the binder's value.
+ *
+ */
+ public void checkValidity();
}
diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java
index c5fe79d260..6e0b9aaf59 100755
--- a/client/src/main/java/com/vaadin/client/widgets/Grid.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java
@@ -1416,6 +1416,15 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* done, false otherwise
*/
boolean handleEvent(EditorDomEvent<T> event);
+
+ /**
+ * Confirms the valid status of the binder so as to determine
+ * whether to allow pending navigation action.
+ *
+ * @param isValid
+ * {@code true} if the binder value is valid
+ */
+ void confirmValidity(boolean isValid);
}
protected enum State {