summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authormichaelvogt <michael@vaadin.com>2013-03-05 10:48:11 +0200
committerVaadin Code Review <review@vaadin.com>2013-03-05 09:04:41 +0000
commitb5c6f6cc0c75fa2849ad14dd395af69698440257 (patch)
tree62453df37489afee37458de72c4ec7f64b28c790 /client
parentd81cd5b9c3eb4a32d4119f946706f76f305372e3 (diff)
downloadvaadin-framework-b5c6f6cc0c75fa2849ad14dd395af69698440257.tar.gz
vaadin-framework-b5c6f6cc0c75fa2849ad14dd395af69698440257.zip
WAI-ARIA for form fields (#11180)
Changes in the base classes of the form fields for WAI-ARIA integration Change-Id: I770082c353b1b0004875675e28f03d6a3e69f03f
Diffstat (limited to 'client')
-rw-r--r--client/src/com/vaadin/client/ui/AriaHelper.java95
-rw-r--r--client/src/com/vaadin/client/ui/HandlesAriaCaption.java20
-rw-r--r--client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java7
-rw-r--r--client/src/com/vaadin/client/ui/orderedlayout/Slot.java7
4 files changed, 128 insertions, 1 deletions
diff --git a/client/src/com/vaadin/client/ui/AriaHelper.java b/client/src/com/vaadin/client/ui/AriaHelper.java
new file mode 100644
index 0000000000..e762ba57ce
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/AriaHelper.java
@@ -0,0 +1,95 @@
+package com.vaadin.client.ui;
+
+import com.google.gwt.aria.client.Id;
+import com.google.gwt.aria.client.InvalidValue;
+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.ui.Widget;
+
+/**
+ * Helper class that helps to implement the WAI-ARIA functionality.
+ */
+public class AriaHelper {
+
+ /**
+ * Binds a caption (label in HTML speak) to the form element as required by
+ * WAI-ARIA specification.
+ *
+ * @param widget
+ * Element, that should be bound to the caption
+ * @param captionElement
+ * Element of the caption
+ */
+ public static void bindCaption(Widget widget, Element captionElement) {
+ assert widget != null : "Valid Widget required";
+
+ ensureUniqueId(captionElement);
+
+ if (widget instanceof HandlesAriaCaption) {
+ ((HandlesAriaCaption) widget).handleAriaCaption(captionElement);
+ } else if (captionElement != null) {
+ String ownerId = ensureUniqueId(widget.getElement());
+ captionElement.setAttribute("for", ownerId);
+
+ Roles.getTextboxRole().setAriaLabelledbyProperty(
+ widget.getElement(), Id.of(captionElement));
+ } else {
+ Roles.getTextboxRole().removeAriaLabelledbyProperty(
+ widget.getElement());
+ }
+ }
+
+ /**
+ * Handles the required actions depending of the input element being
+ * required or not.
+ *
+ * @param inputElement
+ * Element, typically an input element
+ * @param required
+ * boolean, true when the element is required
+ */
+ public static void handleInputRequired(Element inputElement,
+ boolean required) {
+ if (required) {
+ Roles.getTextboxRole().setAriaRequiredProperty(inputElement, true);
+ } else {
+ Roles.getTextboxRole().removeAriaRequiredProperty(inputElement);
+ }
+ }
+
+ /**
+ * Handles the required actions depending of the input element contains
+ * unaccepted input
+ *
+ * @param inputElement
+ * Element, typically an input element
+ * @param showError
+ * boolean, true when the element input has an error
+ */
+ public static void handleInputError(Element inputElement, boolean showError) {
+ if (showError) {
+ Roles.getTextboxRole().setAriaInvalidState(inputElement,
+ InvalidValue.TRUE);
+ } else {
+ Roles.getTextboxRole().removeAriaInvalidState(inputElement);
+ }
+ }
+
+ /**
+ * Makes sure that the provided element has an id attribute. Adds a new
+ * unique id if not.
+ *
+ * @param element
+ * Element to check
+ * @return String with the id of the element
+ */
+ private static String ensureUniqueId(Element element) {
+ String id = element.getId();
+ if (null == id || id.isEmpty()) {
+ id = DOM.createUniqueId();
+ element.setId(id);
+ }
+ return id;
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/HandlesAriaCaption.java b/client/src/com/vaadin/client/ui/HandlesAriaCaption.java
new file mode 100644
index 0000000000..4eef0c5c25
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/HandlesAriaCaption.java
@@ -0,0 +1,20 @@
+package com.vaadin.client.ui;
+
+import com.google.gwt.user.client.Element;
+
+/**
+ * Some Widgets need to handle the caption handling for WAI-ARIA themselfs, as
+ * for example the required ids need to be set in a specific way. In such a
+ * case, the Widget needs to implement this interface.
+ */
+public interface HandlesAriaCaption {
+
+ /**
+ * Called to bind the provided caption (label in HTML speak) element to the
+ * main input element of the Widget.
+ *
+ * @param captionElement
+ * Element of the caption
+ */
+ void handleAriaCaption(Element captionElement);
+}
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
index 50de8e0936..ac5a08475e 100644
--- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
+++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
@@ -31,6 +31,7 @@ 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.layout.ElementResizeEvent;
import com.vaadin.client.ui.layout.ElementResizeListener;
import com.vaadin.shared.AbstractFieldState;
@@ -258,6 +259,12 @@ 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.bindCaption(child.getWidget(), slot.getCaptionElement());
+
if (slot.hasCaption()) {
CaptionPosition pos = slot.getCaptionPosition();
getLayoutManager().addElementResizeListener(
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/Slot.java b/client/src/com/vaadin/client/ui/orderedlayout/Slot.java
index 795b724292..cf19da3496 100644
--- a/client/src/com/vaadin/client/ui/orderedlayout/Slot.java
+++ b/client/src/com/vaadin/client/ui/orderedlayout/Slot.java
@@ -18,6 +18,7 @@ package com.vaadin.client.ui.orderedlayout;
import java.util.List;
+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;
@@ -92,7 +93,6 @@ public final class Slot extends SimplePanel {
private ElementResizeListener spacingResizeListener;
-
// Caption is placed after component unless there is some part which
// moves it above.
private CaptionPosition captionPosition = CaptionPosition.RIGHT;
@@ -479,6 +479,11 @@ public final class Slot extends SimplePanel {
// character)
requiredIcon.setInnerHTML("*");
requiredIcon.setClassName("v-required-field-indicator");
+
+ // The star should not be read by the screen reader, as it is
+ // purely visual. Required state is set at the element level for
+ // the screen reader.
+ Roles.getTextboxRole().setAriaHiddenState(requiredIcon, true);
}
caption.appendChild(requiredIcon);
} else if (requiredIcon != null) {