]> source.dussan.org Git - vaadin-framework.git/commitdiff
Make AbstractListing implement Focusable (#7965)
authorAleksi Hietanen <aleksi@vaadin.com>
Wed, 14 Dec 2016 13:36:14 +0000 (15:36 +0200)
committerPekka Hyvönen <pekka@vaadin.com>
Wed, 14 Dec 2016 13:36:14 +0000 (15:36 +0200)
* 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.

15 files changed:
client/src/main/java/com/vaadin/client/ui/VNativeSelect.java
client/src/main/java/com/vaadin/client/ui/listselect/ListSelectConnector.java
client/src/main/java/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
client/src/main/java/com/vaadin/client/ui/optiongroup/RadioButtonGroupConnector.java
client/src/main/java/com/vaadin/client/ui/twincolselect/TwinColSelectConnector.java
server/src/main/java/com/vaadin/ui/AbstractListing.java
server/src/main/java/com/vaadin/ui/Component.java
uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
uitest/src/test/java/com/vaadin/tests/focusable/AbstractFocusableComponentTest.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/focusable/CheckBoxGroupFocusableTest.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/focusable/GridFocusableTest.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/focusable/ListSelectFocusableTest.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/focusable/NativeSelectFocusableTest.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/focusable/RadioButtonGroupFocusableTest.java [new file with mode: 0644]
uitest/src/test/java/com/vaadin/tests/focusable/TwinColSelectFocusableTest.java [new file with mode: 0644]

index 5005c79fbb7e0b08a908d891e4ad2f9d64105953..0ff6fe01f2eca32a389e15b5b3b0966b45e6c73a 100644 (file)
@@ -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.
      *
index 3e20b115e0eab561c3cb4fdfeafc371432f35666..11aa21ebd971cce6396fee3289978eedd317aa3a 100644 (file)
@@ -51,4 +51,8 @@ public class ListSelectConnector extends AbstractMultiSelectConnector {
         getWidget().setReadOnly(isReadOnly());
     }
 
+    @OnStateChange("tabIndex")
+    void updateTabIndex() {
+        getWidget().setTabIndex(getState().tabIndex);
+    }
 }
index 18764f8b86ffbe0a838c6f25091e1726f12a78b6..33c3170168dd238c995599f2b7cdad11531a3852 100644 (file)
@@ -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();
index 13e39677d3d96d7fab876fe7af61a5728b6a683a..4331273b1e84ad5c8e6c08d05dded14e21532e85 100644 (file)
@@ -61,6 +61,7 @@ public class RadioButtonGroupConnector
     @Override
     public void onStateChanged(StateChangeEvent stateChangeEvent) {
         super.onStateChanged(stateChangeEvent);
+        getWidget().setTabIndex(getState().tabIndex);
         getWidget().client = getConnection();
     }
 
index 304f5dcab09fab327b968c93b4d22af299ea936d..8be2c0da15f7b7f79fc0ee7400c4b8d5e33caf88 100644 (file)
@@ -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()) {
index 0fa18bddbcd12da1341290cbef0fcacb0f7a39c3..95ffef6ee81f8bae555b71eb4771157dc367f031 100644 (file)
@@ -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<T> extends AbstractComponent {
+public abstract class AbstractListing<T> extends AbstractComponent
+        implements Focusable {
     /**
      * The item icon caption provider.
      */
@@ -497,4 +499,19 @@ public abstract class AbstractListing<T> 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;
+    }
 }
index 5ffdf600b3b74859672a3b71bf8f2e65b1eba313..7392a29637f698e4185a3e7a3a18750c7b4d9078 100644 (file)
@@ -1015,8 +1015,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
          * <p>
          * 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.
          * </p>
          *
index a72a055e59b1da5c7fa8738ced068b7146e498c1..2d0c893ddf0ad4c15268a3ae894a51be80ce6b7b 100644 (file)
@@ -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 (file)
index 0000000..61d22ae
--- /dev/null
@@ -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 (file)
index 0000000..a99b3be
--- /dev/null
@@ -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 (file)
index 0000000..96a1990
--- /dev/null
@@ -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 (file)
index 0000000..5a4fc4f
--- /dev/null
@@ -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 (file)
index 0000000..530972b
--- /dev/null
@@ -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 (file)
index 0000000..c84d606
--- /dev/null
@@ -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 (file)
index 0000000..8266471
--- /dev/null
@@ -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"));
+    }
+}