summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKatriHaapalinna <haapalinnakatri@gmail.com>2019-04-08 14:31:17 +0300
committerSun Zhe <31067185+ZheSun88@users.noreply.github.com>2019-04-08 14:31:17 +0300
commit262863dbf6b33995d47bd9433e8f087d13a468ee (patch)
treefdb9d8fd7930d8b201e983b2cfe3541e74d66454
parent7a010de76ec67362d5c9d395c79ce3e22613469f (diff)
downloadvaadin-framework-262863dbf6b33995d47bd9433e8f087d13a468ee.tar.gz
vaadin-framework-262863dbf6b33995d47bd9433e8f087d13a468ee.zip
Use Enter and Space keys to fire Window header buttons (#11517) (#11534)
* Fixes 11517. Use ENTER and SPACE keys as shortcuts for header buttons * Merge branch 'master' into fix-11517 * Increase sleep time for test failing in validation * Merge branch 'master' into fix-11517
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VWindow.java15
-rw-r--r--client/src/main/java/com/vaadin/client/ui/window/WindowConnector.java22
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActions.java37
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActionsTest.java405
4 files changed, 474 insertions, 5 deletions
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 f7fc2ba6b8..e19a13c005 100644
--- a/client/src/main/java/com/vaadin/client/ui/VWindow.java
+++ b/client/src/main/java/com/vaadin/client/ui/VWindow.java
@@ -434,7 +434,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
DOM.appendChild(super.getContainerElement(), wrapper);
sinkEvents(Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.TOUCHEVENTS
- | Event.ONCLICK | Event.ONLOSECAPTURE);
+ | Event.ONCLICK | Event.ONLOSECAPTURE | Event.ONKEYUP);
setWidget(contentPanel);
@@ -1008,18 +1008,21 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
final int type = event.getTypeInt();
final Element target = DOM.eventGetTarget(event);
-
if (resizing || resizeBox == target) {
onResizeEvent(event);
bubble = false;
+ // if clicked or key ENTER or SPACE is pressed
} else if (isClosable() && target == closeBox) {
- if (type == Event.ONCLICK) {
+ if (type == Event.ONCLICK || (type == Event.ONKEYUP
+ && isKeyEnterOrSpace(event.getKeyCode()))) {
onCloseClick();
}
bubble = false;
} else if (target == maximizeRestoreBox) {
// handled in connector
- if (type != Event.ONCLICK) {
+ // if clicked or key ENTER or SPACE is pressed
+ if (type != Event.ONCLICK && !(type == Event.ONKEYUP
+ && isKeyEnterOrSpace(event.getKeyCode()))) {
bubble = false;
}
} else if (header.isOrHasChild(target) && !dragging) {
@@ -1571,4 +1574,8 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
return Document.get().getBody()
.hasClassName(MODAL_WINDOW_OPEN_CLASSNAME);
}
+
+ private boolean isKeyEnterOrSpace(int keyCode) {
+ return keyCode == KeyCodes.KEY_ENTER || keyCode == KeyCodes.KEY_SPACE;
+ }
}
diff --git a/client/src/main/java/com/vaadin/client/ui/window/WindowConnector.java b/client/src/main/java/com/vaadin/client/ui/window/WindowConnector.java
index feb34e502e..12ce828f47 100644
--- a/client/src/main/java/com/vaadin/client/ui/window/WindowConnector.java
+++ b/client/src/main/java/com/vaadin/client/ui/window/WindowConnector.java
@@ -29,6 +29,9 @@ import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.vaadin.client.ApplicationConnection;
@@ -67,7 +70,7 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
};
abstract class WindowEventHandler
- implements ClickHandler, DoubleClickHandler {
+ implements ClickHandler, DoubleClickHandler, KeyUpHandler {
}
private WindowEventHandler maximizeRestoreClickHandler = new WindowEventHandler() {
@@ -91,6 +94,18 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
onMaximizeRestore();
}
}
+
+ @Override
+ public void onKeyUp(KeyUpEvent event) {
+ final int keyCode = event.getNativeKeyCode();
+ final Element target = event.getNativeEvent().getEventTarget()
+ .cast();
+ // key ENTER or SPACE on maximize/restore box
+ if (target == getWidget().maximizeRestoreBox
+ && isKeyEnterOrSpace(keyCode)) {
+ onMaximizeRestore();
+ }
+ }
};
@Override
@@ -115,6 +130,7 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
window.addHandler(maximizeRestoreClickHandler, ClickEvent.getType());
window.addHandler(maximizeRestoreClickHandler,
DoubleClickEvent.getType());
+ window.addHandler(maximizeRestoreClickHandler, KeyUpEvent.getType());
window.setOwner(getConnection().getUIConnector().getWidget());
@@ -511,4 +527,8 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
getRpcProxy(WindowServerRpc.class).windowMoved(event.getNewX(),
event.getNewY());
}
+
+ private boolean isKeyEnterOrSpace(int keyCode) {
+ return keyCode == KeyCodes.KEY_ENTER || keyCode == KeyCodes.KEY_SPACE;
+ }
}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActions.java b/uitest/src/main/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActions.java
new file mode 100644
index 0000000000..4b5dc6de48
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActions.java
@@ -0,0 +1,37 @@
+package com.vaadin.tests.components.window;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+@Widgetset("com.vaadin.DefaultWidgetSet")
+public class WindowHeaderButtonKeyboardActions extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Button button = new Button("Open window");
+ button.setId("firstButton");
+
+ button.addClickListener(new Button.ClickListener() {
+ public void buttonClick(Button.ClickEvent event) {
+ Window window = new Window("WINDOW");
+ window.setContent(new Label("Inside window"));
+ window.setHeight("100px");
+ window.setId("testWindow");
+ window.addCloseListener(new Window.CloseListener() {
+ @Override
+ public void windowClose(Window.CloseEvent e) {
+
+ }
+ });
+ addWindow(window);
+ }
+ });
+ addComponent(button);
+
+ }
+
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActionsTest.java b/uitest/src/test/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActionsTest.java
new file mode 100644
index 0000000000..47ac64107d
--- /dev/null
+++ b/uitest/src/test/java/com/vaadin/tests/components/window/WindowHeaderButtonKeyboardActionsTest.java
@@ -0,0 +1,405 @@
+package com.vaadin.tests.components.window;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.openqa.selenium.JavascriptExecutor;
+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.WindowElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class WindowHeaderButtonKeyboardActionsTest extends MultiBrowserTest {
+
+ private static final String HEADER_CLASS = "v-window-header";
+ private static final String RESTORE_BOX_CLASS = "v-window-restorebox";
+ private static final String MAXIMIZE_BOX_CLASS = "v-window-maximizebox";
+ private static final String CLOSE_BOX_CLASS = "v-window-closebox";
+
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+ openTestURL();
+
+ // open window before each test case
+ waitForElementPresent(By.id("firstButton"));
+ WebElement button = findElement(By.id("firstButton"));
+ button.click();
+
+ waitForElementPresent(By.id("testWindow"));
+ }
+
+ /**
+ * Scenario: focus the close button of the opened window -> press ENTER key
+ * -> window should be closed
+ */
+ @Test
+ public void testCloseWindowWithEnter() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(CLOSE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+
+ assertTrue("Window's close button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.ENTER);
+ assertTrue("Window is not closed",
+ findElements(By.className("v-window")).size() == 0);
+ }
+
+ /**
+ * Scenario: focus the close button of the opened window -> press SPACE key
+ * -> window should be closed
+ */
+ @Test
+ public void testCloseWindowWithSpace() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(CLOSE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+
+ assertTrue("Window's close button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+ pressKeyAndWait(Keys.SPACE);
+
+ assertTrue("Window is not closed",
+ findElements(By.className("v-window")).size() == 0);
+ }
+
+ /**
+ * Scenario: focus close button of opened window -> press keys DELETE,
+ * ARROW_LEFT, and END -> window should remain open after all actions
+ */
+ @Test
+ public void testIncorrectKeyInputDoesntFireClose() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(CLOSE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+
+ assertTrue("Window's close button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.DELETE);
+ assertTrue(
+ "Window is closed by DELETE when close button is the focused element",
+ findElements(By.className("v-window")).size() > 0);
+
+ pressKeyAndWait(Keys.ARROW_LEFT);
+ assertTrue(
+ "Window is closed by ARROW_LEFT when close button is the focused element",
+ findElements(By.className("v-window")).size() > 0);
+
+ pressKeyAndWait(Keys.END);
+ assertTrue(
+ "Window is closed by END when close button is the focused element",
+ findElements(By.className("v-window")).size() > 0);
+ }
+
+ /**
+ * Scenario: close button of opened window is not focused -> press keys
+ * ENTER and SPACE -> window should remain open after all actions
+ */
+ @Test
+ public void testNonfocusedKeyDoesntCloseWindow() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(CLOSE_BOX_CLASS));
+ assertTrue("Window's close button is the focused element",
+ !closeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.ENTER);
+ assertTrue(
+ "Window is closed by ENTER when close button is not the focused element",
+ findElements(By.className("v-window")).size() > 0);
+
+ pressKeyAndWait(Keys.SPACE);
+ assertTrue(
+ "Window is closed by SPACE when close button is not the focused element",
+ findElements(By.className("v-window")).size() > 0);
+ }
+
+ /**
+ * Scenario: focus close button of opened window -> press keys TAB, and
+ * TAB+SHIFT in succession, shifting focus from and back to the button ->
+ * press ENTER key -> window should be closed
+ */
+ @Test
+ public void testShiftFocusAndCloseWindow() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(CLOSE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+ assertTrue("Window's close button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.TAB);
+ assertTrue("Window's close button is the focused element",
+ !closeButton.equals(driver.switchTo().activeElement()));
+ pressKeyAndWait(Keys.SHIFT, Keys.TAB);
+ assertTrue("Window's close button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.ENTER);
+ assertTrue(
+ "Window is not closed when focus is shifted back-and-forth",
+ findElements(By.className("v-window")).size() == 0);
+ }
+
+ /**
+ * Scenario: focus close button of opened window -> click close button with
+ * the mouse cursor -> window should be closed
+ */
+ @Test
+ public void testMouseClickClosesWindowOnFocus() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(CLOSE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+ assertTrue("Window's close button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+
+ // click button with mouse and wait
+ closeButton.click();
+ sleep(200);
+
+ assertTrue("Window is not closed when focused element is clicked",
+ findElements(By.className("v-window")).size() == 0);
+ }
+
+ // Tests for maximize-restore button
+
+ /**
+ * Scenario: focus the maximize button of the opened window -> press ENTER
+ * key -> window should be maximized
+ */
+ @Test
+ public void testMaximizeWindowWithEnter() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(MAXIMIZE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+
+ assertTrue("Window's maximize button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+ pressKeyAndWait(Keys.ENTER);
+
+ assertTrue("Window is not maximized", windowElement.isMaximized());
+ }
+
+ /**
+ * Scenario: focus the maximize button of the opened window -> press SPACE
+ * key -> window should be maximized
+ */
+ @Test
+ public void testMaximizeWindowWithSpace() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(MAXIMIZE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+
+ assertTrue("Window's maximize button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+ pressKeyAndWait(Keys.SPACE);
+
+ assertTrue("Window is not maximized", windowElement.isMaximized());
+ }
+
+ /**
+ * Scenario: focus maximize button of opened window -> press keys DELETE,
+ * ARROW_UP, and ADD -> window should remain open after all actions
+ */
+ @Test
+ public void testIncorrectKeyInputDoesntFireMaximize() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement maximizeButton = windowElement
+ .findElement(By.className(MAXIMIZE_BOX_CLASS));
+ setFocusToElementAndWait(maximizeButton);
+
+ assertTrue("Window's maximize button is not the focused element",
+ maximizeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.DELETE);
+ assertTrue(
+ "Window is maximized by DELETE when maximize button is the focused element",
+ !windowElement.isMaximized());
+
+ pressKeyAndWait(Keys.ARROW_UP);
+ assertTrue(
+ "Window is cmaximized by ARROW_UP when maximize button is the focused element",
+ !windowElement.isMaximized());
+
+ pressKeyAndWait(Keys.ADD);
+ assertTrue(
+ "Window is maximized by ADD when maximize button is the focused element",
+ !windowElement.isMaximized());
+ }
+
+ /**
+ * Scenario: close button of opened window is not focused -> press keys
+ * ENTER and SPACE -> window should remain non-maximized after all actions
+ */
+ @Test
+ public void testNonfocusedKeyDoesntMaximizeWindow() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement maximizeButton = windowElement
+ .findElement(By.className(MAXIMIZE_BOX_CLASS));
+ assertTrue("Window's close button is the focused element",
+ !maximizeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.ENTER);
+ assertTrue(
+ "Window is maximized by ENTER when maximize button is not the focused element",
+ !windowElement.isMaximized());
+
+ pressKeyAndWait(Keys.SPACE);
+ assertTrue(
+ "Window is maximized by SPACE when maximize button is not the focused element",
+ !windowElement.isMaximized());
+ }
+
+ /**
+ * Scenario: focus maximize button of opened window -> press keys TAB, and
+ * TAB+SHIFT in succession, shifting focus from and back to the button ->
+ * press ENTER key -> window should be maximized
+ */
+ @Test
+ public void testShiftFocusAndMaximizeWindow() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement maximizeButton = windowElement
+ .findElement(By.className(MAXIMIZE_BOX_CLASS));
+ setFocusToElementAndWait(maximizeButton);
+ assertTrue("Window's maximize button is not the focused element",
+ maximizeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.TAB);
+ assertTrue("Window's maximize button is the focused element",
+ !maximizeButton.equals(driver.switchTo().activeElement()));
+ pressKeyAndWait(Keys.SHIFT, Keys.TAB);
+ assertTrue("Window's maximize button is not the focused element",
+ maximizeButton.equals(driver.switchTo().activeElement()));
+
+ pressKeyAndWait(Keys.ENTER);
+ assertTrue(
+ "Window is not maximized when focus is shifted back-and-forth",
+ windowElement.isMaximized());
+ }
+
+ /**
+ * Scenario: focus maximize button of opened window -> click maximize button
+ * with mouse cursor -> window should be maximized
+ */
+ @Test
+ public void testMouseClickMaximizesWindowOnFocus() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement maximizeButton = windowElement
+ .findElement(By.className(MAXIMIZE_BOX_CLASS));
+ setFocusToElementAndWait(maximizeButton);
+ assertTrue("Window's maximize button is not the focused element",
+ maximizeButton.equals(driver.switchTo().activeElement()));
+
+ // click button with mouse and wait
+ maximizeButton.click();
+ sleep(100);
+
+ assertTrue("Window is not maximized when focused element is clicked",
+ windowElement.isMaximized());
+ }
+
+ /**
+ * Scenario: focus the maximize button of the opened window -> press ENTER
+ * key -> window should be maximized -> press ENTER key again -> window
+ * should be restored
+ */
+ @Test
+ public void testMaximizeAndRestoreWindowWithEnter() throws IOException {
+
+ assertTrue("Window is not open",
+ findElements(By.id("testWindow")).size() == 1);
+
+ WindowElement windowElement = $(WindowElement.class).first();
+ WebElement closeButton = windowElement
+ .findElement(By.className(MAXIMIZE_BOX_CLASS));
+ setFocusToElementAndWait(closeButton);
+
+ assertTrue("Window's maximize button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+ pressKeyAndWait(Keys.ENTER);
+
+ assertTrue("Window is not maximized", windowElement.isMaximized());
+
+ assertTrue("Window's maximize button is not the focused element",
+ closeButton.equals(driver.switchTo().activeElement()));
+ pressKeyAndWait(Keys.ENTER);
+
+ assertTrue("Window remains maximized", !windowElement.isMaximized());
+ }
+
+ protected void setFocusToElementAndWait(WebElement element) {
+ String elementId = element.getAttribute("id");
+
+ ((JavascriptExecutor) getDriver()).executeScript(
+ "document.getElementById('" + elementId + "').focus();",
+ element);
+ sleep(100);
+ }
+
+ protected void pressKeyAndWait(Keys... key) {
+ new Actions(driver).sendKeys(key).build().perform();
+ sleep(100);
+ }
+}