]> source.dussan.org Git - vaadin-framework.git/commitdiff
Allow setting custom styles to DateField calendar date cells (#10305)
authorAnna Koskinen <Ansku@users.noreply.github.com>
Thu, 28 Dec 2017 11:49:39 +0000 (13:49 +0200)
committerTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>
Thu, 28 Dec 2017 11:49:39 +0000 (13:49 +0200)
Fixes #10304

client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java
client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java
client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java
server/src/main/java/com/vaadin/ui/AbstractDateField.java
shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java
uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldElementUI.java
uitest/src/main/java/com/vaadin/tests/components/datefield/DateTimeFieldElementUI.java
uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldElementTest.java
uitest/src/test/java/com/vaadin/tests/components/datefield/DateTimeFieldElementTest.java

index f009f483e04c1d70d386c70608568aa5533454a3..fbfde9a3f1e61f8186631227c4d74107f1dc8d7b 100644 (file)
@@ -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);
index 54294b54aef7e6c76162254b6703edee12b3b6ef..24922721115c5e7a2348c463a3f357b612230221 100644 (file)
@@ -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();
     }
index c7cfdef71d5dc400e0666bcec93dd1eb2625f6b9..0702211ccb8746a5c929926f38329006eadbf32a 100644 (file)
@@ -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();
+        }
+    }
+
 }
index 5c176f3a5546b53f131d551f124960245321fc73..781848cb19f453455906d1790dfc1ee9d945cc98 100644 (file)
@@ -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;
+    }
 }
index 83544ec6bb0556394635d243437857da045913ec..7dab44803942f59cf0c8b7381fa720ce8aebfb2c 100644 (file)
@@ -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>();
+
 }
index 4a578de91fbbd7a790676cdb9205effec617964d..ecca4a22cbdeb3b3b34f10f0ac07a41ff781241f 100644 (file)
@@ -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
index f7f8e4473662d880a1f8299f11b15efbda0a97b4..1a16e94019d47f04ae28c1510c462daf65653f04 100644 (file)
@@ -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
index c56af7dafc9e3dfbf5e105a9389c580e69c8a3c2..4d784e788d1eff0b84811c7c94afc128756b0dd3 100644 (file)
@@ -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));
 
index 5719a9d97fca046cc1d719729356f85bc1c92194..14fc0f60f8e608ed5ac688e90132a31aba80693b 100644 (file)
@@ -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));