summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnna Koskinen <Ansku@users.noreply.github.com>2017-12-28 13:49:39 +0200
committerTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>2017-12-28 13:49:39 +0200
commitedc3b08defa815d9f65a9589c7a252ad99ea40fa (patch)
tree3306cc2c06cf492aabc874531820a3ce3204f1de
parentaa1371c84a5642c8b01603764291b746ff85f79d (diff)
downloadvaadin-framework-edc3b08defa815d9f65a9589c7a252ad99ea40fa.tar.gz
vaadin-framework-edc3b08defa815d9f65a9589c7a252ad99ea40fa.zip
Allow setting custom styles to DateField calendar date cells (#10305)
Fixes #10304
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java17
-rw-r--r--client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java3
-rw-r--r--client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java12
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractDateField.java68
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java6
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldElementUI.java13
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/datefield/DateTimeFieldElementUI.java15
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldElementTest.java36
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/datefield/DateTimeFieldElementTest.java37
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));