Fixed a bug where IE would synthesize extra click events on a double click.

Patch by: jlabanca
Review by: jgw (desk)
Issue: 3392



git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4910 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
index d071853..03e937c 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplIE6.java
@@ -108,9 +108,16 @@
 
     @com.google.gwt.user.client.impl.DOMImplIE6::dispatchDblClickEvent = function() {
       var newEvent = $doc.createEventObject();
-      $wnd.event.srcElement.fireEvent('onclick', newEvent);
+      // Synthesize a click event if one hasn't already been synthesized.
+      if ($wnd.event.returnValue == null) {
+        $wnd.event.srcElement.fireEvent('onclick', newEvent);
+      }
       if (this.__eventBits & 2) {
         @com.google.gwt.user.client.impl.DOMImplIE6::dispatchEvent.call(this);
+      } else if ($wnd.event.returnValue == null) {
+        // Ensure that we preview the event even if we aren't handling it.
+        $wnd.event.returnValue = true;
+        @com.google.gwt.user.client.DOM::previewEvent(Lcom/google/gwt/user/client/Event;)($wnd.event);
       }
     };
 
diff --git a/user/test/com/google/gwt/user/client/EventTest.java b/user/test/com/google/gwt/user/client/EventTest.java
index 1ed7e7b..a8d6474 100644
--- a/user/test/com/google/gwt/user/client/EventTest.java
+++ b/user/test/com/google/gwt/user/client/EventTest.java
@@ -15,10 +15,19 @@
  */
 package com.google.gwt.user.client;
 
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DoubleClickEvent;
+import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.Event.NativePreviewEvent;
 import com.google.gwt.user.client.Event.NativePreviewHandler;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.RootPanel;
 
 /**
  * Test Case for {@link Event}.
@@ -88,6 +97,23 @@
     }
   }
 
+  /**
+   * A custom {@link Label} used for testing.
+   */
+  private static class TestLabel extends Label implements
+      HasDoubleClickHandlers {
+    public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
+      return addDomHandler(handler, DoubleClickEvent.getType());
+    }
+  }
+
+  /**
+   * Debug information used to test events.
+   */
+  private static class EventInfo {
+    private int fireCount = 0;
+  }
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.User";
@@ -124,8 +150,48 @@
   }
 
   /**
-   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
-   * value if the native event is canceled.
+   * Test that a double click results in exactly two click events, one real and
+   * one simulated. See issue 3392 for more info.
+   */
+  public void testDoubleClickEvent() {
+    TestLabel label = new TestLabel();
+    RootPanel.get().add(label);
+
+    // Add some handlers
+    final EventInfo clickInfo = new EventInfo();
+    label.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+        clickInfo.fireCount++;
+      }
+    });
+    final EventInfo dblclickInfo = new EventInfo();
+    label.addDoubleClickHandler(new DoubleClickHandler() {
+      public void onDoubleClick(DoubleClickEvent event) {
+        dblclickInfo.fireCount++;
+      }
+    });
+
+    // Fire a click event
+    NativeEvent clickEvent = Document.get().createClickEvent(0, 0, 0, 0, 0,
+        false, false, false, false);
+    label.getElement().dispatchEvent(clickEvent);
+    NativeEvent dblclickEvent = Document.get().createDblClickEvent(0, 0, 0, 0,
+        0, false, false, false, false);
+    label.getElement().dispatchEvent(dblclickEvent);
+
+    // Verify the results
+    if (isInternetExplorer()) {
+      assertEquals(2, clickInfo.fireCount);
+    } else {
+      assertEquals(1, clickInfo.fireCount);
+    }
+    assertEquals(1, dblclickInfo.fireCount);
+    RootPanel.get().remove(label);
+  }
+
+  /**
+   * Test that {@link Event#fireNativePreviewEvent(NativeEvent)} returns the
+   * correct value if the native event is canceled.
    */
   public void testFireNativePreviewEventCancel() {
     TestNativePreviewHandler handler0 = new TestNativePreviewHandler(true,
@@ -142,9 +208,9 @@
   }
 
   /**
-   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
-   * value if the native event is prevented from being canceled, even if another
-   * handler cancels the event.
+   * Test that {@link Event#fireNativePreviewEvent(NativeEvent)} returns the
+   * correct value if the native event is prevented from being canceled, even if
+   * another handler cancels the event.
    */
   public void testFireNativePreviewEventPreventCancel() {
     TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
@@ -161,9 +227,9 @@
   }
 
   /**
-   * Test that {@link Event#fireNativePreviewEvent(Event)} fires handlers in
-   * reverse order, and that the legacy EventPreview fires only if it is at the
-   * top of the stack.
+   * Test that {@link Event#fireNativePreviewEvent(NativeEvent)} fires handlers
+   * in reverse order, and that the legacy EventPreview fires only if it is at
+   * the top of the stack.
    */
   @SuppressWarnings("deprecation")
   public void testFireNativePreviewEventReverseOrder() {
@@ -254,8 +320,8 @@
   }
 
   /**
-   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
-   * value if the native event is not canceled.
+   * Test that {@link Event#fireNativePreviewEvent(NativeEvent)} returns the
+   * correct value if the native event is not canceled.
    */
   public void testFireNativePreviewEventWithoutCancel() {
     TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
@@ -272,8 +338,8 @@
   }
 
   /**
-   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
-   * value if no handlers are present.
+   * Test that {@link Event#fireNativePreviewEvent(NativeEvent)} returns the
+   * correct value if no handlers are present.
    */
   public void testFireNativePreviewEventWithoutHandlers() {
     assertTrue(Event.fireNativePreviewEvent(null));
@@ -451,4 +517,8 @@
     handler1.assertIsFired(true);
     reg1.removeHandler();
   }
+
+  private native boolean isInternetExplorer() /*-{
+     return navigator.userAgent.toLowerCase().indexOf("msie") != -1;
+   }-*/;
 }