]> source.dussan.org Git - vaadin-framework.git/commitdiff
Fix for navigating in Grid using Tab
authorTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>
Thu, 19 Apr 2018 12:00:52 +0000 (15:00 +0300)
committerTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>
Fri, 20 Apr 2018 12:19:23 +0000 (15:19 +0300)
client/src/main/java/com/vaadin/client/WidgetUtil.java
client/src/main/java/com/vaadin/client/widgets/Escalator.java
uitest/src/main/java/com/vaadin/tests/components/grid/GridComponents.java
uitest/src/test/java/com/vaadin/tests/components/grid/GridComponentsTest.java

index 58604fe005096a6fa4e98f8618a04e711572dc61..2bbed2b92fb449cd5b3129c27cbca474105768dd 100644 (file)
@@ -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) {
index ced09dc705ca51d28d2ed154f38e6de4f3062c4f..785febc90c3cf01a3962d2b20fc01c4591dab33a 100644 (file)
@@ -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();
index d4b76a27227460f0bd8922ca9b989d742606fc02..0cd07640a061f241774848d5556a6ab1aaee37dc 100644 (file)
@@ -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);
     }
 }
index 8948bdfb68b2c044270f06689e51f3acc2ea9143..ced7fefdacb33e8bce35e24ee14c661e65289d2a 100644 (file)
@@ -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,