summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAutomerge <automerge@vaadin.com>2012-05-30 09:09:06 +0000
committerAutomerge <automerge@vaadin.com>2012-05-30 09:09:06 +0000
commit616387587d1377d0088a87d6831d984667f8eb3a (patch)
tree39bc80e94cf319d4d93d216ad457076ddc6b02d9 /src
parent6d07c324f8a6268c52fe3c4eb969450622d9a985 (diff)
downloadvaadin-framework-616387587d1377d0088a87d6831d984667f8eb3a.tar.gz
vaadin-framework-616387587d1377d0088a87d6831d984667f8eb3a.zip
[merge from 6.7] Make ClickEventHandler fire clicks only if mousedown and mouseup match (#4120)
svn changeset:23846/svn branch:6.8
Diffstat (limited to 'src')
-rw-r--r--src/com/vaadin/terminal/gwt/client/Util.java16
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java79
2 files changed, 90 insertions, 5 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java
index cb2539daa5..1a9991bb80 100644
--- a/src/com/vaadin/terminal/gwt/client/Util.java
+++ b/src/com/vaadin/terminal/gwt/client/Util.java
@@ -1157,6 +1157,22 @@ public class Util {
}
/**
+ * Find the element corresponding to the coordinates in the passed mouse
+ * event. Please note that this is not always the same as the target of the
+ * element e.g. if event capture is used.
+ *
+ * @param event
+ * the mouse event to get coordinates from
+ * @return the element at the coordinates of the event
+ */
+ public static Element getElementUnderMouse(NativeEvent event) {
+ int pageX = getTouchOrMouseClientX(event);
+ int pageY = getTouchOrMouseClientY(event);
+
+ return getElementFromPoint(pageX, pageY);
+ }
+
+ /**
* A helper method to return the client position from an event. Returns
* position from either first changed touch (if touch event) or from the
* event itself.
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
index 3deb140d30..79ae5167fc 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
@@ -6,33 +6,79 @@ package com.vaadin.terminal.gwt.client.ui;
import java.util.HashMap;
import java.util.Map;
+import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ContextMenuEvent;
import com.google.gwt.event.dom.client.ContextMenuHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.Util;
public abstract class ClickEventHandler implements DoubleClickHandler,
- ContextMenuHandler, MouseUpHandler {
+ ContextMenuHandler, MouseUpHandler, MouseDownHandler {
private HandlerRegistration doubleClickHandlerRegistration;
private HandlerRegistration mouseUpHandlerRegistration;
+ private HandlerRegistration mouseDownHandlerRegistration;
private HandlerRegistration contextMenuHandlerRegistration;
protected String clickEventIdentifier;
protected Paintable paintable;
private ApplicationConnection client;
+ /**
+ * The element where the last mouse down event was registered.
+ */
+ private JavaScriptObject lastMouseDownTarget;
+
+ /**
+ * Set to true by {@link #mouseUpPreviewHandler} if it gets a mouseup at the
+ * same element as {@link #lastMouseDownTarget}.
+ */
+ private boolean mouseUpPreviewMatched = false;
+
+ private HandlerRegistration mouseUpEventPreviewRegistration;
+
+ /**
+ * Previews events after a mousedown to detect where the following mouseup
+ * hits.
+ */
+ private final NativePreviewHandler mouseUpPreviewHandler = new NativePreviewHandler() {
+ public void onPreviewNativeEvent(NativePreviewEvent event) {
+ if (event.getTypeInt() == Event.ONMOUSEUP) {
+ mouseUpEventPreviewRegistration.removeHandler();
+
+ // Event's reported target not always correct if event
+ // capture is in use
+ Element elementUnderMouse = Util.getElementUnderMouse(event
+ .getNativeEvent());
+ if (lastMouseDownTarget != null
+ && elementUnderMouse.cast() == lastMouseDownTarget) {
+ mouseUpPreviewMatched = true;
+ } else {
+ System.out.println("Ignoring mouseup from "
+ + elementUnderMouse + " when mousedown was on "
+ + lastMouseDownTarget);
+ }
+ }
+ }
+ };
+
public ClickEventHandler(Paintable paintable, String clickEventIdentifier) {
this.paintable = paintable;
this.clickEventIdentifier = clickEventIdentifier;
@@ -46,6 +92,8 @@ public abstract class ClickEventHandler implements DoubleClickHandler,
if (mouseUpHandlerRegistration == null) {
mouseUpHandlerRegistration = registerHandler(this,
MouseUpEvent.getType());
+ mouseDownHandlerRegistration = registerHandler(this,
+ MouseDownEvent.getType());
contextMenuHandlerRegistration = registerHandler(this,
ContextMenuEvent.getType());
doubleClickHandlerRegistration = registerHandler(this,
@@ -56,10 +104,12 @@ public abstract class ClickEventHandler implements DoubleClickHandler,
// Remove existing handlers
doubleClickHandlerRegistration.removeHandler();
mouseUpHandlerRegistration.removeHandler();
+ mouseDownHandlerRegistration.removeHandler();
contextMenuHandlerRegistration.removeHandler();
contextMenuHandlerRegistration = null;
mouseUpHandlerRegistration = null;
+ mouseDownHandlerRegistration = null;
doubleClickHandlerRegistration = null;
}
@@ -101,14 +151,33 @@ public abstract class ClickEventHandler implements DoubleClickHandler,
}
+ public void onMouseDown(MouseDownEvent event) {
+ /*
+ * When getting a mousedown event, we must detect where the
+ * corresponding mouseup event if it's on a different part of the page.
+ */
+ lastMouseDownTarget = event.getNativeEvent().getEventTarget();
+ mouseUpPreviewMatched = false;
+ mouseUpEventPreviewRegistration = Event
+ .addNativePreviewHandler(mouseUpPreviewHandler);
+ }
+
public void onMouseUp(MouseUpEvent event) {
- // TODO For perfect accuracy we should check that a mousedown has
- // occured on this element before this mouseup and that no mouseup
- // has occured anywhere after that.
- if (hasEventListener()) {
+ /*
+ * Only fire a click if the mouseup hits the same element as the
+ * corresponding mousedown. This is first checked in the event preview
+ * but we can't fire the even there as the event might get canceled
+ * before it gets here.
+ */
+ if (hasEventListener()
+ && mouseUpPreviewMatched
+ && lastMouseDownTarget != null
+ && Util.getElementUnderMouse(event.getNativeEvent()) == lastMouseDownTarget) {
// "Click" with left, right or middle button
fireClick(event.getNativeEvent());
}
+ mouseUpPreviewMatched = false;
+ lastMouseDownTarget = null;
}
public void onDoubleClick(DoubleClickEvent event) {