From 66e68f1ef25804dabfb4b0e4cdd7d59c66522927 Mon Sep 17 00:00:00 2001 From: Olli Tietäväinen Date: Thu, 10 Aug 2017 15:57:27 +0300 Subject: Enable setting non-selected default value for DateField (#9745) Requested feature: allow setting DateField to a certain starting point without selecting a value. --- .../vaadin/client/ui/VAbstractPopupCalendar.java | 2 + .../main/java/com/vaadin/client/ui/VDateField.java | 39 +++++++ .../ui/datefield/AbstractDateFieldConnector.java | 20 ++++ .../main/java/com/vaadin/ui/AbstractDateField.java | 115 +++++++++++++++++---- .../datefield/DateFieldWithDefaultValue.java | 34 ++++++ .../datefield/DateFieldWithDefaultValueTest.java | 46 +++++++++ 6 files changed, 235 insertions(+), 21 deletions(-) create mode 100755 uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java create mode 100755 uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java diff --git a/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java b/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java index a8c356a07c..9d9862ceae 100644 --- a/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java +++ b/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java @@ -391,6 +391,8 @@ public abstract class VAbstractPopupCalendar> extends FlowPanel protected boolean enabled; + /** + * The date that is displayed the date field before a value is selected. If + * null, display the current date. + */ + private Date defaultDate = null; + /** * The date that is selected in the date field. Null if an invalid date is * specified. @@ -94,6 +100,18 @@ public abstract class VDateField> extends FlowPanel this.date = date; } + /** + * Set the default date to open popup when no date is selected. + * + * @param date + * default date to show as the initial (non-selected) value when + * opening a popup with no value selected + * @since 8.1.2 + */ + public void setDefaultDate(Date date) { + this.defaultDate = date; + } + /** * Set the current date using a map with date values. *

@@ -108,6 +126,27 @@ public abstract class VDateField> extends FlowPanel setCurrentDate(getDate(dateValues)); } + /** + * Set the default date using a map with date values. + * + * @see #setCurrentDate(Map) + * @param defaultValues + * @since 8.1.2 + */ + public void setDefaultDate(Map defaultValues) { + setDefaultDate(getDate(defaultValues)); + } + + /** + * Sets the default date when no date is selected. + * + * @return the default date + * @since 8.1.2 + */ + public Date getDefaultDate() { + return defaultDate; + } + public boolean isReadonly() { return readonly; } diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java index c851c13679..21e85773de 100644 --- a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java @@ -77,6 +77,7 @@ public abstract class AbstractDateFieldConnector> + getWidget().resolutionAsString(), true); getWidget().setCurrentDate(getTimeValues(uidl)); + getWidget().setDefaultDate(getDefaultValues(uidl)); } private void updateResolution(UIDL uidl) { @@ -98,6 +99,25 @@ public abstract class AbstractDateFieldConnector> : -1)); } + /** + * Returns the default date (when no date is selected) components as a map + * from Resolution to the corresponding value. + * + * @param uidl + * UIDL with corresponding variables + * @return default date component map + * @since 8.1.2 + */ + protected Map getDefaultValues(UIDL uidl) { + Stream resolutions = getWidget().getResolutions(); + R resolution = getWidget().getCurrentResolution(); + return resolutions.collect(Collectors.toMap(Function.identity(), + res -> (resolution.compareTo(res) <= 0) + ? uidl.getIntVariable("default-" + + getWidget().getResolutionVariable(res)) + : -1)); + } + @SuppressWarnings("unchecked") @Override public VDateField getWidget() { diff --git a/server/src/main/java/com/vaadin/ui/AbstractDateField.java b/server/src/main/java/com/vaadin/ui/AbstractDateField.java index 9d063af5ec..2ad976a7fe 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractDateField.java +++ b/server/src/main/java/com/vaadin/ui/AbstractDateField.java @@ -79,6 +79,12 @@ public abstract class AbstractDateField parsedDate = handleUnparsableDateString(dateString); - parsedDate.ifOk(v-> { + Result parsedDate = handleUnparsableDateString( + dateString); + parsedDate.ifOk(v -> { uiHasValidDateString = true; currentParseErrorMessage = null; - setValue(v,true); + setValue(v, true); }); if (parsedDate.isError()) { dateString = null; uiHasValidDateString = false; - currentParseErrorMessage = parsedDate.getMessage().orElse("Parsing error"); - setComponentError(new UserError(getParseErrorMessage())); - setValue(null,true); + currentParseErrorMessage = parsedDate.getMessage() + .orElse("Parsing error"); + setComponentError( + new UserError(getParseErrorMessage())); + setValue(null, true); } } else { uiHasValidDateString = true; @@ -272,16 +289,16 @@ public abstract class AbstractDateField variables, T oldDate) { + protected T reconstructDateFromFields(Map variables, + T oldDate) { Map calendarFields = new HashMap<>(); - for (R resolution : getResolutionsHigherOrEqualTo( - getResolution())) { + for (R resolution : getResolutionsHigherOrEqualTo(getResolution())) { // Only handle what the client is allowed to send. The same // resolutions that are painted String variableName = getResolutionVariable(resolution); @@ -290,7 +307,8 @@ public abstract class AbstractDateField= 0) { calendarFields.put(resolution, newValue); } else { - calendarFields.put(resolution, getDatePart(oldDate, resolution)); + calendarFields.put(resolution, + getDatePart(oldDate, resolution)); } } return buildDate(calendarFields); @@ -459,6 +477,57 @@ public abstract class AbstractDateField validator = getRangeValidator();// TODO move range check to internal validator? + RangeValidator validator = getRangeValidator();// TODO move range + // check to internal + // validator? ValidationResult result = validator.apply(value, new ValueContext(this, this)); if (result.isError()) { diff --git a/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java new file mode 100755 index 0000000000..e422fc991e --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java @@ -0,0 +1,34 @@ +package com.vaadin.tests.components.datefield; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +import com.vaadin.annotations.Widgetset; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.DateField; + +@Widgetset("com.vaadin.DefaultWidgetSet") +public class DateFieldWithDefaultValue extends AbstractTestUI { + + static final String DATEFIELD_HAS_DEFAULT = "hasdefault"; + + static final String DATEFIELD_REGULAR = "regular"; + + @Override + protected void setup(VaadinRequest request) { + DateField dfWithDefault = new DateField( + "Date field with default value 2010-10-01"); + dfWithDefault.setId(DATEFIELD_HAS_DEFAULT); + LocalDate defaultValue = LocalDate.parse("2010-10-01", + DateTimeFormatter.ISO_DATE); + dfWithDefault.setDefaultValue(defaultValue); + addComponent(dfWithDefault); + + DateField regularDF = new DateField("Regular datefield"); + regularDF.setId(DATEFIELD_REGULAR); + addComponent(regularDF); + + } + +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java new file mode 100755 index 0000000000..964b6bbecb --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java @@ -0,0 +1,46 @@ +package com.vaadin.tests.components.datefield; + +import static com.vaadin.tests.components.datefield.DateFieldWithDefaultValue.DATEFIELD_HAS_DEFAULT; +import static com.vaadin.tests.components.datefield.DateFieldWithDefaultValue.DATEFIELD_REGULAR; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.DateFieldElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class DateFieldWithDefaultValueTest extends MultiBrowserTest { + + @Test + public void testDateFieldDefaultValue() { + openTestURL(); + String datePickerId = DATEFIELD_HAS_DEFAULT; + getDateFieldElement(datePickerId).openPopup(); + WebElement monthSpanElement = getMonthSpanFromVisibleCalendarPanel(); + // Can't check for "October 2010", since IE11 translates October -> + // lokakuu + assert (monthSpanElement.getText().contains("2010")); + } + + @Test + public void testDateFieldWithNoDefault() { + openTestURL(); + String datePickerId = DATEFIELD_REGULAR; + getDateFieldElement(datePickerId).openPopup(); + WebElement monthSpanElement = getMonthSpanFromVisibleCalendarPanel(); + assert (!monthSpanElement.getText().contains("2010")); + } + + private WebElement getMonthSpanFromVisibleCalendarPanel() { + return getDriver() + .findElements( + By.cssSelector(".v-datefield-calendarpanel-month")) + .get(0); + } + + private DateFieldElement getDateFieldElement(String id) { + return $(DateFieldElement.class).id(id); + } + +} -- cgit v1.2.3