Browse Source

Separates a rpc for handling the client event order in DateTimeField (#11574)

* Using @Delayed annotation for DateField Rpc

* Separate a rpc for handling the time change in DateTimeField

* Add test case for wrong event order
tags/8.9.0.alpha1
Zhe Sun 1 month ago
parent
commit
7bda912a77
No account linked to committer's email address

+ 4
- 0
client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java View File

@@ -496,6 +496,10 @@ public abstract class VAbstractPopupCalendar<PANEL extends VAbstractCalendarPane
496 496
             setText(previousValue);
497 497
         }
498 498
         updateTextFieldEnabled();
499
+        bufferedDateString = text.getText();
500
+        updateBufferedResolutions();
501
+        // send the Time changes with delayed rpc.
502
+        sendBufferedValuesWithDelay();
499 503
     }
500 504
 
501 505
     /**

+ 20
- 0
client/src/main/java/com/vaadin/client/ui/VDateField.java View File

@@ -291,6 +291,26 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel
291 291
     }
292 292
 
293 293
     /**
294
+     * Puts the {@link #bufferedDateString} and {@link #bufferedResolutions}
295
+     * changes into the rpc queue and clears their values.
296
+     * <p>
297
+     * Note: The value will not be sent to the server immediately. It will be
298
+     * sent when a non {@link com.vaadin.shared.annotations.Delayed} annotated
299
+     * rpc is triggered.
300
+     * </p>
301
+     *
302
+     * @since
303
+     */
304
+    public void sendBufferedValuesWithDelay() {
305
+        rpc.updateValueWithDelay(bufferedDateString,
306
+                bufferedResolutions.entrySet().stream().collect(
307
+                        Collectors.toMap(entry -> entry.getKey().name(),
308
+                                entry -> entry.getValue())));
309
+        bufferedDateString = null;
310
+        bufferedResolutions.clear();
311
+    }
312
+
313
+    /**
294 314
      * Returns all available resolutions for the field in the ascending order
295 315
      * (which is the same as order of enumeration ordinals).
296 316
      * <p>

+ 10
- 0
server/src/main/java/com/vaadin/ui/AbstractDateField.java View File

@@ -88,6 +88,16 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
88 88
         @Override
89 89
         public void update(String newDateString,
90 90
                 Map<String, Integer> resolutions) {
91
+            valueUpdate(newDateString, resolutions);
92
+        }
93
+
94
+        @Override
95
+        public void updateValueWithDelay(String newDateString,
96
+                                         Map<String, Integer> resolutions) {
97
+            valueUpdate(newDateString, resolutions);
98
+        }
99
+
100
+        private void valueUpdate(String newDateString, Map<String, Integer> resolutions) {
91 101
             Set<String> resolutionNames = getResolutions().map(Enum::name)
92 102
                     .collect(Collectors.toSet());
93 103
             resolutionNames.retainAll(resolutions.keySet());

+ 22
- 0
shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldServerRpc.java View File

@@ -17,6 +17,7 @@ package com.vaadin.shared.ui.datefield;
17 17
 
18 18
 import java.util.Map;
19 19
 
20
+import com.vaadin.shared.annotations.Delayed;
20 21
 import com.vaadin.shared.communication.ServerRpc;
21 22
 
22 23
 /**
@@ -42,6 +43,27 @@ public interface AbstractDateFieldServerRpc extends ServerRpc {
42 43
     void update(String newDateString, Map<String, Integer> resolutions);
43 44
 
44 45
     /**
46
+     * Updates the typed data string and resolution names and values with
47
+     * delayed rpc. The rpc will be sent by triggering another non
48
+     * {@link Delayed} annotated rpc.
49
+     *
50
+     * @since
51
+     *
52
+     * @param newDateString
53
+     *            the value of the text field part. It enables analyzing invalid
54
+     *            input on the server. {@code null} if the date was chosen with
55
+     *            popup calendar or contains user-typed string
56
+     * @param resolutions
57
+     *            map of time unit (resolution) name and value, the key is the
58
+     *            resolution name e.g. "HOUR", "MINUTE", the value can be
59
+     *            {@code null}. If the map is empty, that means the
60
+     *            {@code newDateString} is invalid
61
+     */
62
+    @Delayed(lastOnly = true)
63
+    void updateValueWithDelay(String newDateString,
64
+            Map<String, Integer> resolutions);
65
+
66
+    /**
45 67
      * Indicates to the server that the client-side has lost focus.
46 68
      */
