diff options
author | Anna Koskinen <Ansku@users.noreply.github.com> | 2017-12-28 13:49:39 +0200 |
---|---|---|
committer | Teemu Suo-Anttila <tsuoanttila@users.noreply.github.com> | 2017-12-28 13:49:39 +0200 |
commit | edc3b08defa815d9f65a9589c7a252ad99ea40fa (patch) | |
tree | 3306cc2c06cf492aabc874531820a3ce3204f1de | |
parent | aa1371c84a5642c8b01603764291b746ff85f79d (diff) | |
download | vaadin-framework-edc3b08defa815d9f65a9589c7a252ad99ea40fa.tar.gz vaadin-framework-edc3b08defa815d9f65a9589c7a252ad99ea40fa.zip |
Allow setting custom styles to DateField calendar date cells (#10305)
Fixes #10304
9 files changed, 207 insertions, 0 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java b/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java index f009f483e0..fbfde9a3f1 100644 --- a/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java +++ b/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java @@ -17,7 +17,9 @@ package com.vaadin.client.ui; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Predicate; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -44,6 +46,7 @@ import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.event.dom.client.MouseUpHandler; +import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Button; @@ -191,6 +194,9 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> onSubmit(); }; + private Map<String, String> dateStyles = new HashMap<String, String>(); + private DateTimeFormat df = DateTimeFormat.getFormat("yyyy-MM-dd"); + public VAbstractCalendarPanel() { getElement().setId(DOM.createUniqueId()); setStyleName(VDateField.CLASSNAME + "-calendarpanel"); @@ -446,6 +452,13 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> } } + public void setDateStyles(Map<String, String> dateStyles) { + this.dateStyles.clear(); + if (dateStyles != null) { + this.dateStyles.putAll(dateStyles); + } + } + private void clearCalendarBody(boolean remove) { if (!remove) { // Leave the cells in place but clear their contents @@ -833,6 +846,10 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> if (curr.getMonth() != displayedMonth.getMonth()) { day.addStyleDependentName(CN_OFFMONTH); } + String dayDateString = df.format(dayDate); + if (dateStyles.containsKey(dayDateString)) { + day.addStyleName(dateStyles.get(dayDateString)); + } days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, day); diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java index 54294b54ae..2492272111 100644 --- a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java @@ -46,6 +46,7 @@ public abstract class AbstractInlineDateFieldConnector<PANEL extends VAbstractCa * {@link #updateFromUIDL(UIDL, ApplicationConnection)} method as is and * customizing only listeners logic. */ + @SuppressWarnings("deprecation") protected void updateListeners() { VAbstractDateFieldCalendar<PANEL, R> widget = getWidget(); if (isResolutionMonthOrHigher()) { @@ -90,6 +91,7 @@ public abstract class AbstractInlineDateFieldConnector<PANEL extends VAbstractCa } else { widget.calendarPanel.setDate(null); } + widget.calendarPanel.setDateStyles(getState().dateStyles); updateListeners(); @@ -98,6 +100,7 @@ public abstract class AbstractInlineDateFieldConnector<PANEL extends VAbstractCa } @Override + @SuppressWarnings("unchecked") public VAbstractDateFieldCalendar<PANEL, R> getWidget() { return (VAbstractDateFieldCalendar<PANEL, R>) super.getWidget(); } diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java index c7cfdef71d..0702211ccb 100644 --- a/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java @@ -23,6 +23,7 @@ import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.user.client.ui.PopupPanel; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.UIDL; +import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.VAbstractCalendarPanel; import com.vaadin.client.ui.VAbstractCalendarPanel.FocusChangeListener; @@ -125,6 +126,7 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel< getWidget().setRangeStart(nullSafeDateClone(getState().rangeStart)); getWidget().setRangeEnd(nullSafeDateClone(getState().rangeEnd)); + getWidget().calendar.setDateStyles(getState().dateStyles); getWidget().calendar .setDateTimeService(getWidget().getDateTimeService()); getWidget().calendar @@ -194,4 +196,14 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel< getWidget().getStylePrimaryName() + "-popup" + styleName, add); } + @OnStateChange("dateStyles") + void dateStylesUpdated() { + VAbstractPopupCalendar<PANEL, R> widget = getWidget(); + widget.calendar.setDateStyles(getState().dateStyles); + // Update text field if locale already set + if (widget.getCurrentLocale() != null) { + widget.buildDate(); + } + } + } diff --git a/server/src/main/java/com/vaadin/ui/AbstractDateField.java b/server/src/main/java/com/vaadin/ui/AbstractDateField.java index 5c176f3a55..781848cb19 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractDateField.java +++ b/server/src/main/java/com/vaadin/ui/AbstractDateField.java @@ -27,6 +27,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -802,4 +803,71 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & } }; } + + /** + * <p> + * Sets a custom style name for the given date's calendar cell. Setting the + * style name will override any previous style names that have been set for + * that date, but can contain several actual style names separated by space. + * Setting the custom style name {@code null} will only remove the previous + * custom style name. + * </p> + * <p> + * This logic is entirely separate from {@link #setStyleName(String)} + * </p> + * <p> + * Usage examples: <br> + * {@code setDateStyle(LocalDate.now(), "teststyle");} <br> + * {@code setDateStyle(LocalDate.now(), "teststyle1 teststyle2");} + * </p> + * + * @param date + * which date cell to modify + * @param styleName + * the custom style name(s) for given date, {@code null} to clear + * custom style name(s) + */ + public void setDateStyle(LocalDate date, String styleName) { + if (date != null) { + if (styleName != null) { + getState().dateStyles.put(date.toString(), styleName); + } else { + getState().dateStyles.remove(date.toString()); + } + } + } + + /** + * Returns the custom style name that corresponds with the given date's + * calendar cell. + * + * @param date + * which date cell's custom style name(s) to return + * @return the corresponding style name(s), if any, {@code null} otherwise + * + * @see {@link #setDateStyle(LocalDate, String)} + */ + public String getDateStyle(LocalDate date) { + if (date == null) { + return null; + } + return getState(false).dateStyles.get(date.toString()); + } + + /** + * Returns a map from dates to custom style names in each date's calendar + * cell. + * + * @return map from dates to custom style names in each date's calendar cell + * + * @see {@link #setDateStyle(LocalDate, String)} + */ + public Map<LocalDate, String> getDateStyles() { + HashMap<LocalDate, String> hashMap = new HashMap<>(); + for (Entry<String, String> entry : getState(false).dateStyles + .entrySet()) { + hashMap.put(LocalDate.parse(entry.getKey()), entry.getValue()); + } + return hashMap; + } } diff --git a/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java index 83544ec6bb..7dab448039 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java +++ b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java @@ -106,4 +106,10 @@ public class AbstractDateFieldState extends AbstractFieldState { */ public boolean parsable = true; + /** + * Map of custom style names that correspond with given dates. Each date + * must be set to midnight for the handling logic to work correctly. + */ + public Map<String, String> dateStyles = new HashMap<String, String>(); + } diff --git a/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldElementUI.java b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldElementUI.java index 4a578de91f..ecca4a22cb 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldElementUI.java +++ b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldElementUI.java @@ -6,6 +6,7 @@ import java.util.Locale; import com.vaadin.annotations.Widgetset; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractReindeerTestUIWithLog; +import com.vaadin.ui.Button; import com.vaadin.ui.DateField; import com.vaadin.ui.InlineDateField; @@ -18,6 +19,11 @@ public class DateFieldElementUI extends AbstractReindeerTestUIWithLog { @Override protected void setup(VaadinRequest request) { + getPage().getStyles() + .add(".v-inline-datefield .teststyle { background: yellow; }"); + getPage().getStyles() + .add(".v-datefield-popup .teststyle { background: yellow; }"); + log.setNumberLogRows(false); DateField df = new DateField(); df.addValueChangeListener(event -> log( @@ -42,6 +48,13 @@ public class DateFieldElementUI extends AbstractReindeerTestUIWithLog { usDatefield.addValueChangeListener( event -> log("US date field value set to " + event.getValue())); addComponent(usDatefield); + + addComponent(new Button("Add date styles", e -> { + inlineDateField.setDateStyle(LocalDate.now(), "teststyle"); + finnishDatefield.setDateStyle(LocalDate.of(2017, 12, 1), + "teststyle"); + usDatefield.setDateStyle(LocalDate.of(2017, 12, 1), "teststyle"); + })); } @Override diff --git a/uitest/src/main/java/com/vaadin/tests/components/datefield/DateTimeFieldElementUI.java b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateTimeFieldElementUI.java index f7f8e44736..1a16e94019 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/datefield/DateTimeFieldElementUI.java +++ b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateTimeFieldElementUI.java @@ -1,11 +1,13 @@ package com.vaadin.tests.components.datefield; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Locale; import com.vaadin.annotations.Widgetset; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractReindeerTestUIWithLog; +import com.vaadin.ui.Button; import com.vaadin.ui.DateTimeField; import com.vaadin.ui.InlineDateTimeField; @@ -18,6 +20,11 @@ public class DateTimeFieldElementUI extends AbstractReindeerTestUIWithLog { @Override protected void setup(VaadinRequest request) { + getPage().getStyles() + .add(".v-inline-datefield .teststyle { background: yellow; }"); + getPage().getStyles() + .add(".v-datefield-popup .teststyle { background: yellow; }"); + log.setNumberLogRows(false); DateTimeField df = new DateTimeField(); df.addValueChangeListener(event -> log( @@ -42,6 +49,14 @@ public class DateTimeFieldElementUI extends AbstractReindeerTestUIWithLog { usDateTimeField.addValueChangeListener( event -> log("US date field value set to " + event.getValue())); addComponent(usDateTimeField); + + addComponent(new Button("Add date styles", e -> { + inlineDateTimeField.setDateStyle(LocalDate.now(), "teststyle"); + finnishDateTimeField.setDateStyle(LocalDate.of(2017, 12, 1), + "teststyle"); + usDateTimeField.setDateStyle(LocalDate.of(2017, 12, 1), + "teststyle"); + })); } @Override diff --git a/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldElementTest.java b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldElementTest.java index c56af7dafc..4d784e788d 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldElementTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldElementTest.java @@ -4,11 +4,15 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.time.LocalDate; import org.junit.Test; +import org.openqa.selenium.WebElement; +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.DateFieldElement; import com.vaadin.testbench.elements.InlineDateFieldElement; import com.vaadin.tests.tb3.SingleBrowserTest; @@ -52,6 +56,38 @@ public class DateFieldElementTest extends SingleBrowserTest { DateFieldElementUI.ANOTHER_TEST_DATE_TIME); } + @Test + public void testDateStyles() { + openTestURL(); + assertTrue(findElements(By.className("teststyle")).isEmpty()); + + $(ButtonElement.class).first().click(); + + WebElement styledDateCell = $(InlineDateFieldElement.class).first() + .findElement(By.className("teststyle")); + assertEquals(String.valueOf(LocalDate.now().getDayOfMonth()), + styledDateCell.getText()); + + DateFieldElement fi = $(DateFieldElement.class).id("fi"); + fi.openPopup(); + waitForElementPresent(By.className("v-datefield-popup")); + WebElement popup = findElement( + com.vaadin.testbench.By.className("v-datefield-popup")); + styledDateCell = popup.findElement(By.className("teststyle")); + assertEquals("1", styledDateCell.getText()); + + styledDateCell.click(); // close popup + waitForElementNotPresent(By.className("v-datefield-popup")); + + DateFieldElement us = $(DateFieldElement.class).id("us"); + us.openPopup(); + waitForElementPresent(By.className("v-datefield-popup")); + popup = findElement( + com.vaadin.testbench.By.className("v-datefield-popup")); + styledDateCell = popup.findElement(By.className("teststyle")); + assertEquals("1", styledDateCell.getText()); + } + private void assertServerValue(String id, LocalDate testDateTime) { assertEquals(id + " value set to " + testDateTime, getLogRow(0)); diff --git a/uitest/src/test/java/com/vaadin/tests/components/datefield/DateTimeFieldElementTest.java b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateTimeFieldElementTest.java index 5719a9d97f..14fc0f60f8 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/datefield/DateTimeFieldElementTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateTimeFieldElementTest.java @@ -4,11 +4,15 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.time.LocalDateTime; import org.junit.Test; +import org.openqa.selenium.WebElement; +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.DateTimeFieldElement; import com.vaadin.testbench.elements.InlineDateTimeFieldElement; import com.vaadin.tests.tb3.SingleBrowserTest; @@ -55,6 +59,39 @@ public class DateTimeFieldElementTest extends SingleBrowserTest { DateTimeFieldElementUI.ANOTHER_TEST_DATE_TIME); } + @Test + public void testDateStyles() { + openTestURL(); + assertTrue(findElements(By.className("teststyle")).isEmpty()); + + // add styles + $(ButtonElement.class).first().click(); + + WebElement styledDateCell = $(InlineDateTimeFieldElement.class).first() + .findElement(By.className("teststyle")); + assertEquals(String.valueOf(LocalDateTime.now().getDayOfMonth()), + styledDateCell.getText()); + + DateTimeFieldElement fi = $(DateTimeFieldElement.class).id("fi"); + fi.openPopup(); + waitForElementPresent(By.className("v-datefield-popup")); + WebElement popup = findElement( + com.vaadin.testbench.By.className("v-datefield-popup")); + styledDateCell = popup.findElement(By.className("teststyle")); + assertEquals("1", styledDateCell.getText()); + + styledDateCell.click(); // close popup + waitForElementNotPresent(By.className("v-datefield-popup")); + + DateTimeFieldElement us = $(DateTimeFieldElement.class).id("us"); + us.openPopup(); + waitForElementPresent(By.className("v-datefield-popup")); + popup = findElement( + com.vaadin.testbench.By.className("v-datefield-popup")); + styledDateCell = popup.findElement(By.className("teststyle")); + assertEquals("1", styledDateCell.getText()); + } + private void assertServerValue(String id, LocalDateTime testDateTime) { assertEquals(id + " value set to " + testDateTime, getLogRow(0)); |