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;
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;
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();
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;
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;
}
+ @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,