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
package com.vaadin.client.ui;
+import static com.vaadin.client.Util.isFocusedElementEditable;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
// 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
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) {
&& nativeEvent.getShiftKey()) {
nativeEvent.preventDefault();
}
+ if (nativeEvent.getEventTarget().cast() == topTabStop
+ && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
+ nativeEvent.preventDefault();
+ }
}
};
&& !nativeEvent.getShiftKey()) {
nativeEvent.preventDefault();
}
+ if (nativeEvent.getEventTarget().cast() == bottomTabStop
+ && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
+ nativeEvent.preventDefault();
+ }
}
};
}
@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()));
@Override
public void onBlur(BlurEvent event) {
- hasFocus = false;
-
if (client.hasEventListeners(this, EventId.BLUR)) {
client.updateVariable(id, EventId.BLUR, "", true);
}
@Override
public void onFocus(FocusEvent event) {
- hasFocus = true;
-
if (client.hasEventListeners(this, EventId.FOCUS)) {
client.updateVariable(id, EventId.FOCUS, "", true);
}
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;
@Override
public void buttonClick(ClickEvent event) {
Window window = new Window("Caption");
+ window.setId(MODAL_ID);
VerticalLayout layout = new VerticalLayout();
layout.setWidth("300px");
*/
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());
}
}