47 69
     void blur();

+ 54
- 0
uitest/src/main/java/com/vaadin/tests/components/datefield/DateTimeFieldEventOrder.java View File

@@ -0,0 +1,54 @@
1
+package com.vaadin.tests.components.datefield;
2
+
3
+import com.vaadin.annotations.Widgetset;
4
+import com.vaadin.server.VaadinRequest;
5
+import com.vaadin.shared.ui.ValueChangeMode;
6
+import com.vaadin.shared.ui.datefield.DateTimeResolution;
7
+import com.vaadin.tests.components.AbstractTestUIWithLog;
8
+import com.vaadin.tests.widgetset.TestingWidgetSet;
9
+import com.vaadin.ui.Button;
10
+import com.vaadin.ui.DateTimeField;
11
+import com.vaadin.ui.HorizontalLayout;
12
+import com.vaadin.ui.TextField;
13
+import com.vaadin.v7.shared.ui.datefield.Resolution;
14
+import com.vaadin.v7.ui.DateField;
15
+
16
+@Widgetset(TestingWidgetSet.NAME)
17
+public class DateTimeFieldEventOrder extends AbstractTestUIWithLog {
18
+
19
+    @Override
20
+    protected void setup(VaadinRequest request) {
21
+
22
+        HorizontalLayout horizontalLayout = new HorizontalLayout();
23
+
24
+        DateTimeField dateField = new DateTimeField();
25
+        dateField.setResolution(DateTimeResolution.SECOND);
26
+        dateField.setId("test-field");
27
+        dateField.addValueChangeListener(
28
+                event -> log("DateTimeField value change event"));
29
+
30
+        Button button = new Button("test");
31
+        button.setId("test-button");
32
+        button.addClickListener(ev -> {
33
+            log("Button Click Event");
34
+        });
35
+
36
+        TextField tf = new TextField("test");
37
+        tf.setValueChangeMode(ValueChangeMode.BLUR);
38
+        tf.addValueChangeListener(event -> log("TextField value change event"));
39
+
40
+        DateField df = new DateField();
41
+        df.setResolution(Resolution.SECOND);
42
+        df.addValueChangeListener(event -> {
43
+            log("DateTimeField V7 value change event");
44
+        });
45
+
46
+        horizontalLayout.addComponents(dateField, button, tf, df);
47
+        addComponent(horizontalLayout);
48
+    }
49
+
50
+    @Override
51
+    protected Integer getTicketNumber() {
52
+        return 11316;
53
+    }
54
+}

+ 39
- 0
uitest/src/test/java/com/vaadin/tests/components/datefield/DateTimeFieldEventOrderTest.java View File

@@ -0,0 +1,39 @@
1
+package com.vaadin.tests.components.datefield;
2
+
3
+import java.util.List;
4
+
5
+import org.junit.Test;
6
+import org.openqa.selenium.WebElement;
7
+import org.openqa.selenium.support.ui.Select;
8
+
9
+import com.vaadin.testbench.By;
10
+import com.vaadin.testbench.elements.DateTimeFieldElement;
11
+import com.vaadin.tests.tb3.SingleBrowserTest;
12
+
13
+import static org.junit.Assert.assertEquals;
14
+
15
+public class DateTimeFieldEventOrderTest extends SingleBrowserTest {
16
+
17
+    @Test
18
+    public void testEventOrderIsCorrect() {
19
+        openTestURL();
20
+
21
+        DateTimeFieldElement field = $(DateTimeFieldElement.class).first();
22
+
23
+        field.openPopup();
24
+
25
+        List<WebElement> timeSelects = findElement(
26
+                By.className("v-datefield-calendarpanel-time"))
27
+                        .findElements(By.tagName("select"));
28
+
29
+        new Select(timeSelects.get(0)).selectByValue("09");
30
+
31
+        findElement(By.id("test-button")).click();
32
+
33
+        assertEquals("The button click event should come second.",
34
+                "2. Button Click Event", getLogRow(0));
35
+        assertEquals("The value change event of DTF should come firstly.",
36
+                "1. DateTimeField value change event", getLogRow(1));
37
+
38
+    }
39
+}

Loading…
Cancel
Save