diff options
author | Adam Wagner <wbadam@users.noreply.github.com> | 2018-01-31 11:26:59 +0200 |
---|---|---|
committer | Ilia Motornyi <elmot@vaadin.com> | 2018-01-31 11:26:59 +0200 |
commit | 75b98bee62185c858a875393d50c3fa5e2fe64e7 (patch) | |
tree | 7bc8f3ab6360bf4c1f6758c49faddee0ea9900fb /client | |
parent | 5b9d0b9175f9ce2f20d728db844b6fd03fea1461 (diff) | |
download | vaadin-framework-75b98bee62185c858a875393d50c3fa5e2fe64e7.tar.gz vaadin-framework-75b98bee62185c858a875393d50c3fa5e2fe64e7.zip |
Add ARIA label support to DateField (#10538)
Fixes #10454
Diffstat (limited to 'client')
3 files changed, 177 insertions, 10 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 21ea8ba4c4..8810b26e30 100644 --- a/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java +++ b/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java @@ -25,6 +25,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.google.gwt.aria.client.Id; import com.google.gwt.aria.client.Roles; import com.google.gwt.aria.client.SelectedValue; import com.google.gwt.dom.client.Element; @@ -56,6 +57,7 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.BrowserInfo; import com.vaadin.client.DateTimeService; import com.vaadin.client.WidgetUtil; +import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.shared.util.SharedUtil; /** @@ -167,6 +169,14 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> private boolean initialRenderDone = false; + private String prevMonthAssistiveLabel; + + private String nextMonthAssistiveLabel; + + private String prevYearAssistiveLabel; + + private String nextYearAssistiveLabel; + /** * Represents a click handler for when a user selects a value by using the * mouse @@ -247,6 +257,13 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> if (curday.getDate().equals(date)) { curday.addStyleDependentName(CN_FOCUSED); focusedDay = curday; + + // Reference focused day from calendar panel + Roles.getGridRole() + .setAriaActivedescendantProperty( + getElement(), + Id.of(curday.getElement())); + return; } } @@ -490,8 +507,10 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> * * @param needsMonth * Should the month buttons be visible? + * @param needsBody + * indicates whether the calendar body is drawn */ - private void buildCalendarHeader(boolean needsMonth) { + private void buildCalendarHeader(boolean needsMonth, boolean needsBody) { getRowFormatter().addStyleName(0, parent.getStylePrimaryName() + "-calendarpanel-header"); @@ -501,16 +520,20 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> prevMonth.setHTML("‹"); prevMonth.setStyleName("v-button-prevmonth"); - prevMonth.setTabIndex(-1); - nextMonth = new VEventButton(); nextMonth.setHTML("›"); nextMonth.setStyleName("v-button-nextmonth"); - nextMonth.setTabIndex(-1); - setWidget(0, 3, nextMonth); setWidget(0, 1, prevMonth); + + Roles.getButtonRole().set(prevMonth.getElement()); + Roles.getButtonRole() + .setTabindexExtraAttribute(prevMonth.getElement(), -1); + + Roles.getButtonRole().set(nextMonth.getElement()); + Roles.getButtonRole() + .setTabindexExtraAttribute(nextMonth.getElement(), -1); } else if (prevMonth != null && !needsMonth) { // Remove month traverse buttons remove(prevMonth); @@ -525,18 +548,26 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> prevYear.setHTML("«"); prevYear.setStyleName("v-button-prevyear"); - prevYear.setTabIndex(-1); nextYear = new VEventButton(); nextYear.setHTML("»"); nextYear.setStyleName("v-button-nextyear"); - nextYear.setTabIndex(-1); setWidget(0, 0, prevYear); setWidget(0, 4, nextYear); + + Roles.getButtonRole().set(prevYear.getElement()); + Roles.getButtonRole() + .setTabindexExtraAttribute(prevYear.getElement(), -1); + + Roles.getButtonRole().set(nextYear.getElement()); + Roles.getButtonRole() + .setTabindexExtraAttribute(nextYear.getElement(), -1); } updateControlButtonRangeStyles(needsMonth); + updateAssistiveLabels(); + final String monthName = needsMonth ? getDateTimeService().getMonth(displayedMonth.getMonth()) : ""; @@ -553,6 +584,16 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> getFlexCellFormatter().setStyleName(0, 1, parent.getStylePrimaryName() + "-calendarpanel-prevmonth"); + // Set ID to be referenced from focused date or calendar panel + Element monthYearElement = getFlexCellFormatter().getElement(0, 2); + AriaHelper.ensureHasId(monthYearElement); + if (!needsBody) { + Roles.getGridRole().setAriaLabelledbyProperty(getElement(), + Id.of(monthYearElement)); + } else { + Roles.getGridRole().removeAriaLabelledbyProperty(getElement()); + } + setHTML(0, 2, "<span class=\"" + parent.getStylePrimaryName() + "-calendarpanel-month\">" + monthName + " " + year @@ -830,6 +871,17 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> Date dayDate = (Date) curr.clone(); Day day = new Day(dayDate); + // Set ID with prefix of the calendar panel's ID + day.getElement().setId(getElement().getId() + "-" + weekOfMonth + + "-" + dayOfWeek); + + // Set assistive label to read focused date and month/year + Roles.getButtonRole().set(day.getElement()); + Roles.getButtonRole() + .setAriaLabelledbyProperty(day.getElement(), + Id.of(day.getElement()), + Id.of(getFlexCellFormatter().getElement(0, 2))); + day.setStyleName(getDateField().getStylePrimaryName() + "-calendarpanel-day"); @@ -850,6 +902,11 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> focusedDay = day; if (hasFocus) { day.addStyleDependentName(CN_FOCUSED); + + // Reference focused day from calendar panel + Roles.getGridRole() + .setAriaActivedescendantProperty(getElement(), + Id.of(day.getElement())); } } if (curr.getMonth() != displayedMonth.getMonth()) { @@ -940,7 +997,7 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> final boolean needsMonth = !isYear(getResolution()); boolean needsBody = isBelowMonth(resolution); - buildCalendarHeader(needsMonth); + buildCalendarHeader(needsMonth, needsBody); clearCalendarBody(!needsBody); if (needsBody) { buildCalendarBody(); @@ -1229,7 +1286,6 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> event.getNativeEvent().getShiftKey())) { event.preventDefault(); } - } /** @@ -1345,7 +1401,7 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> renderCalendar(); return true; - } else if (keycode == getCloseKey() || keycode == KeyCodes.KEY_TAB) { + } else if (keycode == getCloseKey()) { onCancel(); // TODO fire close event @@ -2043,6 +2099,77 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> } } + /** + * Set assistive label for the previous year element. + * + * @param label + * the label to set + * @since + */ + public void setAssistiveLabelPreviousYear(String label) { + prevYearAssistiveLabel = label; + } + + /** + * Set assistive label for the next year element. + * + * @param label + * the label to set + * @since + */ + public void setAssistiveLabelNextYear(String label) { + nextYearAssistiveLabel = label; + } + + /** + * Set assistive label for the previous month element. + * + * @param label + * the label to set + * @since + */ + public void setAssistiveLabelPreviousMonth(String label) { + prevMonthAssistiveLabel = label; + } + + /** + * Set assistive label for the next month element. + * + * @param label + * the label to set + * @since + */ + public void setAssistiveLabelNextMonth(String label) { + nextMonthAssistiveLabel = label; + } + + /** + * Updates assistive labels of the navigation elements. + * + * @since + */ + public void updateAssistiveLabels() { + if (prevMonth != null) { + Roles.getButtonRole().setAriaLabelProperty(prevMonth.getElement(), + prevMonthAssistiveLabel); + } + + if (nextMonth != null) { + Roles.getButtonRole().setAriaLabelProperty(nextMonth.getElement(), + nextMonthAssistiveLabel); + } + + if (prevYear != null) { + Roles.getButtonRole().setAriaLabelProperty(prevYear.getElement(), + prevYearAssistiveLabel); + } + + if (nextYear != null) { + Roles.getButtonRole().setAriaLabelProperty(nextYear.getElement(), + nextYearAssistiveLabel); + } + } + private static Logger getLogger() { return Logger.getLogger(VAbstractCalendarPanel.class.getName()); } 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 4b52ee50f6..35d1c1c4d1 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 @@ -24,11 +24,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.vaadin.client.LocaleNotLoadedException; +import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractFieldConnector; +import com.vaadin.client.ui.VAbstractCalendarPanel; +import com.vaadin.client.ui.VAbstractPopupCalendar; import com.vaadin.client.ui.VDateField; import com.vaadin.shared.ui.datefield.AbstractDateFieldServerRpc; import com.vaadin.shared.ui.datefield.AbstractDateFieldState; +import com.vaadin.shared.ui.datefield.AbstractDateFieldState.AccessibleElement; public abstract class AbstractDateFieldConnector<R extends Enum<R>> extends AbstractFieldConnector { @@ -133,6 +137,36 @@ public abstract class AbstractDateFieldConnector<R extends Enum<R>> widget.setDefaultDate(getDefaultValues()); } + @OnStateChange("assistiveLabels") + private void updateAssistiveLabels() { + if (getWidget() instanceof VAbstractPopupCalendar) { + setAndUpdateAssistiveLabels( + ((VAbstractPopupCalendar) getWidget()).calendar); + } + } + + /** + * Sets assistive labels for the calendar panel's navigation elements, and + * updates these labels. + * + * @param calendar + * the calendar panel for which to set the assistive labels + * @since + */ + protected void setAndUpdateAssistiveLabels( + VAbstractCalendarPanel calendar) { + calendar.setAssistiveLabelPreviousMonth( + getState().assistiveLabels.get(AccessibleElement.PREVIOUS_MONTH)); + calendar.setAssistiveLabelNextMonth( + getState().assistiveLabels.get(AccessibleElement.NEXT_MONTH)); + calendar.setAssistiveLabelPreviousYear( + getState().assistiveLabels.get(AccessibleElement.PREVIOUS_YEAR)); + calendar.setAssistiveLabelNextYear( + getState().assistiveLabels.get(AccessibleElement.NEXT_YEAR)); + + calendar.updateAssistiveLabels(); + } + private static Logger getLogger() { return Logger.getLogger(AbstractDateFieldConnector.class.getName()); } 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 2492272111..51852de708 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 @@ -19,6 +19,7 @@ import java.util.Date; 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.VAbstractDateFieldCalendar; @@ -99,6 +100,11 @@ public abstract class AbstractInlineDateFieldConnector<PANEL extends VAbstractCa widget.calendarPanel.renderCalendar(); } + @OnStateChange("assistiveLabels") + private void updateAssistiveLabels() { + setAndUpdateAssistiveLabels(getWidget().calendarPanel); + } + @Override @SuppressWarnings("unchecked") public VAbstractDateFieldCalendar<PANEL, R> getWidget() { |