summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichaelvogt <michael@vaadin.com>2013-03-20 10:37:11 +0200
committermichaelvogt <michael@vaadin.com>2013-03-20 10:37:11 +0200
commit320b4e3776976e5dad822f01542f338cf76140bb (patch)
tree436ed9d448a1e663befde8b01ed8fa08a1f14700
parent9764317f6be8091cfda37faac9294f5e58ecfeef (diff)
downloadvaadin-framework-320b4e3776976e5dad822f01542f338cf76140bb.tar.gz
vaadin-framework-320b4e3776976e5dad822f01542f338cf76140bb.zip
WAI-ARIA fields (#11180)
Field implementations of the WAI-ARIA changes in the base classes Change-Id: Ie51e76130f3f9976a32c373334b709f0f5b68f1a
-rw-r--r--WebContent/VAADIN/themes/base/common/common.scss6
-rw-r--r--client/src/com/vaadin/client/VCaption.java15
-rw-r--r--client/src/com/vaadin/client/VErrorMessage.java3
-rw-r--r--client/src/com/vaadin/client/VTooltip.java130
-rw-r--r--client/src/com/vaadin/client/ui/AriaHelper.java58
-rw-r--r--client/src/com/vaadin/client/ui/HandlesAriaCaption.java8
-rw-r--r--client/src/com/vaadin/client/ui/VCalendarPanel.java85
-rw-r--r--client/src/com/vaadin/client/ui/VCheckBox.java25
-rw-r--r--client/src/com/vaadin/client/ui/VFilterSelect.java13
-rw-r--r--client/src/com/vaadin/client/ui/VFormLayout.java15
-rw-r--r--client/src/com/vaadin/client/ui/VOptionGroup.java61
-rw-r--r--client/src/com/vaadin/client/ui/VPopupCalendar.java113
-rw-r--r--client/src/com/vaadin/client/ui/VTextField.java4
-rw-r--r--client/src/com/vaadin/client/ui/VTextualDate.java21
-rw-r--r--client/src/com/vaadin/client/ui/tree/TreeConnector.java35
-rw-r--r--uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java1
16 files changed, 541 insertions, 52 deletions
diff --git a/WebContent/VAADIN/themes/base/common/common.scss b/WebContent/VAADIN/themes/base/common/common.scss
index e801ec2821..27c6dc949c 100644
--- a/WebContent/VAADIN/themes/base/common/common.scss
+++ b/WebContent/VAADIN/themes/base/common/common.scss
@@ -238,4 +238,10 @@ input::-ms-clear {
height: 0;
}
+.v-assistive-device-only {
+ position: absolute;
+ left: -2000px;
+ width: 10px;
+ overflow: hidden;
+}
} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/VCaption.java b/client/src/com/vaadin/client/VCaption.java
index 47287636c4..607a0f0b0a 100644
--- a/client/src/com/vaadin/client/VCaption.java
+++ b/client/src/com/vaadin/client/VCaption.java
@@ -16,12 +16,15 @@
package com.vaadin.client;
+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;
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;
import com.vaadin.client.ui.Icon;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.AbstractFieldState;
@@ -88,6 +91,8 @@ public class VCaption extends HTML {
this.client = client;
owner = component;
+ AriaHelper.bindCaption(component.getWidget(), getElement());
+
if (client != null && owner != null) {
setOwnerPid(getElement(), owner.getConnectorId());
}
@@ -209,11 +214,21 @@ 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);
}
} else if (requiredFieldIndicator != null) {
// Remove existing
DOM.removeChild(getElement(), requiredFieldIndicator);
requiredFieldIndicator = null;
+
+ Roles.getTextboxRole().removeAriaRequiredProperty(
+ owner.getWidget().getElement());
}
if (showError) {
diff --git a/client/src/com/vaadin/client/VErrorMessage.java b/client/src/com/vaadin/client/VErrorMessage.java
index a384b451dd..2e42b98a05 100644
--- a/client/src/com/vaadin/client/VErrorMessage.java
+++ b/client/src/com/vaadin/client/VErrorMessage.java
@@ -31,6 +31,9 @@ public class VErrorMessage extends FlowPanel {
public VErrorMessage() {
super();
setStyleName(CLASSNAME);
+
+ // Needed for binding with WAI-ARIA attributes
+ getElement().setId(DOM.createUniqueId());
}
/**
diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java
index 759b90a8cd..e6d9a79a5b 100644
--- a/client/src/com/vaadin/client/VTooltip.java
+++ b/client/src/com/vaadin/client/VTooltip.java
@@ -15,8 +15,16 @@
*/
package com.vaadin.client;
+import com.google.gwt.aria.client.Id;
+import com.google.gwt.aria.client.LiveValue;
+import com.google.gwt.aria.client.Roles;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DomEvent;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
@@ -54,6 +62,9 @@ public class VTooltip extends VOverlay {
// Open next tooltip faster. Disabled after 2 sec of showTooltip-silence.
private boolean justClosed = false;
+ private String uniqueId = DOM.createUniqueId();
+ private Element layoutElement;
+
/**
* Used to show tooltips; usually used via the singleton in
* {@link ApplicationConnection}. NOTE that #setOwner(Widget)} should be
@@ -68,8 +79,19 @@ public class VTooltip extends VOverlay {
setWidget(layout);
layout.add(em);
DOM.setElementProperty(description, "className", CLASSNAME + "-text");
- DOM.appendChild(layout.getElement(), description);
+
+ layoutElement = layout.getElement();
+ DOM.appendChild(layoutElement, description);
setSinkShadowEvents(true);
+
+ // WAI-ARIA additions
+ layoutElement.setId(uniqueId);
+ Roles.getTooltipRole().setAriaLiveProperty(getElement(),
+ LiveValue.POLITE);
+
+ description.setId(DOM.createUniqueId());
+ Roles.getTooltipRole().set(layoutElement);
+ Roles.getTooltipRole().setAriaHiddenState(layoutElement, true);
}
/**
@@ -204,15 +226,27 @@ public class VTooltip extends VOverlay {
closing = true;
justClosed = true;
justClosedTimer.schedule(QUICK_OPEN_TIMEOUT);
+ }
+ @Override
+ public void hide() {
+ super.hide();
+ Roles.getTooltipRole().setAriaHiddenState(layoutElement, true);
+ Roles.getTooltipRole().removeAriaDescribedbyProperty(
+ tooltipEventHandler.currentElement);
}
private int tooltipEventMouseX;
private int tooltipEventMouseY;
- public void updatePosition(Event event) {
- tooltipEventMouseX = DOM.eventGetClientX(event);
- tooltipEventMouseY = DOM.eventGetClientY(event);
+ public void updatePosition(Event event, boolean isFocused) {
+ if (isFocused) {
+ tooltipEventMouseX = -1000;
+ tooltipEventMouseY = -1000;
+ } else {
+ tooltipEventMouseX = DOM.eventGetClientX(event);
+ tooltipEventMouseY = DOM.eventGetClientY(event);
+ }
}
@Override
@@ -246,7 +280,7 @@ public class VTooltip extends VOverlay {
}
private class TooltipEventHandler implements MouseMoveHandler,
- ClickHandler, KeyDownHandler {
+ ClickHandler, KeyDownHandler, FocusHandler, BlurHandler {
/**
* Current element hovered
@@ -254,6 +288,11 @@ public class VTooltip extends VOverlay {
private com.google.gwt.dom.client.Element currentElement = null;
/**
+ * Current element focused
+ */
+ private boolean currentIsFocused;
+
+ /**
* Current tooltip active
*/
private TooltipInfo currentTooltipInfo = null;
@@ -319,41 +358,77 @@ public class VTooltip extends VOverlay {
@Override
public void onMouseMove(MouseMoveEvent mme) {
- Event event = Event.as(mme.getNativeEvent());
+ handleShowHide(mme, false);
+ }
+
+ @Override
+ public void onClick(ClickEvent event) {
+ handleHideEvent();
+ }
+
+ @Override
+ public void onKeyDown(KeyDownEvent event) {
+ handleHideEvent();
+ }
+
+ /**
+ * Displays Tooltip when page is navigated with the keyboard.
+ *
+ * Tooltip is not visible. This makes it possible for assistive devices
+ * to recognize the tooltip.
+ */
+ @Override
+ public void onFocus(FocusEvent fe) {
+ handleShowHide(fe, true);
+ }
+
+ /**
+ * Hides Tooltip when the page is navigated with the keyboard.
+ *
+ * Removes the Tooltip from page to make sure assistive devices don't
+ * recognize it by accident.
+ */
+ @Override
+ public void onBlur(BlurEvent be) {
+ handleHideEvent();
+ }
+
+ private void handleShowHide(DomEvent domEvent, boolean isFocused) {
+ Event event = Event.as(domEvent.getNativeEvent());
com.google.gwt.dom.client.Element element = Element.as(event
.getEventTarget());
// We can ignore move event if it's handled by move or over already
- if (currentElement == element) {
+ if (currentElement == element && currentIsFocused == isFocused) {
return;
}
- currentElement = element;
boolean connectorAndTooltipFound = resolveConnector((com.google.gwt.user.client.Element) element);
if (!connectorAndTooltipFound) {
if (isShowing()) {
handleHideEvent();
+ Roles.getButtonRole()
+ .removeAriaDescribedbyProperty(element);
} else {
currentTooltipInfo = null;
}
} else {
- updatePosition(event);
+ updatePosition(event, isFocused);
+
if (isShowing()) {
replaceCurrentTooltip();
+ Roles.getTooltipRole().removeAriaDescribedbyProperty(
+ currentElement);
} else {
showTooltip();
}
- }
- }
- @Override
- public void onClick(ClickEvent event) {
- handleHideEvent();
- }
+ Roles.getTooltipRole().setAriaDescribedbyProperty(element,
+ Id.of(uniqueId));
+ }
- @Override
- public void onKeyDown(KeyDownEvent event) {
- handleHideEvent();
+ currentIsFocused = isFocused;
+ currentElement = element;
}
}
@@ -370,6 +445,25 @@ public class VTooltip extends VOverlay {
widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType());
widget.addDomHandler(tooltipEventHandler, ClickEvent.getType());
widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType());
+ widget.addDomHandler(tooltipEventHandler, FocusEvent.getType());
+ widget.addDomHandler(tooltipEventHandler, BlurEvent.getType());
Profiler.leave("VTooltip.connectHandlersToWidget");
}
+
+ /**
+ * Returns the unique id of the tooltip element.
+ *
+ * @return String containing the unique id of the tooltip, which always has
+ * a value
+ */
+ public String getUniqueId() {
+ return uniqueId;
+ }
+
+ @Override
+ public void setPopupPositionAndShow(PositionCallback callback) {
+ super.setPopupPositionAndShow(callback);
+
+ Roles.getTooltipRole().setAriaHiddenState(layoutElement, false);
+ }
}
diff --git a/client/src/com/vaadin/client/ui/AriaHelper.java b/client/src/com/vaadin/client/ui/AriaHelper.java
index 189149f8b5..56f358f294 100644
--- a/client/src/com/vaadin/client/ui/AriaHelper.java
+++ b/client/src/com/vaadin/client/ui/AriaHelper.java
@@ -27,6 +27,7 @@ import com.google.gwt.user.client.ui.Widget;
* Helper class that helps to implement the WAI-ARIA functionality.
*/
public class AriaHelper {
+ public static final String ASSISTIVE_DEVICE_ONLY_STYLE = "v-assistive-device-only";
/**
* Binds a caption (label in HTML speak) to the form element as required by
@@ -40,24 +41,32 @@ public class AriaHelper {
public static void bindCaption(Widget widget, Element captionElement) {
assert widget != null : "Valid Widget required";
- if (null != captionElement) {
- ensureUniqueId(captionElement);
-
- if (widget instanceof HandlesAriaCaption) {
- ((HandlesAriaCaption) widget).handleAriaCaption(captionElement);
+ if (widget instanceof HandlesAriaCaption) {
+ // Let the widget handle special cases itself
+ if (captionElement == null) {
+ ((HandlesAriaCaption) widget).clearAriaCaption();
} else {
- String ownerId = ensureUniqueId(widget.getElement());
- captionElement.setAttribute("for", ownerId);
-
- Roles.getTextboxRole().setAriaLabelledbyProperty(
- widget.getElement(), Id.of(captionElement));
+ ensureUniqueId(captionElement);
+ ((HandlesAriaCaption) widget).bindAriaCaption(captionElement);
}
+ } else if (captionElement != null) {
+ // Handle the default case
+ ensureUniqueId(captionElement);
+ String ownerId = ensureUniqueId(widget.getElement());
+ captionElement.setAttribute("for", ownerId);
+
+ Roles.getTextboxRole().setAriaLabelledbyProperty(
+ widget.getElement(), Id.of(captionElement));
} else {
- Roles.getTextboxRole().removeAriaLabelledbyProperty(
- widget.getElement());
+ clearCaption(widget);
}
}
+ public static void clearCaption(Widget widget) {
+ Roles.getTextboxRole()
+ .removeAriaLabelledbyProperty(widget.getElement());
+ }
+
/**
* Handles the required actions depending of the input element being
* required or not.
@@ -102,7 +111,7 @@ public class AriaHelper {
* Element to check
* @return String with the id of the element
*/
- private static String ensureUniqueId(Element element) {
+ public static String ensureUniqueId(Element element) {
String id = element.getId();
if (null == id || id.isEmpty()) {
id = DOM.createUniqueId();
@@ -110,4 +119,27 @@ public class AriaHelper {
}
return id;
}
+
+ /**
+ * Moves an element out of sight. That way it is possible to have additional
+ * information for an assistive device, that is not in the way for visual
+ * users.
+ *
+ * @param element
+ * Element to move out of sight
+ */
+ public static void visibleForAssistiveDevicesOnly(Element element) {
+ element.addClassName(ASSISTIVE_DEVICE_ONLY_STYLE);
+ }
+
+ /**
+ * Clears the settings that moved the element out of sight, so it is visible
+ * on the page again.
+ *
+ * @param element
+ * Element to clear the specific styles from
+ */
+ public static void visibleForAll(Element element) {
+ element.removeClassName(ASSISTIVE_DEVICE_ONLY_STYLE);
+ }
}
diff --git a/client/src/com/vaadin/client/ui/HandlesAriaCaption.java b/client/src/com/vaadin/client/ui/HandlesAriaCaption.java
index 045bec1d4b..fbbbbff462 100644
--- a/client/src/com/vaadin/client/ui/HandlesAriaCaption.java
+++ b/client/src/com/vaadin/client/ui/HandlesAriaCaption.java
@@ -32,5 +32,11 @@ public interface HandlesAriaCaption {
* @param captionElement
* Element of the caption
*/
- void handleAriaCaption(Element captionElement);
+ void bindAriaCaption(Element captionElement);
+
+ /**
+ * Called to clear the binding to a caption from the main input element of
+ * the widget.
+ */
+ void clearAriaCaption();
}
diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java
index e234cc911c..3e81ec734b 100644
--- a/client/src/com/vaadin/client/ui/VCalendarPanel.java
+++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java
@@ -19,6 +19,8 @@ package com.vaadin.client.ui;
import java.util.Date;
import java.util.Iterator;
+import com.google.gwt.aria.client.Roles;
+import com.google.gwt.aria.client.SelectedValue;
import com.google.gwt.dom.client.Node;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -40,6 +42,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.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
@@ -175,9 +178,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
private boolean showISOWeekNumbers;
- private Date displayedMonth;
+ private FocusedDate displayedMonth;
- private Date focusedDate;
+ private FocusedDate focusedDate;
private Day selectedDay;
@@ -198,8 +201,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
private boolean initialRenderDone = false;
public VCalendarPanel() {
-
+ getElement().setId(DOM.createUniqueId());
setStyleName(VDateField.CLASSNAME + "-calendarpanel");
+ Roles.getGridRole().set(getElement());
/*
* Firefox auto-repeat works correctly only if we use a key press
@@ -267,6 +271,8 @@ public class VCalendarPanel extends FocusableFlexTable implements
private void selectDate(Date date) {
if (selectedDay != null) {
selectedDay.removeStyleDependentName(CN_SELECTED);
+ Roles.getGridcellRole().removeAriaSelectedState(
+ selectedDay.getElement());
}
int rowCount = days.getRowCount();
@@ -279,6 +285,8 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (curday.getDate().equals(date)) {
curday.addStyleDependentName(CN_SELECTED);
selectedDay = curday;
+ Roles.getGridcellRole().setAriaSelectedState(
+ selectedDay.getElement(), SelectedValue.TRUE);
return;
}
}
@@ -528,6 +536,10 @@ public class VCalendarPanel extends FocusableFlexTable implements
} else {
days.setHTML(headerRow, firstWeekdayColumn + i, "");
}
+
+ Roles.getColumnheaderRole().set(
+ days.getCellFormatter().getElement(headerRow,
+ firstWeekdayColumn + i));
}
// Zero out hours, minutes, seconds, and milliseconds to compare dates
@@ -557,6 +569,8 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (curr.equals(selectedDate)) {
day.addStyleDependentName(CN_SELECTED);
+ Roles.getGridcellRole().setAriaSelectedState(
+ day.getElement(), SelectedValue.TRUE);
selectedDay = day;
}
if (curr.equals(today)) {
@@ -574,10 +588,14 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, day);
+ Roles.getGridcellRole().set(
+ days.getCellFormatter().getElement(weekOfMonth,
+ firstWeekdayColumn + dayOfWeek));
// ISO week numbers if requested
days.getCellFormatter().setVisible(weekOfMonth, weekColumn,
isShowISOWeekNumbers());
+
if (isShowISOWeekNumbers()) {
final String baseCssClass = parent.getStylePrimaryName()
+ "-calendarpanel-weeknumber";
@@ -615,8 +633,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (focusedDate == null) {
Date now = new Date();
// focusedDate must have zero hours, mins, secs, millisecs
- focusedDate = new Date(now.getYear(), now.getMonth(), now.getDate());
- displayedMonth = new Date(now.getYear(), now.getMonth(), 1);
+ focusedDate = new FocusedDate(now.getYear(), now.getMonth(),
+ now.getDate());
+ displayedMonth = new FocusedDate(now.getYear(), now.getMonth(), 1);
}
if (getResolution().getCalendarField() <= Resolution.MONTH
@@ -1062,9 +1081,10 @@ public class VCalendarPanel extends FocusableFlexTable implements
*/
} else if (keycode == getResetKey() && !shift) {
// Restore showing value the selected value
- focusedDate = new Date(value.getYear(), value.getMonth(),
+ focusedDate = new FocusedDate(value.getYear(), value.getMonth(),
value.getDate());
- displayedMonth = new Date(value.getYear(), value.getMonth(), 1);
+ displayedMonth = new FocusedDate(value.getYear(), value.getMonth(),
+ 1);
renderCalendar();
return true;
}
@@ -1264,9 +1284,10 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (value == null) {
focusedDate = displayedMonth = null;
} else {
- focusedDate = new Date(value.getYear(), value.getMonth(),
+ focusedDate = new FocusedDate(value.getYear(), value.getMonth(),
value.getDate());
- displayedMonth = new Date(value.getYear(), value.getMonth(), 1);
+ displayedMonth = new FocusedDate(value.getYear(), value.getMonth(),
+ 1);
}
// Re-render calendar if the displayed month is changed,
@@ -1821,4 +1842,50 @@ public class VCalendarPanel extends FocusableFlexTable implements
mouseTimer.cancel();
}
}
+
+ /**
+ * Helper class to inform the screen reader that the user changed the
+ * selected date. It sets the value of a field that is outside the view, and
+ * is defined as a live area. That way the screen reader recognizes the
+ * change and reads it to the user.
+ */
+ public class FocusedDate extends Date {
+
+ public FocusedDate(int year, int month, int date) {
+ super(year, month, date);
+ }
+
+ @Override
+ public void setTime(long time) {
+ super.setTime(time);
+ setLabel();
+ }
+
+ @Override
+ @Deprecated
+ public void setDate(int date) {
+ super.setDate(date);
+ setLabel();
+ }
+
+ @Override
+ @Deprecated
+ public void setMonth(int month) {
+ super.setMonth(month);
+ setLabel();
+ }
+
+ @Override
+ @Deprecated
+ public void setYear(int year) {
+ super.setYear(year);
+ setLabel();
+ }
+
+ private void setLabel() {
+ if (parent instanceof VPopupCalendar) {
+ ((VPopupCalendar) parent).setFocusedDate(this);
+ }
+ }
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VCheckBox.java b/client/src/com/vaadin/client/ui/VCheckBox.java
index ca1e3ebcdb..a94c2fcfee 100644
--- a/client/src/com/vaadin/client/ui/VCheckBox.java
+++ b/client/src/com/vaadin/client/ui/VCheckBox.java
@@ -16,6 +16,8 @@
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;
@@ -46,6 +48,11 @@ 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,
@@ -69,4 +76,22 @@ 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);
+ }
+
+ private void setCheckedValue(Boolean value) {
+ CheckedValue checkedValue = value ? CheckedValue.TRUE
+ : CheckedValue.FALSE;
+ Roles.getCheckboxRole().setAriaCheckedState(getElement(), checkedValue);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+
+ Roles.getCheckboxRole().setAriaDisabledState(getElement(), true);
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java
index cea3489b42..5025f27248 100644
--- a/client/src/com/vaadin/client/ui/VFilterSelect.java
+++ b/client/src/com/vaadin/client/ui/VFilterSelect.java
@@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Style;
@@ -219,6 +220,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
DOM.sinkEvents(root, Event.ONMOUSEDOWN | Event.ONMOUSEWHEEL);
addCloseHandler(this);
+
+ Roles.getListRole().set(getElement());
}
/**
@@ -684,6 +687,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
while (it.hasNext()) {
final FilterSelectSuggestion s = it.next();
final MenuItem mi = new MenuItem(s.getDisplayString(), true, s);
+ Roles.getListitemRole().set(mi.getElement());
Util.sinkOnloadForImages(mi.getElement());
@@ -1049,9 +1053,13 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
});
popupOpener.sinkEvents(Event.ONMOUSEDOWN);
+ Roles.getButtonRole().set(popupOpener.getElement());
+
panel.add(tb);
panel.add(popupOpener);
initWidget(panel);
+ Roles.getComboboxRole().set(panel.getElement());
+
tb.addKeyDownHandler(this);
tb.addKeyUpHandler(this);
@@ -1059,6 +1067,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
tb.addBlurHandler(this);
tb.addClickHandler(this);
+ Roles.getTextboxRole().set(tb.getElement());
+
popupOpener.addClickHandler(this);
setStyleName(CLASSNAME);
@@ -1163,8 +1173,11 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
// Always update styles as they might have been overwritten
if (textInputEnabled) {
removeStyleDependentName(STYLE_NO_INPUT);
+ Roles.getTextboxRole().removeAriaReadonlyProperty(tb.getElement());
} else {
addStyleDependentName(STYLE_NO_INPUT);
+ Roles.getTextboxRole().setAriaReadonlyProperty(tb.getElement(),
+ true);
}
if (this.textInputEnabled == textInputEnabled) {
diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java
index 495e842bfd..4c7190340f 100644
--- a/client/src/com/vaadin/client/ui/VFormLayout.java
+++ b/client/src/com/vaadin/client/ui/VFormLayout.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
@@ -276,6 +277,9 @@ public class VFormLayout extends SimplePanel {
if (state.caption != null) {
if (captionText == null) {
captionText = DOM.createSpan();
+
+ AriaHelper.bindCaption(owner.getWidget(), captionText);
+
DOM.insertChild(getElement(), captionText, icon == null ? 0
: 1);
}
@@ -305,11 +309,22 @@ public class VFormLayout extends SimplePanel {
DOM.setElementProperty(requiredFieldIndicator, "className",
"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(
+ requiredFieldIndicator, true);
}
} else {
if (requiredFieldIndicator != null) {
DOM.removeChild(getElement(), requiredFieldIndicator);
requiredFieldIndicator = null;
+
+ Roles.getTextboxRole().removeAriaRequiredProperty(
+ owner.getWidget().getElement());
}
}
diff --git a/client/src/com/vaadin/client/ui/VOptionGroup.java b/client/src/com/vaadin/client/ui/VOptionGroup.java
index 2ba8a9e729..f0c7b7f83d 100644
--- a/client/src/com/vaadin/client/ui/VOptionGroup.java
+++ b/client/src/com/vaadin/client/ui/VOptionGroup.java
@@ -22,6 +22,9 @@ 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;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -32,6 +35,7 @@ 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;
@@ -46,7 +50,7 @@ import com.vaadin.shared.EventId;
import com.vaadin.shared.ui.optiongroup.OptionGroupConstants;
public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
- BlurHandler {
+ BlurHandler, HandlesAriaCaption {
public static final String CLASSNAME = "v-select-optiongroup";
@@ -85,6 +89,8 @@ 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;
@@ -99,6 +105,13 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
public void buildOptions(UIDL uidl) {
panel.clear();
optionsEnabled.clear();
+
+ if (isMultiselect()) {
+ Roles.getGroupRole().set(getElement());
+ } else {
+ Roles.getRadiogroupRole().set(getElement());
+ }
+
for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext();) {
final UIDL opUidl = (UIDL) it.next();
CheckBox op;
@@ -118,9 +131,30 @@ 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) {
@@ -165,6 +199,13 @@ 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);
+ }
}
}
@@ -238,4 +279,22 @@ 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 2a2578aa16..dfa5625341 100644
--- a/client/src/com/vaadin/client/ui/VPopupCalendar.java
+++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java
@@ -18,6 +18,9 @@ package com.vaadin.client.ui;
import java.util.Date;
+import com.google.gwt.aria.client.Id;
+import com.google.gwt.aria.client.LiveValue;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -25,14 +28,18 @@ import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.i18n.client.DateTimeFormat;
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.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.VCalendarPanel.FocusOutListener;
@@ -68,6 +75,10 @@ public class VPopupCalendar extends VTextualDate implements Field,
private boolean textFieldEnabled = true;
+ private String captionId;
+
+ private Label selectedDate;
+
public VPopupCalendar() {
super();
@@ -75,6 +86,11 @@ public class VPopupCalendar extends VTextualDate implements Field,
calendarToggle.addClickHandler(this);
// -2 instead of -1 to avoid FocusWidget.onAttach to reset it
calendarToggle.getElement().setTabIndex(-2);
+
+ Roles.getButtonRole().set(calendarToggle.getElement());
+ Roles.getButtonRole().setAriaHiddenState(calendarToggle.getElement(),
+ true);
+
add(calendarToggle);
calendar = GWT.create(VCalendarPanel.class);
@@ -88,6 +104,9 @@ public class VPopupCalendar extends VTextualDate implements Field,
}
});
+ Roles.getButtonRole().setAriaControlsProperty(
+ calendarToggle.getElement(), Id.of(calendar.getElement()));
+
calendar.setSubmitListener(new SubmitListener() {
@Override
public void onSubmit() {
@@ -109,7 +128,19 @@ public class VPopupCalendar extends VTextualDate implements Field,
popup = new VOverlay(true, true, true);
popup.setOwner(this);
- popup.setWidget(calendar);
+ FlowPanel wrapper = new FlowPanel();
+ selectedDate = new Label();
+ selectedDate.setStyleName(getStylePrimaryName() + "-selecteddate");
+ AriaHelper.visibleForAssistiveDevicesOnly(selectedDate.getElement());
+
+ Roles.getTextboxRole().setAriaLiveProperty(selectedDate.getElement(),
+ LiveValue.ASSERTIVE);
+ Roles.getTextboxRole().setAriaAtomicProperty(selectedDate.getElement(),
+ true);
+ wrapper.add(selectedDate);
+ wrapper.add(calendar);
+
+ popup.setWidget(wrapper);
popup.addCloseHandler(this);
DOM.setElementProperty(calendar.getElement(), "id",
@@ -181,9 +212,63 @@ public class VPopupCalendar extends VTextualDate implements Field,
text.setEnabled(textFieldEnabled);
if (textFieldEnabled) {
calendarToggle.setTabIndex(-1);
+ Roles.getButtonRole().setAriaHiddenState(
+ calendarToggle.getElement(), true);
} else {
calendarToggle.setTabIndex(0);
+ Roles.getButtonRole().setAriaHiddenState(
+ calendarToggle.getElement(), false);
+ }
+
+ handleAriaAttributes();
+ }
+
+ @Override
+ public void bindAriaCaption(Element captionElement) {
+ captionId = captionElement.getId();
+
+ if (isTextFieldEnabled()) {
+ super.bindAriaCaption(captionElement);
+ } else {
+ AriaHelper.bindCaption(calendarToggle, captionElement);
+ }
+
+ handleAriaAttributes();
+ }
+
+ private void handleAriaAttributes() {
+ Widget removeFromWidget;
+ Widget setForWidget;
+
+ if (isTextFieldEnabled()) {
+ setForWidget = text;
+ removeFromWidget = calendarToggle;
+ } else {
+ setForWidget = calendarToggle;
+ removeFromWidget = text;
}
+
+ Roles.getFormRole().removeAriaLabelledbyProperty(
+ removeFromWidget.getElement());
+ if (captionId == null) {
+ Roles.getFormRole().removeAriaLabelledbyProperty(
+ setForWidget.getElement());
+ } else {
+ Roles.getFormRole().setAriaLabelledbyProperty(
+ setForWidget.getElement(), Id.of(captionId));
+ }
+ }
+
+ @Override
+ public void clearAriaCaption() {
+ captionId = null;
+ if (isTextFieldEnabled()) {
+ super.clearAriaCaption();
+ } else {
+ AriaHelper.clearCaption(calendarToggle);
+ }
+
+ handleAriaAttributes();
}
/*
@@ -350,6 +435,32 @@ public class VPopupCalendar extends VTextualDate implements Field,
calendar.setFocus(focus);
}
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+
+ if (enabled) {
+ Roles.getButtonRole().setAriaDisabledState(
+ calendarToggle.getElement(), true);
+ } else {
+ Roles.getButtonRole().setAriaDisabledState(
+ calendarToggle.getElement(), false);
+ }
+ }
+
+ /**
+ * Sets the content of a special field for assistive devices, so that they
+ * can recognize the change and inform the user (reading out in case of
+ * screen reader)
+ *
+ * @param selectedDate
+ * Date that is currently selected
+ */
+ public void setFocusedDate(Date selectedDate) {
+ this.selectedDate.setText(DateTimeFormat.getFormat("dd, MMMM, yyyy")
+ .format(selectedDate));
+ }
+
/**
* For internal use only. May be removed or replaced in the future.
*
diff --git a/client/src/com/vaadin/client/ui/VTextField.java b/client/src/com/vaadin/client/ui/VTextField.java
index 0fbed0dd90..9b85dd22da 100644
--- a/client/src/com/vaadin/client/ui/VTextField.java
+++ b/client/src/com/vaadin/client/ui/VTextField.java
@@ -16,6 +16,7 @@
package com.vaadin.client.ui;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
@@ -95,6 +96,9 @@ public class VTextField extends TextBoxBase implements Field, ChangeHandler,
}
addFocusHandler(this);
addBlurHandler(this);
+
+ // Add a11y role "textbox"
+ Roles.getTextboxRole().set(node);
}
/**
diff --git a/client/src/com/vaadin/client/ui/VTextualDate.java b/client/src/com/vaadin/client/ui/VTextualDate.java
index 2f444a8587..97a868b69d 100644
--- a/client/src/com/vaadin/client/ui/VTextualDate.java
+++ b/client/src/com/vaadin/client/ui/VTextualDate.java
@@ -18,6 +18,7 @@ package com.vaadin.client.ui;
import java.util.Date;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
@@ -34,7 +35,7 @@ import com.vaadin.shared.EventId;
import com.vaadin.shared.ui.datefield.Resolution;
public class VTextualDate extends VDateField implements Field, ChangeHandler,
- Focusable, SubPartAware {
+ Focusable, SubPartAware, HandlesAriaCaption {
private static final String PARSE_ERROR_CLASSNAME = "-parseerror";
@@ -96,6 +97,9 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
}
}
});
+
+ Roles.getTextboxRole().set(text.getElement());
+
add(text);
}
@@ -150,6 +154,16 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
return formatStr;
}
+ @Override
+ public void bindAriaCaption(Element captionElement) {
+ AriaHelper.bindCaption(text, captionElement);
+ }
+
+ @Override
+ public void clearAriaCaption() {
+ AriaHelper.clearCaption(text);
+ }
+
/**
* Updates the text field according to the current date (provided by
* {@link #getDate()}). Takes care of updating text, enabling and disabling
@@ -178,8 +192,12 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
if (readonly) {
text.addStyleName("v-readonly");
+ Roles.getTextboxRole().setAriaReadonlyProperty(text.getElement(),
+ true);
} else {
text.removeStyleName("v-readonly");
+ Roles.getTextboxRole()
+ .removeAriaReadonlyProperty(text.getElement());
}
}
@@ -348,5 +366,4 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
return null;
}
-
}
diff --git a/client/src/com/vaadin/client/ui/tree/TreeConnector.java b/client/src/com/vaadin/client/ui/tree/TreeConnector.java
index d6d1cef8cc..6e3fffb47c 100644
--- a/client/src/com/vaadin/client/ui/tree/TreeConnector.java
+++ b/client/src/com/vaadin/client/ui/tree/TreeConnector.java
@@ -19,6 +19,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Element;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
@@ -26,6 +27,7 @@ import com.vaadin.client.Paintable;
import com.vaadin.client.TooltipInfo;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
+import com.vaadin.client.VConsole;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.VTree;
@@ -93,7 +95,7 @@ public class TreeConnector extends AbstractComponentConnector implements
}
childTree = getWidget().new TreeNode();
getConnection().getVTooltip().connectHandlersToWidget(childTree);
- updateNodeFromUIDL(childTree, childUidl);
+ updateNodeFromUIDL(childTree, childUidl, 1);
getWidget().body.add(childTree);
childTree.addStyleDependentName("root");
childTree.childNodeContainer.addStyleDependentName("root");
@@ -108,6 +110,9 @@ public class TreeConnector extends AbstractComponentConnector implements
getWidget().isMultiselect = "multi".equals(selectMode);
if (getWidget().isMultiselect) {
+ Roles.getTreeRole().setAriaMultiselectableProperty(
+ getWidget().getElement(), true);
+
if (BrowserInfo.get().isTouchDevice()) {
// Always use the simple mode for touch devices that do not have
// shift/ctrl keys (#8595)
@@ -116,6 +121,9 @@ public class TreeConnector extends AbstractComponentConnector implements
getWidget().multiSelectMode = MultiSelectMode.valueOf(uidl
.getStringAttribute("multiselectmode"));
}
+ } else {
+ Roles.getTreeRole().setAriaMultiselectableProperty(
+ getWidget().getElement(), false);
}
getWidget().selectedIds = uidl.getStringArrayVariableAsSet("selected");
@@ -169,7 +177,18 @@ public class TreeConnector extends AbstractComponentConnector implements
// expanding node happened server side
rootNode.setState(true, false);
}
- renderChildNodes(rootNode, (Iterator) uidl.getChildIterator());
+ String levelPropertyString = Roles.getTreeitemRole()
+ .getAriaLevelProperty(rootNode.getElement());
+ int levelProperty;
+ try {
+ levelProperty = Integer.valueOf(levelPropertyString);
+ } catch (NumberFormatException e) {
+ levelProperty = 1;
+ VConsole.error(e);
+ }
+
+ renderChildNodes(rootNode, (Iterator) uidl.getChildIterator(),
+ levelProperty + 1);
}
}
@@ -196,7 +215,10 @@ public class TreeConnector extends AbstractComponentConnector implements
}
- public void updateNodeFromUIDL(TreeNode treeNode, UIDL uidl) {
+ public void updateNodeFromUIDL(TreeNode treeNode, UIDL uidl, int level) {
+ Roles.getTreeitemRole().setAriaLevelProperty(treeNode.getElement(),
+ level);
+
String nodeKey = uidl.getStringAttribute("key");
treeNode.setText(uidl
.getStringAttribute(TreeConstants.ATTRIBUTE_NODE_CAPTION));
@@ -212,7 +234,8 @@ public class TreeConnector extends AbstractComponentConnector implements
if (uidl.getChildCount() == 0) {
treeNode.childNodeContainer.setVisible(false);
} else {
- renderChildNodes(treeNode, (Iterator) uidl.getChildIterator());
+ renderChildNodes(treeNode, (Iterator) uidl.getChildIterator(),
+ level + 1);
treeNode.childrenLoaded = true;
}
} else {
@@ -243,7 +266,7 @@ public class TreeConnector extends AbstractComponentConnector implements
.getStringAttribute(TreeConstants.ATTRIBUTE_NODE_ICON));
}
- void renderChildNodes(TreeNode containerNode, Iterator<UIDL> i) {
+ void renderChildNodes(TreeNode containerNode, Iterator<UIDL> i, int level) {
containerNode.childNodeContainer.clear();
containerNode.childNodeContainer.setVisible(true);
while (i.hasNext()) {
@@ -256,7 +279,7 @@ public class TreeConnector extends AbstractComponentConnector implements
}
final TreeNode childTree = getWidget().new TreeNode();
getConnection().getVTooltip().connectHandlersToWidget(childTree);
- updateNodeFromUIDL(childTree, childUidl);
+ updateNodeFromUIDL(childTree, childUidl, level);
containerNode.childNodeContainer.add(childTree);
if (!i.hasNext()) {
childTree
diff --git a/uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java b/uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java
index 126caa5985..4ffe7f806e 100644
--- a/uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java
+++ b/uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java
@@ -1,6 +1,5 @@
package com.vaadin.tests.layouts;
-
import java.util.ArrayList;
import java.util.List;