aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Török <31210544+torok-peter@users.noreply.github.com>2017-11-07 11:39:11 +0200
committerTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>2017-11-27 10:43:45 +0200
commit61c8896a88bc09d749f070b8267c679de8b3c0e4 (patch)
tree9d588708f52972a485b3650a2d18ac251d642e74
parentef4a0bceb1d7d6cfd642bc1bd3a729b10b1584b3 (diff)
downloadvaadin-framework-61c8896a88bc09d749f070b8267c679de8b3c0e4.tar.gz
vaadin-framework-61c8896a88bc09d749f070b8267c679de8b3c0e4.zip
Make focus circulate in modal dialog to improve accessibility (#10260)
-rw-r--r--client/src/main/java/com/vaadin/client/ui/FocusUtil.java23
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VWindow.java56
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java8
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/window/ModalWindowFocus.java2
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java8
5 files changed, 67 insertions, 30 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/FocusUtil.java b/client/src/main/java/com/vaadin/client/ui/FocusUtil.java
index 49cd9284c1..0a510f2b65 100644
--- a/client/src/main/java/com/vaadin/client/ui/FocusUtil.java
+++ b/client/src/main/java/com/vaadin/client/ui/FocusUtil.java
@@ -15,6 +15,7 @@
*/
package com.vaadin.client.ui;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.Widget;
@@ -95,4 +96,26 @@ public class FocusUtil {
return focusable.getElement().getTabIndex();
}
+
+ public static native Element[] getFocusableChildren(Element parent)
+ /*-{
+ var focusableChildren = parent.querySelectorAll('[type][tabindex]:not([tabindex="-1"]), [role=button][tabindex]:not([tabindex="-1"])');
+ return focusableChildren;
+ }-*/;
+
+ public static void focusOnFirstFocusableElement(Element parent)
+ {
+ Element[] focusableChildren = getFocusableChildren(parent);
+ if (focusableChildren.length > 0) {
+ focusableChildren[0].focus();
+ }
+ }
+
+ public static void focusOnLastFocusableElement(Element parent)
+ {
+ Element[] focusableChildren = getFocusableChildren(parent);
+ if (focusableChildren.length > 0) {
+ focusableChildren[focusableChildren.length - 1].focus();
+ }
+ }
}
diff --git a/client/src/main/java/com/vaadin/client/ui/VWindow.java b/client/src/main/java/com/vaadin/client/ui/VWindow.java
index 8b907f9a4a..76def668f9 100644
--- a/client/src/main/java/com/vaadin/client/ui/VWindow.java
+++ b/client/src/main/java/com/vaadin/client/ui/VWindow.java
@@ -439,37 +439,39 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
Roles.getDialogRole().setAriaLabelledbyProperty(getElement(),
Id.of(headerText));
- // Handlers to Prevent tab to leave the window
+ // Handlers to Prevent tab to leave the window (by circulating focus)
// and backspace to cause browser navigation
- topEventBlocker = new NativePreviewHandler() {
- @Override
- public void onPreviewNativeEvent(NativePreviewEvent event) {
- NativeEvent nativeEvent = event.getNativeEvent();
- if (nativeEvent.getEventTarget().cast() == topTabStop
- && nativeEvent.getKeyCode() == KeyCodes.KEY_TAB
- && nativeEvent.getShiftKey()) {
- nativeEvent.preventDefault();
- }
- if (nativeEvent.getEventTarget().cast() == topTabStop
- && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
- nativeEvent.preventDefault();
- }
+ topEventBlocker = event -> {
+ if (!getElement().isOrHasChild(WidgetUtil.getFocusedElement())) {
+ return;
+ }
+ NativeEvent nativeEvent = event.getNativeEvent();
+ if (nativeEvent.getEventTarget().cast() == topTabStop
+ && nativeEvent.getKeyCode() == KeyCodes.KEY_TAB
+ && nativeEvent.getShiftKey()) {
+ nativeEvent.preventDefault();
+ FocusUtil.focusOnLastFocusableElement(this.getElement());
+ }
+ if (nativeEvent.getEventTarget().cast() == topTabStop
+ && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
+ nativeEvent.preventDefault();
}
};
- bottomEventBlocker = new NativePreviewHandler() {
- @Override
- public void onPreviewNativeEvent(NativePreviewEvent event) {
- NativeEvent nativeEvent = event.getNativeEvent();
- if (nativeEvent.getEventTarget().cast() == bottomTabStop
- && nativeEvent.getKeyCode() == KeyCodes.KEY_TAB
- && !nativeEvent.getShiftKey()) {
- nativeEvent.preventDefault();
- }
- if (nativeEvent.getEventTarget().cast() == bottomTabStop
- && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
- nativeEvent.preventDefault();
- }
+ bottomEventBlocker = event -> {
+ if (!getElement().isOrHasChild(WidgetUtil.getFocusedElement())) {
+ return;
+ }
+ NativeEvent nativeEvent = event.getNativeEvent();
+ if (nativeEvent.getEventTarget().cast() == bottomTabStop
+ && nativeEvent.getKeyCode() == KeyCodes.KEY_TAB
+ && !nativeEvent.getShiftKey()) {
+ nativeEvent.preventDefault();
+ FocusUtil.focusOnFirstFocusableElement(this.getElement());
+ }
+ if (nativeEvent.getEventTarget().cast() == bottomTabStop
+ && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
+ nativeEvent.preventDefault();
}
};
}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java b/uitest/src/main/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java
index f25e4e9349..c53a77b223 100644
--- a/uitest/src/main/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java
+++ b/uitest/src/main/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java
@@ -15,11 +15,13 @@
*/
package com.vaadin.tests.components.window;
+import com.vaadin.annotations.Theme;
+import com.vaadin.annotations.Widgetset;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.server.VaadinRequest;
-import com.vaadin.tests.components.AbstractReindeerTestUI;
+import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Label;
@@ -28,7 +30,9 @@ import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
-public class BackspaceKeyWithModalOpened extends AbstractReindeerTestUI {
+@Theme("valo")
+@Widgetset("com.vaadin.DefaultWidgetSet")
+public class BackspaceKeyWithModalOpened extends AbstractTestUI {
private static final String DEFAULT_VIEW_ID = "";
private static final String SECOND_VIEW_ID = "second";
diff --git a/uitest/src/main/java/com/vaadin/tests/components/window/ModalWindowFocus.java b/uitest/src/main/java/com/vaadin/tests/components/window/ModalWindowFocus.java
index 85c60d3738..65e4e26215 100644
--- a/uitest/src/main/java/com/vaadin/tests/components/window/ModalWindowFocus.java
+++ b/uitest/src/main/java/com/vaadin/tests/components/window/ModalWindowFocus.java
@@ -15,6 +15,7 @@
*/
package com.vaadin.tests.components.window;
+import com.vaadin.annotations.Widgetset;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractReindeerTestUI;
import com.vaadin.ui.Button;
@@ -22,6 +23,7 @@ import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Window;
+@Widgetset("com.vaadin.DefaultWidgetSet")
public class ModalWindowFocus extends AbstractReindeerTestUI {
@Override
diff --git a/uitest/src/test/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java b/uitest/src/test/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java
index ce015bab9d..b9199e0aec 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java
@@ -22,6 +22,7 @@ import static org.openqa.selenium.Keys.BACK_SPACE;
import static org.openqa.selenium.Keys.TAB;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
@@ -60,9 +61,14 @@ public class BackspaceKeyWithModalOpenedTest extends MultiBrowserTest {
}
/**
- * Tests that backspace action in the bottom component is prevented
+ * Tests that backspace action in the bottom component is prevented.
+ *
+ * Ignored because the fix to #8855 stops the top and bottom components
+ * from functioning as focus traps. Meanwhile, navigation with Backspace
+ * is not anymore supported by reasonable browsers.
*/
@Test
+ @Ignore
public void testWithFocusOnBottom() throws Exception {
TextFieldElement textField = getTextField();