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 5 months 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
setText(previousValue);
}
updateTextFieldEnabled();
bufferedDateString = text.getText();
updateBufferedResolutions();
// send the Time changes with delayed rpc.
sendBufferedValuesWithDelay();
}

/**

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

@@ -290,6 +290,26 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel
bufferedResolutions.clear();
}

/**
* Puts the {@link #bufferedDateString} and {@link #bufferedResolutions}
* changes into the rpc queue and clears their values.
* <p>
* Note: The value will not be sent to the server immediately. It will be
* sent when a non {@link com.vaadin.shared.annotations.Delayed} annotated
* rpc is triggered.
* </p>
*
* @since
*/
public void sendBufferedValuesWithDelay() {
rpc.updateValueWithDelay(bufferedDateString,
bufferedResolutions.entrySet().stream().collect(
Collectors.toMap(entry -> entry.getKey().name(),
entry -> entry.getValue())));
bufferedDateString = null;
bufferedResolutions.clear();
}

/**
* Returns all available resolutions for the field in the ascending order
* (which is the same as order of enumeration ordinals).

+ 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 &
@Override
public void update(String newDateString,
Map<String, Integer> resolutions) {
valueUpdate(newDateString, resolutions);
}

@Override
public void updateValueWithDelay(String newDateString,
Map<String, Integer> resolutions) {
valueUpdate(newDateString, resolutions);
}

private void valueUpdate(String newDateString, Map<String, Integer> resolutions) {
Set<String> resolutionNames = getResolutions().map(Enum::name)
.collect(Collectors.toSet());
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;

import java.util.Map;

import com.vaadin.shared.annotations.Delayed;
import com.vaadin.shared.communication.ServerRpc;

/**
@@ -41,6 +42,27 @@ public interface AbstractDateFieldServerRpc extends ServerRpc {
*/
void update(String newDateString, Map<String, Integer> resolutions);

/**
* Updates the typed data string and resolution names and values with
* delayed rpc. The rpc will be sent by triggering another non
* {@link Delayed} annotated rpc.
*
* @since
*
* @param newDateString
* the value of the text field part. It enables analyzing invalid
* input on the server. {@code null} if the date was chosen with
* popup calendar or contains user-typed string
* @param resolutions
* map of time unit (resolution) name and value, the key is the
* resolution name e.g. "HOUR", "MINUTE", the value can be
* {@code null}. If the map is empty, that means the
* {@code newDateString} is invalid
*/
@Delayed(lastOnly = true)
void updateValueWithDelay(String newDateString,
Map<String, Integer> resolutions);

/**
* Indicates to the server that the client-side has lost focus.
*/

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

@@ -0,0 +1,54 @@
package com.vaadin.tests.components.datefield;

import com.vaadin.annotations.Widgetset;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.ValueChangeMode;
import com.vaadin.shared.ui.datefield.DateTimeResolution;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.tests.widgetset.TestingWidgetSet;
import com.vaadin.ui.Button;
import com.vaadin.ui.DateTimeField;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.TextField;
import com.vaadin.v7.shared.ui.datefield.Resolution;
import com.vaadin.v7.ui.DateField;

@Widgetset(TestingWidgetSet.NAME)
public class DateTimeFieldEventOrder extends AbstractTestUIWithLog {

@Override
protected void setup(VaadinRequest request) {

HorizontalLayout horizontalLayout = new HorizontalLayout();

DateTimeField dateField = new DateTimeField();
dateField.setResolution(DateTimeResolution.SECOND);
dateField.setId("test-field");
dateField.addValueChangeListener(
event -> log("DateTimeField value change event"));

Button button = new Button("test");
button.setId("test-button");
button.addClickListener(ev -> {
log("Button Click Event");
});

TextField tf = new TextField("test");
tf.setValueChangeMode(ValueChangeMode.BLUR);
tf.addValueChangeListener(event -> log("TextField value change event"));

DateField df = new DateField();
df.setResolution(Resolution.SECOND);
df.addValueChangeListener(event -> {
log("DateTimeField V7 value change event");
});

horizontalLayout.addComponents(dateField, button, tf, df);
addComponent(horizontalLayout);
}

@Override
protected Integer getTicketNumber() {
return 11316;
}
}

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

@@ -0,0 +1,39 @@
package com.vaadin.tests.components.datefield;

import java.util.List;

import org.junit.Test;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.DateTimeFieldElement;
import com.vaadin.tests.tb3.SingleBrowserTest;

import static org.junit.Assert.assertEquals;

public class DateTimeFieldEventOrderTest extends SingleBrowserTest {

@Test
public void testEventOrderIsCorrect() {
openTestURL();

DateTimeFieldElement field = $(DateTimeFieldElement.class).first();

field.openPopup();

List<WebElement> timeSelects = findElement(
By.className("v-datefield-calendarpanel-time"))
.findElements(By.tagName("select"));

new Select(timeSelects.get(0)).selectByValue("09");

findElement(By.id("test-button")).click();

assertEquals("The button click event should come second.",
"2. Button Click Event", getLogRow(0));
assertEquals("The value change event of DTF should come firstly.",
"1. DateTimeField value change event", getLogRow(1));

}
}

Loading…
Cancel
Save