]> source.dussan.org Git - vaadin-framework.git/commitdiff
Backspace in modal doesn't make browser navigation (#13180)
authorGuillermo Alvarez <guillermo@vaadin.com>
Wed, 13 Aug 2014 11:40:38 +0000 (14:40 +0300)
committerVaadin Code Review <review@vaadin.com>
Thu, 4 Sep 2014 13:16:03 +0000 (13:16 +0000)
In a modal window if focus is not in an editable component
the backspace default action is prevented.
Also when focus is on bottom or top components.

Change-Id: I53f0922e5ddff142e2d540be52e70c7d23d1b585

client/src/com/vaadin/client/Util.java
client/src/com/vaadin/client/ui/VWindow.java
uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java
uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java

index 306f26b1afe86834eb510940deb2309c774715d1..1cdd8fb458e3631d43dad924502a02da4ae689f8 100644 (file)
@@ -1261,6 +1261,25 @@ public class Util {
         return getFocusedElement();
     }
 
+    /**
+     * Gets currently focused element and checks if it's editable
+     * 
+     * @return true if focused element is editable
+     */
+    public static boolean isFocusedElementEditable() {
+        Element focusedElement = Util.getFocusedElement();
+        if (focusedElement != null) {
+            String tagName = focusedElement.getTagName();
+            String contenteditable = focusedElement
+                    .getAttribute("contenteditable");
+
+            return "textarea".equalsIgnoreCase(tagName)
+                    || "input".equalsIgnoreCase(tagName)
+                    || "true".equalsIgnoreCase(contenteditable);
+        }
+        return false;
+    }
+
     /**
      * Kind of stronger version of isAttached(). In addition to std isAttached,
      * this method checks that this widget nor any of its parents is hidden. Can
index 7223e4ac83976b91f4ef6b726a4ad0afee89790e..58e7a8301204bae2e9f520f54984309017760af0 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.vaadin.client.ui;
 
+import static com.vaadin.client.Util.isFocusedElementEditable;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -178,8 +180,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
     // Prevents leaving the window with the Tab key when true
     private boolean doTabStop;
 
-    private boolean hasFocus;
-
     /**
      * If centered (via UIDL), the window should stay in the centered -mode
      * until a position is received from the server, or the user moves or
@@ -420,6 +420,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
                 Id.of(headerText));
 
         // Handlers to Prevent tab to leave the window
+        // and backspace to cause browser navigation
         topEventBlocker = new NativePreviewHandler() {
             @Override
             public void onPreviewNativeEvent(NativePreviewEvent event) {
@@ -429,6 +430,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
                         && nativeEvent.getShiftKey()) {
                     nativeEvent.preventDefault();
                 }
+                if (nativeEvent.getEventTarget().cast() == topTabStop
+                        && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
+                    nativeEvent.preventDefault();
+                }
             }
         };
 
@@ -441,6 +446,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
                         && !nativeEvent.getShiftKey()) {
                     nativeEvent.preventDefault();
                 }
+                if (nativeEvent.getEventTarget().cast() == bottomTabStop
+                        && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
+                    nativeEvent.preventDefault();
+                }
             }
         };
     }
@@ -1302,10 +1311,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
 
     @Override
     public void onKeyDown(KeyDownEvent event) {
-        if (hasFocus && event.getNativeKeyCode() == KeyCodes.KEY_BACKSPACE) {
+        if (vaadinModality
+                && event.getNativeKeyCode() == KeyCodes.KEY_BACKSPACE
+                && !isFocusedElementEditable()) {
             event.preventDefault();
         }
-
         if (shortcutHandler != null) {
             shortcutHandler
                     .handleKeyboardEvent(Event.as(event.getNativeEvent()));
@@ -1322,8 +1332,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
 
     @Override
     public void onBlur(BlurEvent event) {
-        hasFocus = false;
-
         if (client.hasEventListeners(this, EventId.BLUR)) {
             client.updateVariable(id, EventId.BLUR, "", true);
         }
@@ -1331,8 +1339,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
 
     @Override
     public void onFocus(FocusEvent event) {
-        hasFocus = true;
-
         if (client.hasEventListeners(this, EventId.FOCUS)) {
             client.updateVariable(id, EventId.FOCUS, "", true);
         }
index 849d756ca96d414ca866537406f89f6c4ab604fd..7f23362efd783f83830909d45c8897a53ca97d9a 100644 (file)
@@ -36,6 +36,7 @@ public class BackspaceKeyWithModalOpened extends AbstractTestUI {
     public static final String BTN_NEXT_ID = "btn_next";
     public static final String BTN_OPEN_MODAL_ID = "btn_open_modal";
     public static final String TEXT_FIELD_IN_MODAL = "txt_in_modal";
+    public static final String MODAL_ID = "modal_window";
 
     private Navigator navigator;
 
@@ -66,6 +67,7 @@ public class BackspaceKeyWithModalOpened extends AbstractTestUI {
                         @Override
                         public void buttonClick(ClickEvent event) {
                             Window window = new Window("Caption");
+                            window.setId(MODAL_ID);
 
                             VerticalLayout layout = new VerticalLayout();
                             layout.setWidth("300px");
index f59c4bd762c494e8358435c4b9033017030b9a06..e18b5b043a2b8aa2c4227f028ef7c4ea17cb91a6 100644 (file)
  */
 package com.vaadin.tests.components.window;
 
