From: Aleksi Hietanen Date: Wed, 14 Dec 2016 13:36:14 +0000 (+0200) Subject: Make AbstractListing implement Focusable (#7965) X-Git-Tag: 8.0.0.alpha10~23 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=afcd95da1dba4abfd6158f38ab0a95755e2623e4;p=vaadin-framework.git Make AbstractListing implement Focusable (#7965) * Make AbstractListing implement Focusable Fixes vaadin/framework8-issues#552 * Add tests for other components that inherit from AbstractListing * Fix setTabIndex in NativeSelect, ListSelect, RadioButtonGroup Also adds a test for TwinColSelect. --- diff --git a/client/src/main/java/com/vaadin/client/ui/VNativeSelect.java b/client/src/main/java/com/vaadin/client/ui/VNativeSelect.java index 5005c79fbb..0ff6fe01f2 100644 --- a/client/src/main/java/com/vaadin/client/ui/VNativeSelect.java +++ b/client/src/main/java/com/vaadin/client/ui/VNativeSelect.java @@ -59,6 +59,16 @@ public class VNativeSelect extends FocusableFlowPanelComposite } } + /** + * Sets the tab index. + * + * @param tabIndex + * the tab index to set + */ + public void setTabIndex(int tabIndex) { + getListBox().setTabIndex(tabIndex); + } + /** * Gets the underlying ListBox widget that this widget wraps. * diff --git a/client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java b/client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java index 3e20b115e0..11aa21ebd9 100644 --- a/client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java @@ -51,4 +51,8 @@ public class ListSelectConnector extends AbstractMultiSelectConnector { getWidget().setReadOnly(isReadOnly()); } + @OnStateChange("tabIndex") + void updateTabIndex() { + getWidget().setTabIndex(getState().tabIndex); + } } diff --git a/client/src/main/java/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java b/client/src/main/java/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java index 18764f8b86..33c3170168 100644 --- a/client/src/main/java/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java @@ -77,7 +77,6 @@ public class NativeSelectConnector } @OnStateChange("readOnly") - @SuppressWarnings("deprecation") void updateWidgetReadOnly() { getWidget().getListBox().setEnabled(isEnabled() && !isReadOnly()); } @@ -87,6 +86,11 @@ public class NativeSelectConnector getWidget().setSelectedItem(getState().selectedItemKey); } + @OnStateChange("tabIndex") + void updateTabIndex() { + getWidget().setTabIndex(getState().tabIndex); + } + @Override public NativeSelectState getState() { return (NativeSelectState) super.getState(); diff --git a/client/src/main/java/com/vaadin/client/ui/optiongroup/RadioButtonGroupConnector.java b/client/src/main/java/com/vaadin/client/ui/optiongroup/RadioButtonGroupConnector.java index 13e39677d3..4331273b1e 100644 --- a/client/src/main/java/com/vaadin/client/ui/optiongroup/RadioButtonGroupConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/optiongroup/RadioButtonGroupConnector.java @@ -61,6 +61,7 @@ public class RadioButtonGroupConnector @Override public void onStateChanged(StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); + getWidget().setTabIndex(getState().tabIndex); getWidget().client = getConnection(); } diff --git a/client/src/main/java/com/vaadin/client/ui/twincolselect/TwinColSelectConnector.java b/client/src/main/java/com/vaadin/client/ui/twincolselect/TwinColSelectConnector.java index 304f5dcab0..8be2c0da15 100644 --- a/client/src/main/java/com/vaadin/client/ui/twincolselect/TwinColSelectConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/twincolselect/TwinColSelectConnector.java @@ -70,6 +70,11 @@ public class TwinColSelectConnector extends AbstractMultiSelectConnector getWidget().setReadOnly(isReadOnly()); } + @OnStateChange("tabIndex") + void updateTabIndex() { + getWidget().setTabIndex(getState().tabIndex); + } + @Override public void layoutVertically() { if (isUndefinedHeight()) { diff --git a/server/src/main/java/com/vaadin/ui/AbstractListing.java b/server/src/main/java/com/vaadin/ui/AbstractListing.java index 0fa18bddbc..95ffef6ee8 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractListing.java +++ b/server/src/main/java/com/vaadin/ui/AbstractListing.java @@ -31,6 +31,7 @@ import com.vaadin.server.data.DataProvider; import com.vaadin.server.data.Query; import com.vaadin.shared.extension.abstractlisting.AbstractListingExtensionState; import com.vaadin.shared.ui.abstractlisting.AbstractListingState; +import com.vaadin.ui.Component.Focusable; import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignContext; import com.vaadin.ui.declarative.DesignException; @@ -51,7 +52,8 @@ import com.vaadin.ui.declarative.DesignFormatter; * * @see Listing */ -public abstract class AbstractListing extends AbstractComponent { +public abstract class AbstractListing extends AbstractComponent + implements Focusable { /** * The item icon caption provider. */ @@ -497,4 +499,19 @@ public abstract class AbstractListing extends AbstractComponent { protected AbstractListingState getState(boolean markAsDirty) { return (AbstractListingState) super.getState(markAsDirty); } + + @Override + public void focus() { + super.focus(); + } + + @Override + public int getTabIndex() { + return getState(false).tabIndex; + } + + @Override + public void setTabIndex(int tabIndex) { + getState().tabIndex = tabIndex; + } } diff --git a/server/src/main/java/com/vaadin/ui/Component.java b/server/src/main/java/com/vaadin/ui/Component.java index 5ffdf600b3..7392a29637 100644 --- a/server/src/main/java/com/vaadin/ui/Component.java +++ b/server/src/main/java/com/vaadin/ui/Component.java @@ -1015,8 +1015,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable { *

* Notice that this interface does not provide an accessor that would * allow finding out the currently focused component. Focus information - * can be acquired for some (but not all) {@code LegacyField} components - * through the {@link com.vaadin.event.FieldEvents.FocusListener} and + * can be acquired for some (but not all) components through the + * {@link com.vaadin.event.FieldEvents.FocusListener} and * {@link com.vaadin.event.FieldEvents.BlurListener} interfaces. *

* diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java index a72a055e59..2d0c893ddf 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java @@ -438,6 +438,12 @@ public class GridBasics extends AbstractTestUIWithLog { enableItem.setChecked(true); createSelectionMenu(stateMenu); + + stateMenu.addItem("Set focus", item -> grid.focus()); + MenuItem tabIndexMenu = stateMenu.addItem("Tab index", null); + addGridMethodMenu(tabIndexMenu, "0", 0, grid::setTabIndex); + addGridMethodMenu(tabIndexMenu, "-1", -1, grid::setTabIndex); + addGridMethodMenu(tabIndexMenu, "10", 10, grid::setTabIndex); } private void createRowStyleMenu(MenuItem rowStyleMenu) { diff --git a/uitest/src/test/java/com/vaadin/tests/focusable/AbstractFocusableComponentTest.java b/uitest/src/test/java/com/vaadin/tests/focusable/AbstractFocusableComponentTest.java new file mode 100644 index 0000000000..61d22ae647 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/focusable/AbstractFocusableComponentTest.java @@ -0,0 +1,45 @@ +package com.vaadin.tests.focusable; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public abstract class AbstractFocusableComponentTest extends MultiBrowserTest { + + @Before + public void setUp() { + openTestURL(); + } + + @Test + public void testProgrammaticFocus() { + selectMenuPath("Component", "State", "Set focus"); + assertTrue("Component should be focused", isFocused()); + } + + @Test + public void testTabIndex() { + assertEquals("0", getTabIndex()); + + selectMenuPath("Component", "State", "Tab index", "-1"); + assertEquals("-1", getTabIndex()); + + selectMenuPath("Component", "State", "Tab index", "10"); + assertEquals("10", getTabIndex()); + } + + protected String getTabIndex() { + return getFocusElement().getAttribute("tabindex"); + } + + protected boolean isFocused() { + return getFocusElement().equals(getDriver().switchTo().activeElement()); + } + + protected abstract WebElement getFocusElement(); +} diff --git a/uitest/src/test/java/com/vaadin/tests/focusable/CheckBoxGroupFocusableTest.java b/uitest/src/test/java/com/vaadin/tests/focusable/CheckBoxGroupFocusableTest.java new file mode 100644 index 0000000000..a99b3be9fe --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/focusable/CheckBoxGroupFocusableTest.java @@ -0,0 +1,19 @@ +package com.vaadin.tests.focusable; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.components.checkbox.CheckBoxGroupTestUI; + +public class CheckBoxGroupFocusableTest extends AbstractFocusableComponentTest { + + @Override + protected Class getUIClass() { + return CheckBoxGroupTestUI.class; + } + + @Override + protected WebElement getFocusElement() { + return findElement(By.xpath("//input[@type='checkbox']")); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/focusable/GridFocusableTest.java b/uitest/src/test/java/com/vaadin/tests/focusable/GridFocusableTest.java new file mode 100644 index 0000000000..96a19902eb --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/focusable/GridFocusableTest.java @@ -0,0 +1,28 @@ +package com.vaadin.tests.focusable; + +import com.vaadin.testbench.customelements.GridElement; +import com.vaadin.testbench.elements.GridElement.GridCellElement; +import com.vaadin.tests.components.grid.basics.GridBasics; + +public class GridFocusableTest extends AbstractFocusableComponentTest { + + @Override + protected Class getUIClass() { + return GridBasics.class; + } + + @Override + protected String getTabIndex() { + return $(GridElement.class).first().getAttribute("tabindex"); + } + + @Override + protected boolean isFocused() { + return getFocusElement().isFocused(); + } + + @Override + protected GridCellElement getFocusElement() { + return $(GridElement.class).first().getCell(0, 0); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/focusable/ListSelectFocusableTest.java b/uitest/src/test/java/com/vaadin/tests/focusable/ListSelectFocusableTest.java new file mode 100644 index 0000000000..5a4fc4f870 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/focusable/ListSelectFocusableTest.java @@ -0,0 +1,19 @@ +package com.vaadin.tests.focusable; + +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.components.listselect.ListSelectTestUI; + +public class ListSelectFocusableTest extends AbstractFocusableComponentTest { + + @Override + protected Class getUIClass() { + return ListSelectTestUI.class; + } + + @Override + protected WebElement getFocusElement() { + return findElement(By.className("v-select-select")); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/focusable/NativeSelectFocusableTest.java b/uitest/src/test/java/com/vaadin/tests/focusable/NativeSelectFocusableTest.java new file mode 100644 index 0000000000..530972b8a6 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/focusable/NativeSelectFocusableTest.java @@ -0,0 +1,19 @@ +package com.vaadin.tests.focusable; + +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.components.nativeselect.NativeSelects; + +public class NativeSelectFocusableTest extends AbstractFocusableComponentTest { + + @Override + protected Class getUIClass() { + return NativeSelects.class; + } + + @Override + protected WebElement getFocusElement() { + return findElement(By.className("v-select-select")); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/focusable/RadioButtonGroupFocusableTest.java b/uitest/src/test/java/com/vaadin/tests/focusable/RadioButtonGroupFocusableTest.java new file mode 100644 index 0000000000..c84d606ac3 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/focusable/RadioButtonGroupFocusableTest.java @@ -0,0 +1,19 @@ +package com.vaadin.tests.focusable; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.components.radiobutton.RadioButtonGroupTestUI; + +public class RadioButtonGroupFocusableTest extends AbstractFocusableComponentTest { + + @Override + protected Class getUIClass() { + return RadioButtonGroupTestUI.class; + } + + @Override + protected WebElement getFocusElement() { + return findElement(By.xpath("//input[@type='radio']")); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/focusable/TwinColSelectFocusableTest.java b/uitest/src/test/java/com/vaadin/tests/focusable/TwinColSelectFocusableTest.java new file mode 100644 index 0000000000..826647129a --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/focusable/TwinColSelectFocusableTest.java @@ -0,0 +1,20 @@ +package com.vaadin.tests.focusable; + +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.components.twincolselect.TwinColSelectTestUI; + +public class TwinColSelectFocusableTest + extends AbstractFocusableComponentTest { + + @Override + protected Class getUIClass() { + return TwinColSelectTestUI.class; + } + + @Override + protected WebElement getFocusElement() { + return findElement(By.className("v-select-twincol-options")); + } +}