From d6853c436e5acc0374cd73ce32d8e51c5b44f553 Mon Sep 17 00:00:00 2001 From: Guillermo Alvarez Date: Wed, 13 Aug 2014 14:40:38 +0300 Subject: [PATCH] Backspace in modal doesn't make browser navigation (#13180) 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 | 19 +++++ client/src/com/vaadin/client/ui/VWindow.java | 22 ++++-- .../window/BackspaceKeyWithModalOpened.java | 2 + .../BackspaceKeyWithModalOpenedTest.java | 78 +++++++++++++++---- 4 files changed, 97 insertions(+), 24 deletions(-) diff --git a/client/src/com/vaadin/client/Util.java b/client/src/com/vaadin/client/Util.java index 306f26b1af..1cdd8fb458 100644 --- a/client/src/com/vaadin/client/Util.java +++ b/client/src/com/vaadin/client/Util.java @@ -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 diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index 7223e4ac83..58e7a83012 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -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); } diff --git a/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java b/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java index 849d756ca9..7f23362efd 100644 --- a/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java +++ b/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpened.java @@ -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"); diff --git a/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java b/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java index f59c4bd762..e18b5b043a 100644 --- a/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java +++ b/uitest/src/com/vaadin/tests/components/window/BackspaceKeyWithModalOpenedTest.java @@ -15,40 +15,86 @@ */ 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()); } } -- 2.39.5