Allow multiple DomEvent types per DOM event
It’s possible that different libraries provide DomEvent types for the
same DOM event (mainly HTML 5 events, e.g. transitionend). If that
happens only one library will work, as GWT only knows the last
registered DomEvent type. To fix this a one-to-many mapping between
DOM event name and DomEvent types has been introduced.
This patch also contributes to issue 8379 which aims to make the
event system more extendable.
Bug: issue 7698
Change-Id: Iedbac84881484849548e1829d61eb13a6c7d00e3
(cherry picked from commit a5327b8db8379737cf2775b784e8e7241a63cc59)
diff --git a/user/src/com/google/gwt/event/dom/client/DomEvent.java b/user/src/com/google/gwt/event/dom/client/DomEvent.java
index 1500589..dbebdf3 100644
--- a/user/src/com/google/gwt/event/dom/client/DomEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DomEvent.java
@@ -21,6 +21,9 @@
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HasHandlers;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* {@link DomEvent} is a subclass of {@link GwtEvent} that provides events that
* underlying native browser event object as well as a subclass of {@link Type}
@@ -64,7 +67,12 @@
if (registered == null) {
init();
}
- registered.unsafePut(eventName, this);
+ List<Type<?>> types = registered.unsafeGet(eventName);
+ if (types == null) {
+ types = new ArrayList<Type<?>>();
+ registered.unsafePut(eventName, types);
+ }
+ types.add(this);
name = eventName;
}
@@ -78,7 +86,7 @@
}
}
- private static PrivateMap<Type<?>> registered;
+ private static PrivateMap<List<Type<?>>> registered;
/**
* Fires the given native event on the specified handlers.
@@ -104,26 +112,28 @@
assert nativeEvent != null : "nativeEvent must not be null";
if (registered != null) {
- final DomEvent.Type<?> typeKey = registered.unsafeGet(nativeEvent.getType());
- if (typeKey != null) {
- // Store and restore native event just in case we are in recursive
- // loop.
- NativeEvent currentNative = typeKey.flyweight.nativeEvent;
- Element currentRelativeElem = typeKey.flyweight.relativeElem;
- typeKey.flyweight.setNativeEvent(nativeEvent);
- typeKey.flyweight.setRelativeElement(relativeElem);
+ List<Type<?>> types = registered.unsafeGet(nativeEvent.getType());
+ if (types != null) {
+ for (DomEvent.Type<?> type : types) {
+ // Store and restore native event just in case we are in recursive
+ // loop.
+ NativeEvent currentNative = type.flyweight.nativeEvent;
+ Element currentRelativeElem = type.flyweight.relativeElem;
+ type.flyweight.setNativeEvent(nativeEvent);
+ type.flyweight.setRelativeElement(relativeElem);
- handlerSource.fireEvent(typeKey.flyweight);
+ handlerSource.fireEvent(type.flyweight);
- typeKey.flyweight.setNativeEvent(currentNative);
- typeKey.flyweight.setRelativeElement(currentRelativeElem);
+ type.flyweight.setNativeEvent(currentNative);
+ type.flyweight.setRelativeElement(currentRelativeElem);
+ }
}
}
}
// This method can go away once we have eager clinits.
static void init() {
- registered = new PrivateMap<Type<?>>();
+ registered = new PrivateMap<List<Type<?>>>();
}
private NativeEvent nativeEvent;
diff --git a/user/test/com/google/gwt/event/dom/client/DomEventTest.java b/user/test/com/google/gwt/event/dom/client/DomEventTest.java
index 65f35e4..154e434 100644
--- a/user/test/com/google/gwt/event/dom/client/DomEventTest.java
+++ b/user/test/com/google/gwt/event/dom/client/DomEventTest.java
@@ -17,6 +17,7 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HandlerTestBase;
@@ -32,6 +33,30 @@
public boolean flag = false;
}
+ interface CustomClickHandler extends EventHandler {
+ void onClick(CustomClickEvent evt);
+ }
+
+ static class CustomClickEvent extends MouseEvent<CustomClickHandler> {
+
+ public static final Type<CustomClickHandler> TYPE =
+ new Type<CustomClickHandler>("click", new CustomClickEvent());
+
+ public static Type<CustomClickHandler> getType() {
+ return TYPE;
+ }
+
+ @Override
+ public Type<CustomClickHandler> getAssociatedType() {
+ return TYPE;
+ }
+
+ @Override
+ protected void dispatch(CustomClickHandler handler) {
+ handler.onClick(this);
+ }
+ }
+
public void testKeyEvents() {
final Flag flag = new Flag();
@@ -152,6 +177,33 @@
assertTrue("Never received expected mouse-down event", flag.flag);
}
+ public void testMultipleDomEventTypesPerEventName() {
+ Button b = new Button();
+ RootPanel.get().add(b);
+
+ final Flag first = new Flag();
+ b.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ first.flag = true;
+ }
+ });
+
+ final Flag second = new Flag();
+ b.addDomHandler(new CustomClickHandler() {
+ @Override
+ public void onClick(CustomClickEvent event) {
+ second.flag = true;
+ }
+ }, CustomClickEvent.getType());
+
+ NativeEvent event = Document.get().createClickEvent(0, 0, 0, 0, 0, false, false, false, false);
+ b.getElement().dispatchEvent(event);
+
+ assertTrue("Never received expected click event", first.flag);
+ assertTrue("Never received expected click event", second.flag);
+ }
+
private void checkFire(DomEvent<?> event, HandlerRegistration registration,
Flag flag, String eventName) {