diff options
author | michaelvogt <michael@vaadin.com> | 2013-03-25 15:46:58 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-04-02 14:10:58 +0000 |
commit | 4c5c1e0cfeff1c7118ab3fffe4d45e0f1966d470 (patch) | |
tree | 70440f782721af726d2fa930d7b9f6ed8e84bffe | |
parent | d454bf66d960d23908f427f86b4979912c476ec1 (diff) | |
download | vaadin-framework-4c5c1e0cfeff1c7118ab3fffe4d45e0f1966d470.tar.gz vaadin-framework-4c5c1e0cfeff1c7118ab3fffe4d45e0f1966d470.zip |
WAI-ARIA field corrections (#11407)
Implementation of suggestions from usage test by an screen reader user
Change-Id: If02512f3d4ee60e3e115023af9d9e600dc11321a
15 files changed, 225 insertions, 116 deletions
diff --git a/client/src/com/vaadin/client/VCaption.java b/client/src/com/vaadin/client/VCaption.java index 607a0f0b0a..787b650f3f 100644 --- a/client/src/com/vaadin/client/VCaption.java +++ b/client/src/com/vaadin/client/VCaption.java @@ -21,7 +21,6 @@ import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AriaHelper; @@ -205,6 +204,8 @@ public class VCaption extends HTML { removeStyleDependentName("hasdescription"); } + AriaHelper.handleInputRequired(owner.getWidget(), showRequired); + if (showRequired) { if (requiredFieldIndicator == null) { requiredFieldIndicator = DOM.createDiv(); @@ -215,9 +216,6 @@ public class VCaption extends HTML { DOM.insertChild(getElement(), requiredFieldIndicator, getInsertPosition(InsertPosition.REQUIRED)); - Roles.getTextboxRole().setAriaRequiredProperty( - owner.getWidget().getElement(), true); - // Hide the required indicator from assistive device Roles.getTextboxRole().setAriaHiddenState( requiredFieldIndicator, true); @@ -226,11 +224,10 @@ public class VCaption extends HTML { // Remove existing DOM.removeChild(getElement(), requiredFieldIndicator); requiredFieldIndicator = null; - - Roles.getTextboxRole().removeAriaRequiredProperty( - owner.getWidget().getElement()); } + AriaHelper.handleInputInvalid(owner.getWidget(), showError); + if (showError) { if (errorIndicatorElement == null) { errorIndicatorElement = DOM.createDiv(); @@ -240,6 +237,10 @@ public class VCaption extends HTML { DOM.insertChild(getElement(), errorIndicatorElement, getInsertPosition(InsertPosition.ERROR)); + + // Hide error indicator from assistive devices + Roles.getTextboxRole().setAriaHiddenState( + errorIndicatorElement, true); } } else if (errorIndicatorElement != null) { // Remove existing diff --git a/client/src/com/vaadin/client/ui/AriaHelper.java b/client/src/com/vaadin/client/ui/AriaHelper.java index 56f358f294..10038a720f 100644 --- a/client/src/com/vaadin/client/ui/AriaHelper.java +++ b/client/src/com/vaadin/client/ui/AriaHelper.java @@ -34,9 +34,9 @@ public class AriaHelper { * WAI-ARIA specification. * * @param widget - * Element, that should be bound to the caption - * @param captionElement - * Element of the caption + * Widget, that should be bound to the caption + * @param captionElements + * Element with of caption to bind */ public static void bindCaption(Widget widget, Element captionElement) { assert widget != null : "Valid Widget required"; @@ -62,44 +62,87 @@ public class AriaHelper { } } - public static void clearCaption(Widget widget) { + /** + * Removes a binding to a caption from the provided Widget. + * + * @param widget + * Widget, that was bound to a caption before + */ + private static void clearCaption(Widget widget) { Roles.getTextboxRole() .removeAriaLabelledbyProperty(widget.getElement()); } /** + * Handles the required actions depending of the input Widget being required + * or not. + * + * @param widget + * Widget, typically an input Widget like TextField + * @param required + * boolean, true when the element is required + */ + public static void handleInputRequired(Widget widget, boolean required) { + assert widget != null : "Valid Widget required"; + + if (widget instanceof HandlesAriaRequired) { + ((HandlesAriaRequired) widget).setRequired(required); + } else { + handleInputRequired(widget.getElement(), required); + } + } + + /** * Handles the required actions depending of the input element being * required or not. * - * @param inputElement - * Element, typically an input element + * @param element + * Element, typically from an input Widget like TextField * @param required * boolean, true when the element is required */ - public static void handleInputRequired(Element inputElement, - boolean required) { + public static void handleInputRequired(Element element, boolean required) { if (required) { - Roles.getTextboxRole().setAriaRequiredProperty(inputElement, true); + Roles.getTextboxRole().setAriaRequiredProperty(element, required); + } else { + Roles.getTextboxRole().removeAriaRequiredProperty(element); + } + } + + /** + * Handles the required actions depending of the input Widget contains + * unaccepted input. + * + * @param widget + * Widget, typically an input Widget like TextField + * @param invalid + * boolean, true when the Widget input has an error + */ + public static void handleInputInvalid(Widget widget, boolean invalid) { + assert widget != null : "Valid Widget required"; + + if (widget instanceof HandlesAriaInvalid) { + ((HandlesAriaInvalid) widget).setInvalid(invalid); } else { - Roles.getTextboxRole().removeAriaRequiredProperty(inputElement); + handleInputInvalid(widget.getElement(), invalid); } } /** * Handles the required actions depending of the input element contains - * unaccepted input + * unaccepted input. * - * @param inputElement - * Element, typically an input element - * @param showError + * @param element + * Element, typically an input Widget like TextField + * @param invalid * boolean, true when the element input has an error */ - public static void handleInputError(Element inputElement, boolean showError) { - if (showError) { - Roles.getTextboxRole().setAriaInvalidState(inputElement, + public static void handleInputInvalid(Element element, boolean invalid) { + if (invalid) { + Roles.getTextboxRole().setAriaInvalidState(element, InvalidValue.TRUE); } else { - Roles.getTextboxRole().removeAriaInvalidState(inputElement); + Roles.getTextboxRole().removeAriaInvalidState(element); } } @@ -112,6 +155,8 @@ public class AriaHelper { * @return String with the id of the element */ public static String ensureUniqueId(Element element) { + assert element != null : "Valid Element required"; + String id = element.getId(); if (null == id || id.isEmpty()) { id = DOM.createUniqueId(); diff --git a/client/src/com/vaadin/client/ui/HandlesAriaInvalid.java b/client/src/com/vaadin/client/ui/HandlesAriaInvalid.java new file mode 100644 index 0000000000..1793c4386d --- /dev/null +++ b/client/src/com/vaadin/client/ui/HandlesAriaInvalid.java @@ -0,0 +1,17 @@ +package com.vaadin.client.ui; + +/** + * Some Widgets need to handle the required handling for WAI-ARIA themselfs, as + * this attribute needs to be set to the input element itself. In such a case, + * the Widget needs to implement this interface. + */ +public interface HandlesAriaInvalid { + /** + * Called to set the element, typically an input element, as invalid. + * + * @param invalid + * boolean, true when the element should be marked invalid, false + * otherwise + */ + void setInvalid(boolean invalid); +} diff --git a/client/src/com/vaadin/client/ui/HandlesAriaRequired.java b/client/src/com/vaadin/client/ui/HandlesAriaRequired.java new file mode 100644 index 0000000000..a2c61220ae --- /dev/null +++ b/client/src/com/vaadin/client/ui/HandlesAriaRequired.java @@ -0,0 +1,16 @@ +package com.vaadin.client.ui; + +/** + * Some Widgets need to handle the required handling for WAI-ARIA themselfs, as + * this attribute needs to be set to the input element itself. In such a case, + * the Widget needs to implement this interface. + */ +public interface HandlesAriaRequired { + /** + * Called to set the element, typically an input element, as required. + * + * @param required + * boolean true when the element needs to be set as required + */ + void setRequired(boolean required); +} diff --git a/client/src/com/vaadin/client/ui/VCheckBox.java b/client/src/com/vaadin/client/ui/VCheckBox.java index a94c2fcfee..4c592d52a1 100644 --- a/client/src/com/vaadin/client/ui/VCheckBox.java +++ b/client/src/com/vaadin/client/ui/VCheckBox.java @@ -16,8 +16,6 @@ package com.vaadin.client.ui; -import com.google.gwt.aria.client.CheckedValue; -import com.google.gwt.aria.client.Roles; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; @@ -26,7 +24,7 @@ import com.vaadin.client.Util; import com.vaadin.client.VTooltip; public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements - Field { + Field, HandlesAriaInvalid, HandlesAriaRequired { public static final String CLASSNAME = "v-checkbox"; @@ -48,11 +46,6 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements public VCheckBox() { setStyleName(CLASSNAME); - // Add a11y role "checkbox" - Roles.getCheckboxRole().set(getElement()); - Roles.getCheckboxRole().setAriaCheckedState(getElement(), - CheckedValue.FALSE); - Element el = DOM.getFirstChild(getElement()); while (el != null) { DOM.sinkEvents(el, @@ -76,22 +69,23 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements } } - @Override - public void setValue(Boolean value, boolean fireEvents) { - setCheckedValue(value); - super.setValue(value, fireEvents); + /** + * Gives access to the input element. + * + * @return Element of the CheckBox itself + */ + private Element getCheckBoxElement() { + // FIXME: Would love to use a better way to access the checkbox element + return (Element) getElement().getFirstChildElement(); } - private void setCheckedValue(Boolean value) { - CheckedValue checkedValue = value ? CheckedValue.TRUE - : CheckedValue.FALSE; - Roles.getCheckboxRole().setAriaCheckedState(getElement(), checkedValue); + @Override + public void setRequired(boolean required) { + AriaHelper.handleInputRequired(getCheckBoxElement(), required); } @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - Roles.getCheckboxRole().setAriaDisabledState(getElement(), true); + public void setInvalid(boolean invalid) { + AriaHelper.handleInputInvalid(getCheckBoxElement(), invalid); } } diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 5025f27248..d74bb6c7a2 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -82,7 +82,7 @@ import com.vaadin.shared.ui.combobox.FilteringMode; @SuppressWarnings("deprecation") public class VFilterSelect extends Composite implements Field, KeyDownHandler, KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable, - SubPartAware { + SubPartAware, HandlesAriaInvalid, HandlesAriaRequired { /** * Represents a suggestion in the suggestion popup box @@ -1053,6 +1053,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, }); popupOpener.sinkEvents(Event.ONMOUSEDOWN); + Roles.getButtonRole() + .setAriaHiddenState(popupOpener.getElement(), true); Roles.getButtonRole().set(popupOpener.getElement()); panel.add(tb); @@ -1831,4 +1833,14 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, } return null; } + + @Override + public void setRequired(boolean required) { + AriaHelper.handleInputRequired(tb, required); + } + + @Override + public void setInvalid(boolean invalid) { + AriaHelper.handleInputInvalid(tb, invalid); + } } diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java index 4c7190340f..37a2541aba 100644 --- a/client/src/com/vaadin/client/ui/VFormLayout.java +++ b/client/src/com/vaadin/client/ui/VFormLayout.java @@ -302,6 +302,9 @@ public class VFormLayout extends SimplePanel { boolean required = owner instanceof AbstractFieldConnector && ((AbstractFieldConnector) owner).isRequired(); + + AriaHelper.handleInputRequired(owner.getWidget(), required); + if (required) { if (requiredFieldIndicator == null) { requiredFieldIndicator = DOM.createSpan(); @@ -310,9 +313,6 @@ public class VFormLayout extends SimplePanel { "v-required-field-indicator"); DOM.appendChild(getElement(), requiredFieldIndicator); - Roles.getTextboxRole().setAriaRequiredProperty( - owner.getWidget().getElement(), true); - // Hide the required indicator from screen reader, as this // information is set directly at the input field Roles.getTextboxRole().setAriaHiddenState( @@ -322,9 +322,6 @@ public class VFormLayout extends SimplePanel { if (requiredFieldIndicator != null) { DOM.removeChild(getElement(), requiredFieldIndicator); requiredFieldIndicator = null; - - Roles.getTextboxRole().removeAriaRequiredProperty( - owner.getWidget().getElement()); } } @@ -379,6 +376,8 @@ public class VFormLayout extends SimplePanel { showError = false; } + AriaHelper.handleInputInvalid(owner.getWidget(), showError); + if (showError) { if (errorIndicatorElement == null) { errorIndicatorElement = DOM.createDiv(); @@ -386,6 +385,11 @@ public class VFormLayout extends SimplePanel { DOM.setElementProperty(errorIndicatorElement, "className", "v-errorindicator"); DOM.appendChild(getElement(), errorIndicatorElement); + + // Hide the error indicator from screen reader, as this + // information is set directly at the input field + Roles.getFormRole().setAriaHiddenState( + errorIndicatorElement, true); } } else if (errorIndicatorElement != null) { diff --git a/client/src/com/vaadin/client/ui/VOptionGroup.java b/client/src/com/vaadin/client/ui/VOptionGroup.java index f0c7b7f83d..eed5549e39 100644 --- a/client/src/com/vaadin/client/ui/VOptionGroup.java +++ b/client/src/com/vaadin/client/ui/VOptionGroup.java @@ -22,8 +22,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import com.google.gwt.aria.client.CheckedValue; -import com.google.gwt.aria.client.Id; import com.google.gwt.aria.client.Roles; import com.google.gwt.core.client.Scheduler; import com.google.gwt.event.dom.client.BlurEvent; @@ -35,7 +33,6 @@ import com.google.gwt.event.dom.client.LoadEvent; import com.google.gwt.event.dom.client.LoadHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.Focusable; @@ -50,7 +47,7 @@ import com.vaadin.shared.EventId; import com.vaadin.shared.ui.optiongroup.OptionGroupConstants; public class VOptionGroup extends VOptionGroupBase implements FocusHandler, - BlurHandler, HandlesAriaCaption { + BlurHandler { public static final String CLASSNAME = "v-select-optiongroup"; @@ -89,8 +86,6 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, /** For internal use only. May be removed or replaced in the future. */ public boolean htmlContentAllowed = false; - private String labelId; - public VOptionGroup() { super(CLASSNAME); panel = (Panel) optionsContainer; @@ -131,30 +126,9 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, if (isMultiselect()) { op = new VCheckBox(); op.setHTML(itemHtml); - - // Add a11y role "checkbox" - FIXME - did not find a good - // solution to prevent getFirstChild() - com.google.gwt.dom.client.Element checkBoxElement = op - .getElement().getFirstChildElement(); - Roles.getCheckboxRole().set(checkBoxElement); - Roles.getCheckboxRole().setAriaCheckedState(checkBoxElement, - CheckedValue.FALSE); } else { op = new RadioButton(paintableId, itemHtml, true); op.setStyleName("v-radiobutton"); - - // Add a11y role "radio" - FIXME - did not find a good solution - // to prevent getFirstChild() - com.google.gwt.dom.client.Element radioElement = op - .getElement().getFirstChildElement(); - Roles.getRadioRole().set(radioElement); - Roles.getRadioRole().setAriaCheckedState(radioElement, - CheckedValue.FALSE); - } - - if (labelId != null && !labelId.isEmpty()) { - Roles.getFormRole().setAriaDescribedbyProperty( - op.getElement().getFirstChildElement(), Id.of(labelId)); } if (icon != null && icon.length() != 0) { @@ -199,13 +173,6 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, } client.updateVariable(paintableId, "selected", getSelectedItems(), isImmediate()); - - for (CheckBox item : optionsToKeys.keySet()) { - CheckedValue value = item.getValue() ? CheckedValue.TRUE - : CheckedValue.FALSE; - Roles.getCheckboxRole().setAriaCheckedState(item.getElement(), - value); - } } } @@ -279,22 +246,4 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, }); } } - - @Override - public void bindAriaCaption(Element captionElement) { - labelId = captionElement.getId(); - for (CheckBox item : optionsToKeys.keySet()) { - Roles.getCheckboxRole().setAriaLabelledbyProperty( - item.getElement(), Id.of(labelId)); - } - } - - @Override - public void clearAriaCaption() { - labelId = null; - for (CheckBox item : optionsToKeys.keySet()) { - Roles.getCheckboxRole().removeAriaLabelledbyProperty( - item.getElement()); - } - } } diff --git a/client/src/com/vaadin/client/ui/VPopupCalendar.java b/client/src/com/vaadin/client/ui/VPopupCalendar.java index a437f3c64a..aa34a1b4e3 100644 --- a/client/src/com/vaadin/client/ui/VPopupCalendar.java +++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java @@ -44,6 +44,7 @@ import com.vaadin.client.BrowserInfo; import com.vaadin.client.VConsole; import com.vaadin.client.ui.VCalendarPanel.FocusOutListener; import com.vaadin.client.ui.VCalendarPanel.SubmitListener; +import com.vaadin.shared.ui.datefield.PopupDateFieldState; import com.vaadin.shared.ui.datefield.Resolution; /** @@ -79,6 +80,8 @@ public class VPopupCalendar extends VTextualDate implements Field, private Label selectedDate; + private Element descriptionForAssisitveDevicesElement; + public VPopupCalendar() { super(); @@ -93,6 +96,16 @@ public class VPopupCalendar extends VTextualDate implements Field, add(calendarToggle); + // Description of the usage of the widget for assisitve device users + descriptionForAssisitveDevicesElement = DOM.createDiv(); + descriptionForAssisitveDevicesElement + .setInnerText(PopupDateFieldState.DESCRIPTION_FOR_ASSISTIVE_DEVICES); + AriaHelper.ensureUniqueId(descriptionForAssisitveDevicesElement); + Id.of(descriptionForAssisitveDevicesElement); + AriaHelper + .visibleForAssistiveDevicesOnly(descriptionForAssisitveDevicesElement); + DOM.appendChild(getElement(), descriptionForAssisitveDevicesElement); + calendar = GWT.create(VCalendarPanel.class); calendar.setParentField(this); calendar.setFocusOutListener(new FocusOutListener() { @@ -265,7 +278,7 @@ public class VPopupCalendar extends VTextualDate implements Field, if (isTextFieldEnabled()) { super.clearAriaCaption(); } else { - AriaHelper.clearCaption(calendarToggle); + AriaHelper.bindCaption(calendarToggle, null); } handleAriaAttributes(); @@ -546,4 +559,26 @@ public class VPopupCalendar extends VTextualDate implements Field, return super.getSubPartName(subElement); } + /** + * Set a description that explains the usage of the Widget for users of + * assistive devices. + * + * @param descriptionForAssistiveDevices + * String with the description + */ + public void setDescriptionForAssistiveDevices( + String descriptionForAssistiveDevices) { + descriptionForAssisitveDevicesElement + .setInnerText(descriptionForAssistiveDevices); + } + + /** + * Get the description that explains the usage of the Widget for users of + * assistive devices. + * + * @return String with the description + */ + public String getDescriptionForAssistiveDevices() { + return descriptionForAssisitveDevicesElement.getInnerText(); + } } diff --git a/client/src/com/vaadin/client/ui/VTextualDate.java b/client/src/com/vaadin/client/ui/VTextualDate.java index 97a868b69d..92cc81605c 100644 --- a/client/src/com/vaadin/client/ui/VTextualDate.java +++ b/client/src/com/vaadin/client/ui/VTextualDate.java @@ -35,7 +35,8 @@ import com.vaadin.shared.EventId; import com.vaadin.shared.ui.datefield.Resolution; public class VTextualDate extends VDateField implements Field, ChangeHandler, - Focusable, SubPartAware, HandlesAriaCaption { + Focusable, SubPartAware, HandlesAriaCaption, HandlesAriaInvalid, + HandlesAriaRequired { private static final String PARSE_ERROR_CLASSNAME = "-parseerror"; @@ -161,7 +162,17 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler, @Override public void clearAriaCaption() { - AriaHelper.clearCaption(text); + AriaHelper.bindCaption(text, null); + } + + @Override + public void setRequired(boolean required) { + AriaHelper.handleInputRequired(text, required); + } + + @Override + public void setInvalid(boolean invalid) { + AriaHelper.handleInputInvalid(text, invalid); } /** diff --git a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java index 772419e730..ebfda2d715 100644 --- a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java +++ b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java @@ -69,6 +69,8 @@ public class CheckBoxConnector extends AbstractFieldConnector implements blurHandlerRegistration); if (null != getState().errorMessage) { + getWidget().setInvalid(true); + if (getWidget().errorIndicatorElement == null) { getWidget().errorIndicatorElement = DOM.createSpan(); getWidget().errorIndicatorElement.setInnerHTML(" "); @@ -85,12 +87,13 @@ public class CheckBoxConnector extends AbstractFieldConnector implements } else if (getWidget().errorIndicatorElement != null) { DOM.setStyleAttribute(getWidget().errorIndicatorElement, "display", "none"); - } - if (isReadOnly()) { - getWidget().setEnabled(false); + getWidget().setInvalid(false); } + getWidget().setRequired(isRequired()); + getWidget().setEnabled(!isReadOnly()); + if (getIcon() != null) { if (getWidget().icon == null) { getWidget().icon = new Icon(getConnection()); diff --git a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java index 7246c27b6b..f59ac713e8 100644 --- a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java +++ b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java @@ -119,6 +119,8 @@ public class PopupDateFieldConnector extends TextualDateConnector { + "-button-readonly"); } + getWidget().setDescriptionForAssistiveDevices( + getState().descriptionForAssistiveDevices); getWidget().calendarToggle.setEnabled(true); } diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index ac5a08475e..9cda995160 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -30,8 +30,8 @@ import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractLayoutConnector; -import com.vaadin.client.ui.LayoutClickEventHandler; import com.vaadin.client.ui.AriaHelper; +import com.vaadin.client.ui.LayoutClickEventHandler; import com.vaadin.client.ui.layout.ElementResizeEvent; import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.shared.AbstractFieldState; @@ -259,10 +259,8 @@ public abstract class AbstractOrderedLayoutConnector extends slot.setCaption(caption, iconUrlString, styles, error, showError, required, enabled); - AriaHelper.handleInputRequired(child.getWidget().getElement(), - required); - AriaHelper.handleInputError(child.getWidget().getElement(), - showError); + AriaHelper.handleInputRequired(child.getWidget(), required); + AriaHelper.handleInputInvalid(child.getWidget(), showError); AriaHelper.bindCaption(child.getWidget(), slot.getCaptionElement()); if (slot.hasCaption()) { diff --git a/server/src/com/vaadin/ui/PopupDateField.java b/server/src/com/vaadin/ui/PopupDateField.java index ae33493c89..b113378e74 100644 --- a/server/src/com/vaadin/ui/PopupDateField.java +++ b/server/src/com/vaadin/ui/PopupDateField.java @@ -118,4 +118,24 @@ public class PopupDateField extends DateField { getState().textFieldEnabled = state; } + /** + * Set a description that explains the usage of the Widget for users of + * assistive devices. + * + * @param descriptionForAssistiveDevices + * String with the description + */ + public void setDescriptionForAssistiveDevices(String description) { + getState().descriptionForAssistiveDevices = description; + } + + /** + * Get the description that explains the usage of the Widget for users of + * assistive devices. + * + * @return String with the description + */ + public String getDescriptionForAssistiveDevices() { + return getState().descriptionForAssistiveDevices; + } } diff --git a/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java index 74cab3efb0..1c061b3ac3 100644 --- a/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java +++ b/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java @@ -16,10 +16,12 @@ package com.vaadin.shared.ui.datefield; public class PopupDateFieldState extends TextualDateFieldState { + public static final String DESCRIPTION_FOR_ASSISTIVE_DEVICES = "Arrow down key opens calendar element for choosing the date"; + { primaryStyleName = "v-datefield"; } public boolean textFieldEnabled = true; - + public String descriptionForAssistiveDevices = DESCRIPTION_FOR_ASSISTIVE_DEVICES; } |