diff options
author | Automerge <automerge@vaadin.com> | 2012-05-30 09:09:06 +0000 |
---|---|---|
committer | Automerge <automerge@vaadin.com> | 2012-05-30 09:09:06 +0000 |
commit | 616387587d1377d0088a87d6831d984667f8eb3a (patch) | |
tree | 39bc80e94cf319d4d93d216ad457076ddc6b02d9 /src | |
parent | 6d07c324f8a6268c52fe3c4eb969450622d9a985 (diff) | |
download | vaadin-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.java | 16 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java | 79 |
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) { |