]> source.dussan.org Git - vaadin-framework.git/commitdiff
Fix remaining issues for NativeSelect blur/focus events (#6847)
authorArtur Signell <artur@vaadin.com>
Tue, 13 Jan 2015 10:42:22 +0000 (12:42 +0200)
committerArtur Signell <artur@vaadin.com>
Tue, 13 Jan 2015 17:55:46 +0000 (19:55 +0200)
* Do not spam focus/blur events to the server
* Receive focus blur events no matter which constructor is used
* Run test on all browsers

Change-Id: I7d548397e6df3a375f9263c695a53c801d9c5c4a

client/src/com/vaadin/client/EventHelper.java
client/src/com/vaadin/client/ui/VNativeSelect.java
client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
server/src/com/vaadin/ui/NativeSelect.java
server/tests/src/com/vaadin/ui/NativeSelectTest.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsFocusAndBlurListenerTests.java

index a1cb75527d3a14774dec0cac0fbf55c52a761ea1..f251215d41bed07ed346416d07d4f5550c849a4b 100644 (file)
@@ -25,6 +25,7 @@ import com.google.gwt.event.dom.client.FocusEvent;
 import com.google.gwt.event.dom.client.FocusHandler;
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Widget;
 
 /**
  * Helper class for attaching/detaching handlers for Vaadin client side
@@ -61,7 +62,7 @@ public class EventHelper {
      * @param connector
      *            The connector to update. Must implement focusHandler.
      * @param handlerRegistration
-     *            The old registration reference or null no handler has been
+     *            The old registration reference or null if no handler has been
      *            registered previously
      * @return a new registration handler that can be used to unregister the
      *         handler later
@@ -69,7 +70,27 @@ public class EventHelper {
     public static <T extends ComponentConnector & FocusHandler> HandlerRegistration updateFocusHandler(
             T connector, HandlerRegistration handlerRegistration) {
         return updateHandler(connector, FOCUS, handlerRegistration,
-                FocusEvent.getType());
+                FocusEvent.getType(), connector.getWidget());
+    }
+
+    /**
+     * Adds or removes a focus handler depending on if the connector has focus
+     * listeners on the server side or not.
+     * 
+     * @param connector
+     *            The connector to update. Must implement focusHandler.
+     * @param handlerRegistration
+     *            The old registration reference or null if no handler has been
+     *            registered previously
+     * @param widget
+     *            The widget which emits focus events
+     * @return a new registration handler that can be used to unregister the
+     *         handler later
+     */
+    public static <T extends ComponentConnector & FocusHandler> HandlerRegistration updateFocusHandler(
+            T connector, HandlerRegistration handlerRegistration, Widget widget) {
+        return updateHandler(connector, FOCUS, handlerRegistration,
+                FocusEvent.getType(), widget);
     }
 
     /**
@@ -79,7 +100,7 @@ public class EventHelper {
      * @param connector
      *            The connector to update. Must implement BlurHandler.
      * @param handlerRegistration
-     *            The old registration reference or null no handler has been
+     *            The old registration reference or null if no handler has been
      *            registered previously
      * @return a new registration handler that can be used to unregister the
      *         handler later
@@ -87,16 +108,36 @@ public class EventHelper {
     public static <T extends ComponentConnector & BlurHandler> HandlerRegistration updateBlurHandler(
             T connector, HandlerRegistration handlerRegistration) {
         return updateHandler(connector, BLUR, handlerRegistration,
-                BlurEvent.getType());
+                BlurEvent.getType(), connector.getWidget());
+    }
+
+    /**
+     * Adds or removes a blur handler depending on if the connector has blur
+     * listeners on the server side or not.
+     * 
+     * @param connector
+     *            The connector to update. Must implement BlurHandler.
+     * @param handlerRegistration
+     *            The old registration reference or null if no handler has been
+     *            registered previously
+     * @param widget
+     *            The widget which emits blur events
+     * 
+     * @return a new registration handler that can be used to unregister the
+     *         handler later
+     */
+    public static <T extends ComponentConnector & BlurHandler> HandlerRegistration updateBlurHandler(
+            T connector, HandlerRegistration handlerRegistration, Widget widget) {
+        return updateHandler(connector, BLUR, handlerRegistration,
+                BlurEvent.getType(), widget);
     }
 
     private static <H extends EventHandler> HandlerRegistration updateHandler(
             ComponentConnector connector, String eventIdentifier,
-            HandlerRegistration handlerRegistration, Type<H> type) {
+            HandlerRegistration handlerRegistration, Type<H> type, Widget widget) {
         if (connector.hasEventListener(eventIdentifier)) {
             if (handlerRegistration == null) {
-                handlerRegistration = connector.getWidget().addDomHandler(
-                        (H) connector, type);
+                handlerRegistration = widget.addDomHandler((H) connector, type);
             }
         } else if (handlerRegistration != null) {
             handlerRegistration.removeHandler();
index 879c54cae879fad5341f78d8079a187e361d58cd..330442b550c2122b00aa2844fb268559f9260764 100644 (file)
@@ -19,9 +19,7 @@ package com.vaadin.client.ui;
 import java.util.ArrayList;
 import java.util.Iterator;
 
-import com.google.gwt.event.dom.client.BlurHandler;
 import com.google.gwt.event.dom.client.ChangeEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
 import com.google.gwt.user.client.ui.ListBox;
 import com.vaadin.client.BrowserInfo;
 import com.vaadin.client.UIDL;
@@ -119,14 +117,6 @@ public class VNativeSelect extends VOptionGroupBase implements Field {
         }
     }
 
-    public void addFocusHandler(FocusHandler handler) {
-        select.addFocusHandler(handler);
-    }
-
-    public void addBlurHandler(BlurHandler handler) {
-        select.addBlurHandler(handler);
-    }
-
     @Override
     public void setHeight(String height) {
         select.setHeight(height);
@@ -154,4 +144,11 @@ public class VNativeSelect extends VOptionGroupBase implements Field {
         select.setFocus(true);
     }
 
+    /**
+     * @return the root select widget
+     */
+    public ListBox getSelect() {
+        return getOptionsContainer();
+    }
+
 }
index c52b762e5895153a8c3bea16d214c8337cd44b85..938903da9a3cf70303fccc7c2e5e9a09172f89e9 100644 (file)
@@ -20,6 +20,9 @@ import com.google.gwt.event.dom.client.BlurEvent;
 import com.google.gwt.event.dom.client.BlurHandler;
 import com.google.gwt.event.dom.client.FocusEvent;
 import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.vaadin.client.EventHelper;
+import com.vaadin.client.annotations.OnStateChange;
 import com.vaadin.client.ui.VNativeSelect;
 import com.vaadin.client.ui.optiongroup.OptionGroupBaseConnector;
 import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
@@ -30,10 +33,19 @@ import com.vaadin.ui.NativeSelect;
 public class NativeSelectConnector extends OptionGroupBaseConnector implements
         BlurHandler, FocusHandler {
 
+    private HandlerRegistration focusHandlerRegistration = null;
+    private HandlerRegistration blurHandlerRegistration = null;
+
     public NativeSelectConnector() {
         super();
-        getWidget().addFocusHandler(this);
-        getWidget().addBlurHandler(this);
+    }
+
+    @OnStateChange("registeredEventListeners")
+    private void onServerEventListenerChanged() {
+        focusHandlerRegistration = EventHelper.updateFocusHandler(this,
+                focusHandlerRegistration, getWidget().getSelect());
+        blurHandlerRegistration = EventHelper.updateBlurHandler(this,
+                blurHandlerRegistration, getWidget().getSelect());
     }
 
     @Override
@@ -43,11 +55,16 @@ public class NativeSelectConnector extends OptionGroupBaseConnector implements
 
     @Override
     public void onFocus(FocusEvent event) {
+        // EventHelper.updateFocusHandler ensures that this is called only when
+        // there is a listener on server side
         getRpcProxy(FocusAndBlurServerRpc.class).focus();
     }
 
     @Override
     public void onBlur(BlurEvent event) {
+        // EventHelper.updateFocusHandler ensures that this is called only when
+        // there is a listener on server side
         getRpcProxy(FocusAndBlurServerRpc.class).blur();
     }
+
 }
index ee7bfc3e5c3c82e87aa9665da89f003e9c8f61ac..137d57f677e2f686e3cd52fb322e2029cf56ddf5 100644 (file)
@@ -56,14 +56,17 @@ public class NativeSelect extends AbstractSelect implements
 
     public NativeSelect(String caption, Collection<?> options) {
         super(caption, options);
+        registerRpc(focusBlurRpc);
     }
 
     public NativeSelect(String caption, Container dataSource) {
         super(caption, dataSource);
+        registerRpc(focusBlurRpc);
     }
 
     public NativeSelect(String caption) {
         super(caption);
+        registerRpc(focusBlurRpc);
     }
 
     /**
diff --git a/server/tests/src/com/vaadin/ui/NativeSelectTest.java b/server/tests/src/com/vaadin/ui/NativeSelectTest.java
new file mode 100644 (file)
index 0000000..7e2a04e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui;
+
+import java.util.Collections;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.data.util.IndexedContainer;
+
+public class NativeSelectTest {
+
+    @Test
+    public void rpcRegisteredConstructorNoArg() {
+        assertFocusRpcRegistered(new NativeSelect());
+    }
+
+    @Test
+    public void rpcRegisteredConstructorString() {
+        assertFocusRpcRegistered(new NativeSelect("foo"));
+    }
+
+    @Test
+    public void rpcRegisteredConstructorStringCollection() {
+        assertFocusRpcRegistered(new NativeSelect("foo",
+                Collections.singleton("Hello")));
+    }
+
+    @Test
+    public void rpcRegisteredConstructorStringContainer() {
+        assertFocusRpcRegistered(new NativeSelect("foo", new IndexedContainer()));
+    }
+
+    private void assertFocusRpcRegistered(NativeSelect s) {
+        Assert.assertNotNull(
+                "RPC is not correctly registered",
+                s.getRpcManager("com.vaadin.shared.communication.FieldRpc$FocusAndBlurServerRpc"));
+    }
+
+}
index 29c8c278832928ebe607d37173657d8ec349e9d0..bf81ca439036eb14ccda69911c211e939cb95784 100644 (file)
  */
 package com.vaadin.tests.components.nativeselect;
 
-import java.util.Collections;
-import java.util.List;
-
 import org.junit.Assert;
 import org.junit.Test;
 import org.openqa.selenium.By;
-import org.openqa.selenium.WebElement;
 import org.openqa.selenium.interactions.Actions;
-import org.openqa.selenium.remote.DesiredCapabilities;
 
+import com.vaadin.testbench.elements.NativeSelectElement;
 import com.vaadin.tests.tb3.MultiBrowserTest;
 
-/**
- * 
- * @since
- * @author Vaadin Ltd
- */
 public class NativeSelectsFocusAndBlurListenerTests extends MultiBrowserTest {
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see com.vaadin.tests.tb3.MultiBrowserTest#getBrowsersToTest()
-     */
-    @Override
-    public List<DesiredCapabilities> getBrowsersToTest() {
-        return Collections.singletonList(Browser.CHROME
-                .getDesiredCapabilities());
-    }
-
     @Test
-    public void testFocusListener() throws InterruptedException {
+    public void testFocusAndBlurListener() throws InterruptedException {
         setDebug(true);
         openTestURL();
-        Thread.sleep(1000);
+        Thread.sleep(200);
         menu("Component");
         menuSub("Listeners");
         menuSub("Focus listener");
-
-        getDriver().findElement(By.tagName("body")).click();
-
-        WebElement select = getDriver().findElement(By.tagName("select"));
-        select.click();
-
-        String bodytext = getDriver().findElement(By.tagName("body")).getText();
-
-        Assert.assertTrue(bodytext.contains("FocusEvent"));
-
-    }
-
-    @Test
-    public void testBlurListener() throws InterruptedException {
-        setDebug(true);
-        openTestURL();
-        Thread.sleep(1000);
         menu("Component");
         menuSub("Listeners");
         menuSub("Blur listener");
 
-        getDriver().findElement(By.tagName("body")).click();
-
-        WebElement select = getDriver().findElement(By.tagName("select"));
-        select.click();
+        findElement(By.tagName("body")).click();
 
+        NativeSelectElement s = $(NativeSelectElement.class).first();
+        s.selectByText("Item 3");
         getDriver().findElement(By.tagName("body")).click();
 
-        String bodytext = getDriver().findElement(By.tagName("body")).getText();
-
-        Assert.assertTrue(bodytext.contains("BlurEvent"));
+        // Somehow selectByText causes focus + blur + focus + blur on
+        // Chrome/PhantomJS
+        if (BrowserUtil.isChrome(getDesiredCapabilities())
+                || BrowserUtil.isPhantomJS(getDesiredCapabilities())) {
+            Assert.assertEquals("4. FocusEvent", getLogRow(1));
+            Assert.assertEquals("5. BlurEvent", getLogRow(0));
+        } else {
+            Assert.assertEquals("2. FocusEvent", getLogRow(1));
+            Assert.assertEquals("3. BlurEvent", getLogRow(0));
+        }
 
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see com.vaadin.tests.tb3.AbstractTB3Test#getUIClass()
-     */
     @Override
     protected Class<?> getUIClass() {
         return NativeSelects.class;
     }
 
-    /**
-     * @since
-     * @param string
-     */
     private void menuSub(String string) {
         getDriver().findElement(By.xpath("//span[text() = '" + string + "']"))
                 .click();
         new Actions(getDriver()).moveByOffset(100, 0).build().perform();
     }
 
-    /**
-     * @since
-     * @param string
-     */
     private void menu(String string) {
         getDriver().findElement(By.xpath("//span[text() = '" + string + "']"))
                 .click();