aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>2018-04-19 15:00:52 +0300
committerIlia Motornyi <elmot@vaadin.com>2018-04-19 15:00:52 +0300
commit07c6456da8f15d279340188dc86d7424cee36cd0 (patch)
treeabba54a5a0a2ab5b956bc568950ed414604c25d5
parentf0bb6f4e35cb4ed3f01ea8cadb521e79d623870a (diff)
downloadvaadin-framework-07c6456da8f15d279340188dc86d7424cee36cd0.tar.gz
vaadin-framework-07c6456da8f15d279340188dc86d7424cee36cd0.zip
Fix for navigating in Grid using Tab
-rw-r--r--client/src/main/java/com/vaadin/client/WidgetUtil.java4
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Escalator.java35
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/GridComponents.java12
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/grid/GridComponentsTest.java82
4 files changed, 128 insertions, 5 deletions
diff --git a/client/src/main/java/com/vaadin/client/WidgetUtil.java b/client/src/main/java/com/vaadin/client/WidgetUtil.java
index 58604fe005..2bbed2b92f 100644
--- a/client/src/main/java/com/vaadin/client/WidgetUtil.java
+++ b/client/src/main/java/com/vaadin/client/WidgetUtil.java
@@ -916,8 +916,10 @@ public class WidgetUtil {
EventListener eventListener = null;
while (eventListener == null && element != null) {
eventListener = Event.getEventListener(element);
- if (eventListener == null) {
+ if (eventListener == null
+ || !(eventListener instanceof Widget)) {
element = element.getParentElement();
+ eventListener = null;
}
}
if (eventListener instanceof Widget) {
diff --git a/client/src/main/java/com/vaadin/client/widgets/Escalator.java b/client/src/main/java/com/vaadin/client/widgets/Escalator.java
index ced09dc705..785febc90c 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Escalator.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Escalator.java
@@ -30,6 +30,7 @@ import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
+import java.util.stream.Stream;
import com.google.gwt.animation.client.Animation;
import com.google.gwt.animation.client.AnimationScheduler;
@@ -53,9 +54,11 @@ import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.dom.client.Touch;
+import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.logging.client.LogConfiguration;
import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.RootPanel;
@@ -5823,6 +5826,38 @@ public class Escalator extends Widget
tableWrapper = DivElement.as(DOM.createDiv());
+ Event.sinkEvents(tableWrapper, Event.ONSCROLL | Event.KEYEVENTS);
+
+ Event.setEventListener(tableWrapper, event -> {
+ if (event.getKeyCode() != KeyCodes.KEY_TAB) {
+ return;
+ }
+
+ boolean browserScroll = tableWrapper.getScrollLeft() != 0
+ || tableWrapper.getScrollTop() != 0;
+ boolean keyEvent = event.getType().startsWith("key");
+
+ if (browserScroll || keyEvent) {
+
+ // Browser is scrolling our div automatically, reset
+ tableWrapper.setScrollLeft(0);
+ tableWrapper.setScrollTop(0);
+
+ Element focused = WidgetUtil.getFocusedElement();
+ Stream.of(header, body, footer).forEach(container -> {
+ Cell cell = container.getCell(focused);
+ if (cell == null) {
+ return;
+ }
+
+ scrollToColumn(cell.getColumn(), ScrollDestination.ANY, 0);
+ if (container == body) {
+ scrollToRow(cell.getRow(), ScrollDestination.ANY, 0);
+ }
+ });
+ }
+ });
+
root.appendChild(tableWrapper);
table = DOM.createTable();
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridComponents.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridComponents.java
index d4b76a2722..0cd07640a0 100644
--- a/uitest/src/main/java/com/vaadin/tests/components/grid/GridComponents.java
+++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridComponents.java
@@ -76,7 +76,15 @@ public class GridComponents extends AbstractTestUIWithLog {
resetData.click();
addComponent(resetData);
- grid.appendHeaderRow().join("label", "textField", "button").setComponent(new TextField());
- grid.appendFooterRow().join("label", "textField", "button").setComponent(new TextField());
+ TextField headerField = new TextField();
+ TextField footerField = new TextField();
+
+ headerField.setId("headerField");
+ footerField.setId("footerField");
+
+ grid.appendHeaderRow().join("label", "textField", "button")
+ .setComponent(headerField);
+ grid.appendFooterRow().join("label", "textField", "button")
+ .setComponent(footerField);
}
}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/GridComponentsTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/GridComponentsTest.java
index 1420cfeefe..1c134f97e4 100644
--- a/uitest/src/test/java/com/vaadin/tests/components/grid/GridComponentsTest.java
+++ b/uitest/src/test/java/com/vaadin/tests/components/grid/GridComponentsTest.java
@@ -11,9 +11,9 @@ import java.util.stream.Stream;
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.annotations.RunLocally;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.GridElement;
import com.vaadin.testbench.elements.GridElement.GridCellElement;
@@ -21,7 +21,6 @@ import com.vaadin.testbench.elements.GridElement.GridRowElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.testbench.elements.TextFieldElement;
-import com.vaadin.testbench.parallel.Browser;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
@@ -185,6 +184,85 @@ public class GridComponentsTest extends MultiBrowserTest {
}
+ @Test
+ public void testTabNavigation() {
+ openTestURL();
+
+ GridElement grid = $(GridElement.class).first();
+ WebElement resizeHandle = grid.getHeaderCell(0, 0)
+ .findElement(By.cssSelector("div.v-grid-column-resize-handle"));
+
+ new Actions(getDriver()).moveToElement(resizeHandle).clickAndHold()
+ .moveByOffset(440, 0).release().perform();
+
+ // Scroll to end
+ grid.getCell(0, 2);
+ int scrollMax = getScrollLeft(grid);
+ assertTrue("Width of the grid too narrow, no scroll bar",
+ scrollMax > 0);
+
+ // Scroll to start
+ grid.getHorizontalScroller().scrollLeft(0);
+
+ assertEquals(
+ "Grid should scrolled to the start for this part of the test..",
+ 0, getScrollLeft(grid));
+
+ // Focus TextField in second column
+ WebElement textField = grid.getCell(0, 1)
+ .findElement(By.tagName("input"));
+ textField.click();
+
+ // Navigate to currently out of viewport Button
+ new Actions(getDriver()).sendKeys(Keys.TAB).perform();
+ assertEquals("Grid should be scrolled to the end", scrollMax,
+ getScrollLeft(grid));
+
+ // Navigate back to fully visible TextField
+ new Actions(getDriver()).sendKeys(Keys.chord(Keys.SHIFT, Keys.TAB))
+ .perform();
+ assertEquals(
+ "Grid should not scroll when focusing the text field again. ",
+ scrollMax, getScrollLeft(grid));
+
+ // Navigate to out of viewport TextField in Header
+ new Actions(getDriver()).sendKeys(Keys.chord(Keys.SHIFT, Keys.TAB))
+ .perform();
+ assertEquals("Focus should be in TextField in Header", "headerField",
+ getFocusedElement().getAttribute("id"));
+ assertEquals("Grid should've scrolled back to start.", 0,
+ getScrollLeft(grid));
+
+ // Focus button in last visible row of Grid
+ grid.getCell(6, 2).findElement(By.id("row_6")).click();
+
+ // Navigate to currently out of viewport TextField on Row 7
+ new Actions(getDriver()).sendKeys(Keys.TAB).perform();
+ int scrollTopRow7 = Integer
+ .parseInt(grid.getVerticalScroller().getAttribute("scrollTop"));
+ assertTrue("Grid should be scrolled to show row 7", scrollTopRow7 > 0);
+
+ // Navigate to currently out of viewport TextField on Row 8
+ new Actions(getDriver()).sendKeys(Keys.TAB, Keys.TAB).perform();
+ assertTrue("Grid should be scrolled to show row 7",
+ Integer.parseInt(grid.getVerticalScroller()
+ .getAttribute("scrollTop")) > scrollTopRow7);
+
+ // Focus button in last row of Grid
+ grid.getCell(999, 2).findElement(By.id("row_999")).click();
+ // Navigate to out of viewport TextField in Footer
+ new Actions(getDriver()).sendKeys(Keys.TAB).perform();
+ assertEquals("Focus should be in TextField in Footer", "footerField",
+ getFocusedElement().getAttribute("id"));
+ assertEquals("Grid should've scrolled horizontally back to start.", 0,
+ getScrollLeft(grid));
+ }
+
+ private int getScrollLeft(GridElement grid) {
+ return Integer.parseInt(
+ grid.getHorizontalScroller().getAttribute("scrollLeft"));
+ }
+
private void assertRowExists(int i, String string) {
GridRowElement row = $(GridElement.class).first().getRow(i);
assertEquals("Label text did not match", string,