summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichaelvogt <michael@vaadin.com>2013-03-25 15:46:58 +0200
committerVaadin Code Review <review@vaadin.com>2013-04-02 14:10:58 +0000
commit4c5c1e0cfeff1c7118ab3fffe4d45e0f1966d470 (patch)
tree70440f782721af726d2fa930d7b9f6ed8e84bffe
parentd454bf66d960d23908f427f86b4979912c476ec1 (diff)
downloadvaadin-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
-rw-r--r--client/src/com/vaadin/client/VCaption.java15
-rw-r--r--client/src/com/vaadin/client/ui/AriaHelper.java81
-rw-r--r--client/src/com/vaadin/client/ui/HandlesAriaInvalid.java17
-rw-r--r--client/src/com/vaadin/client/ui/HandlesAriaRequired.java16
-rw-r--r--client/src/com/vaadin/client/ui/VCheckBox.java34
-rw-r--r--client/src/com/vaadin/client/ui/VFilterSelect.java14
-rw-r--r--client/src/com/vaadin/client/ui/VFormLayout.java16
-rw-r--r--client/src/com/vaadin/client/ui/VOptionGroup.java53
-rw-r--r--client/src/com/vaadin/client/ui/VPopupCalendar.java37
-rw-r--r--client/src/com/vaadin/client/ui/VTextualDate.java15
-rw-r--r--client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java9
-rw-r--r--client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java2
-rw-r--r--client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java8
-rw-r--r--server/src/com/vaadin/ui/PopupDateField.java20
-rw-r--r--shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java4
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("&nbsp;");
@@ -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;
}