* Using @Delayed annotation for DateField Rpc * Separate a rpc for handling the time change in DateTimeField * Add test case for wrong event ordertags/8.9.0.alpha1
@@ -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(); | |||
} | |||
/** |
@@ -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). |
@@ -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()); |
@@ -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. | |||
*/ |
@@ -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; | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |