diff options
author | Teemu Suo-Anttila <tsuoanttila@users.noreply.github.com> | 2018-04-19 15:00:52 +0300 |
---|---|---|
committer | Ilia Motornyi <elmot@vaadin.com> | 2018-04-19 15:00:52 +0300 |
commit | 07c6456da8f15d279340188dc86d7424cee36cd0 (patch) | |
tree | abba54a5a0a2ab5b956bc568950ed414604c25d5 | |
parent | f0bb6f4e35cb4ed3f01ea8cadb521e79d623870a (diff) | |
download | vaadin-framework-07c6456da8f15d279340188dc86d7424cee36cd0.tar.gz vaadin-framework-07c6456da8f15d279340188dc86d7424cee36cd0.zip |
Fix for navigating in Grid using Tab
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, |