+import static com.vaadin.tests.components.window.BackspaceKeyWithModalOpened.BTN_NEXT_ID;
+import static com.vaadin.tests.components.window.BackspaceKeyWithModalOpened.BTN_OPEN_MODAL_ID;
+import static org.junit.Assert.assertEquals;
+import static org.openqa.selenium.Keys.BACK_SPACE;
+import static org.openqa.selenium.Keys.TAB;
+
+import org.junit.Before;
 import org.junit.Test;
-import org.openqa.selenium.Keys;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.interactions.Actions;
 
 import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.TextFieldElement;
 import com.vaadin.tests.tb3.MultiBrowserTest;
 
 public class BackspaceKeyWithModalOpenedTest extends MultiBrowserTest {
 
+    /**
+     * Tests that backspace in textfield does work
+     */
     @Test
-    public void testWindowScrollbars() throws Exception {
-        openTestURL();
+    public void testWithFocusOnInput() throws Exception {
 
-        WebElement nextButton = driver.findElement(By
-                .id(BackspaceKeyWithModalOpened.BTN_NEXT_ID));
+        TextFieldElement textField = getTextField();
 
-        nextButton.click();
+        // Try to delete characters in a text field.
+        textField.sendKeys("textt");
+        textField.sendKeys(BACK_SPACE);
+        assertEquals("text", textField.getValue());
+        checkButtonsCount();
+    }
 
-        WebElement openModalButton = driver.findElement(By
-                .id(BackspaceKeyWithModalOpened.BTN_OPEN_MODAL_ID));
+    /**
+     * Tests that backspace action outside textfield is prevented
+     */
+    @Test
+    public void testWithFocusOnModal() throws Exception {
+        // Try to send back actions to the browser.
+        new Actions(getDriver()).sendKeys(BACK_SPACE).perform();
 
-        openModalButton.click();
+        checkButtonsCount();
+    }
+
+    /**
+     * Tests that backspace action in the bottom component is prevented
+     */
+    @Test
+    public void testWithFocusOnBottom() throws Exception {
+        TextFieldElement textField = getTextField();
+
+        // tab in last field set focus on bottom component
+        textField.sendKeys(TAB);
 
         // Try to send back actions to the browser.
-        new Actions(getDriver()).sendKeys(Keys.BACK_SPACE).perform();
+        new Actions(getDriver()).sendKeys(BACK_SPACE).perform();
 
-        WebElement textField = driver.findElement(By
-                .id(BackspaceKeyWithModalOpened.TEXT_FIELD_IN_MODAL));
+        checkButtonsCount();
+    }
 
-        // Try to delete characters in a text field.
-        textField.sendKeys("textt");
-        textField.sendKeys(Keys.BACK_SPACE);
+    private TextFieldElement getTextField() {
+        return $(TextFieldElement.class).first();
+    }
+
+    @Before
+    public void testSetup() {
+        openTestURL();
+        WebElement nextButton = driver.findElement(By.id(BTN_NEXT_ID));
+        nextButton.click();
+
+        WebElement openModalButton = driver.findElement(By
+                .id(BTN_OPEN_MODAL_ID));
+        openModalButton.click();
+    }
 
-        compareScreen(getScreenshotBaseName());
+    /**
+     * If there was a back navigation due to the backspace the next button
+     * would've been added again
+     */
+    private void checkButtonsCount() {
+        assertEquals(2, $(ButtonElement.class).all().size());
     }
 }