]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add a check for tab events trying to set focus outside a modal Window (#10655)
authorOlli Tietäväinen <ollit@vaadin.com>
Mon, 16 Apr 2018 14:56:16 +0000 (17:56 +0300)
committerIlia Motornyi <elmot@vaadin.com>
Mon, 16 Apr 2018 14:56:16 +0000 (17:56 +0300)
client/src/main/java/com/vaadin/client/ui/VWindow.java
uitest/src/main/java/com/vaadin/tests/components/window/ModalWindowFocus.java
uitest/src/test/java/com/vaadin/tests/components/window/ModalWindowFocusTest.java
uitest/src/test/java/com/vaadin/tests/components/window/ModalWindowRefocusTest.java [new file with mode: 0755]

index 69ffa8a89a59a867e9cb6f7e563614e6268ed296..746c4329975002df8995a1359cf33dce80c3f0d9 100644 (file)
@@ -178,9 +178,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
 
     private NativePreviewHandler topEventBlocker;
     private NativePreviewHandler bottomEventBlocker;
+    private NativePreviewHandler modalEventBlocker;
 
     private HandlerRegistration topBlockerRegistration;
     private HandlerRegistration bottomBlockerRegistration;
+    private HandlerRegistration modalBlockerRegistration;
 
     // Prevents leaving the window with the Tab key when true
     private boolean doTabStop;
@@ -264,6 +266,8 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
                     .addNativePreviewHandler(topEventBlocker);
             bottomBlockerRegistration = Event
                     .addNativePreviewHandler(bottomEventBlocker);
+            modalBlockerRegistration = Event
+                    .addNativePreviewHandler(modalEventBlocker);
         }
     }
 
@@ -274,6 +278,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
 
             bottomBlockerRegistration.removeHandler();
             bottomBlockerRegistration = null;
+
+            modalBlockerRegistration.removeHandler();
+            modalBlockerRegistration = null;
         }
     }
 
@@ -468,6 +475,25 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
                 nativeEvent.preventDefault();
             }
         };
+
+        // Handle modal window + tabbing when the focus is not inside the
+        // window (custom tab order or tabbing in from browser url bar)
+        modalEventBlocker = event -> {
+            if (!vaadinModality
+                    || getElement().isOrHasChild(WidgetUtil.getFocusedElement())
+                    || (getTopmostWindow() != VWindow.this)) {
+                return;
+            }
+
+            NativeEvent nativeEvent = event.getNativeEvent();
+            if (nativeEvent.getType().equals("keyup")
+                    && nativeEvent.getKeyCode() == KeyCodes.KEY_TAB) {
+                nativeEvent.preventDefault();
+                focus();
+
+            }
+        };
+
     }
 
     /**
index 38ce020b803c16790c97dee467b4871f865b24ef..20a6e4cfc716038392b78cae083e916ba6957e07 100644 (file)
@@ -16,6 +16,7 @@ public class ModalWindowFocus extends AbstractReindeerTestUI {
     protected void setup(VaadinRequest req) {
 
         Button button = new Button("Open windows");
+        button.setTabIndex(2);
         button.setId("firstButton");
         addComponent(button);
         button.addClickListener(event -> {
@@ -42,6 +43,7 @@ public class ModalWindowFocus extends AbstractReindeerTestUI {
         });
         Button button2 = new Button(
                 "Open unclosable and unresizable modal window");
+        button2.setTabIndex(1);
         addComponent(button2);
         button2.setId("modalWindowButton");
         button2.addClickListener(event -> {
index b5bd7bcdcc48c8a1ea3da474f3bfdd200a1fe136..4bece63be69e4aa238db2bf37b427e0d1a8e5ac2 100644 (file)
@@ -96,7 +96,7 @@ public class ModalWindowFocusTest extends MultiBrowserTest {
                 "this has been focused".equals(tfe.getValue()));
     }
 
-    private void pressKeyAndWait(Keys key) {
+    protected void pressKeyAndWait(Keys key) {
         new Actions(driver).sendKeys(key).build().perform();
         sleep(100);
     }
@@ -113,7 +113,6 @@ public class ModalWindowFocusTest extends MultiBrowserTest {
         assertEquals("true", ariaModal);
         String role = windowElement.getAttribute("role");
         assertEquals("dialog", role);
-
     }
 
 }
diff --git a/uitest/src/test/java/com/vaadin/tests/components/window/ModalWindowRefocusTest.java b/uitest/src/test/java/com/vaadin/tests/components/window/ModalWindowRefocusTest.java
new file mode 100755 (executable)
index 0000000..d09d3ce
--- /dev/null
@@ -0,0 +1,61 @@
+package com.vaadin.tests.components.window;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.TextFieldElement;
+import com.vaadin.testbench.parallel.Browser;
+
+/**
+ * Tests that a modal window is focused on creation and that on closing a window
+ * focus is given to underlying modal window
+ *
+ * @author Vaadin Ltd
+ */
+public class ModalWindowRefocusTest extends ModalWindowFocusTest {
+
+    @Override
+    public List<DesiredCapabilities> getBrowsersToTest() {
+        // Chrome doesn't support clicking on the modality curtain
+        return getBrowserCapabilities(Browser.IE11, Browser.EDGE,
+                Browser.FIREFOX);
+    }
+
+    @Override
+    protected Class<?> getUIClass() {
+        return ModalWindowFocus.class;
+    }
+
+    /**
+     * Open modal window -> click modality curtain to remove focus from Window
+     * -> press tab thrice so that focus goes into Window again and focuses the
+     * text field so that the focus event is fired.
+     */
+    @Test
+    public void testFocusOutsideModal() {
+        waitForElementPresent(By.id("modalWindowButton"));
+        WebElement button = findElement(By.id("modalWindowButton"));
+        button.click();
+        waitForElementPresent(By.id("focusfield"));
+        WebElement curtain = findElement(
+                org.openqa.selenium.By.className("v-window-modalitycurtain"));
+        curtain.click();
+
+        pressKeyAndWait(Keys.TAB);
+        pressKeyAndWait(Keys.TAB);
+        pressKeyAndWait(Keys.TAB);
+
+        TextFieldElement tfe = $(TextFieldElement.class).id("focusfield");
+        assertTrue("First TextField should have received focus",
+                "this has been focused".equals(tfe.getValue()));
+
+    }
+
+}