Improves GWT event dispatch for extensibility.
New implementation introduces a dispatcher map for bitless events and
uses a 'default' dispatch function if there is no specific dispatcher
defined for the event.
Similarly, a dispatcher map for capture events introduced as well that
simplifies the boiler-plate around capture events.
With this change even if the event is not known by GWT yet, it will
still be dispatched. As most events don't need custom dispatching, no
further changes will be required to DOMImpl (e.g. MGWT will no longer
need to rebind DOMImpl for transitionEnd and animationEnd as those will
work out of the box.)
Partially fixes issue 8379
Change-Id: Ia00c177d0f007d544d4837e2291c991615795474
Review-Link: https://gwt-review.googlesource.com/#/c/5222/
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
index df83254..4c7b609 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplMozilla.java
@@ -22,6 +22,15 @@
*/
class DOMImplMozilla extends DOMImplStandard {
+ static {
+ addMozillaCaptureEventDispatchers();
+ }
+
+ private static native void addMozillaCaptureEventDispatchers() /*-{
+ @com.google.gwt.user.client.impl.DOMImplStandard::captureEventDispatchers['DOMMouseScroll'] =
+ @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*);
+ }-*/;
+
@Override
public void sinkEvents(Element elem, int bits) {
super.sinkEvents(elem, bits);
@@ -62,19 +71,5 @@
}),
true
);
-
- $wnd.addEventListener('DOMMouseScroll',
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- }-*/;
-
- @Override
- protected void disposeEventSystem() {
- super.disposeEventSystem();
- disposeEventSystemMozilla();
- }
-
- private native void disposeEventSystemMozilla() /*-{
- $wnd.removeEventListener('DOMMouseScroll',
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
}-*/;
}
diff --git a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
index 06ffbed..3a5f893 100644
--- a/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
+++ b/user/src/com/google/gwt/user/client/impl/DOMImplStandard.java
@@ -24,20 +24,20 @@
/**
* Base implementation of {@link com.google.gwt.user.client.impl.DOMImpl} shared
* by those browsers that come a bit closer to supporting a common standard (ie,
- * not IE).
+ * not legacy IEs).
*/
abstract class DOMImplStandard extends DOMImpl {
private static Element captureElem;
- private static JavaScriptObject dispatchCapturedEvent;
+ private static JavaScriptObject bitlessEventDispatchers = getBitlessEventDispatchers();
- private static JavaScriptObject dispatchCapturedMouseEvent;
+ private static JavaScriptObject captureEventDispatchers = getCaptureEventDispatchers();
- private static JavaScriptObject dispatchDragEvent;
-
+ @Deprecated // We no longer want any external JSNI dependencies
private static JavaScriptObject dispatchEvent;
+ @Deprecated // We no longer want any external JSNI dependencies
private static JavaScriptObject dispatchUnhandledEvent;
@Override
@@ -151,110 +151,40 @@
}
@Override
- protected native void disposeEventSystem() /*-{
- $wnd.removeEventListener('click', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('dblclick', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('mousedown', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('mouseup', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('mousemove', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('mouseover', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('mouseout', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('mousewheel', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('keydown', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
- $wnd.removeEventListener('keyup', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
- $wnd.removeEventListener('keypress', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
+ protected native void initEventSystem() /*-{
+ // Ensure $entry for bitfull event dispatchers
+ @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent =
+ $entry(@com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent(*));
- // Touch and gesture events are not actually mouse events, but we treat
- // them as such, so that DOM#setCapture() and DOM#releaseCapture() work.
- $wnd.removeEventListener('touchstart', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('touchmove', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('touchend', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('touchcancel', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('gesturestart', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('gesturechange', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.removeEventListener('gestureend', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+ @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent =
+ $entry(@com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent(*));
+
+ var foreach = @com.google.gwt.user.client.impl.DOMImplStandard::foreach(*);
+
+ // Ensure $entry for bitless event dispatchers
+ var bitlessEvents = @com.google.gwt.user.client.impl.DOMImplStandard::bitlessEventDispatchers;
+ foreach(bitlessEvents, function(e, fn) { bitlessEvents[e] = $entry(fn); });
+
+ // Ensure $entry for capture event dispatchers
+ var captureEvents = @com.google.gwt.user.client.impl.DOMImplStandard::captureEventDispatchers;
+ foreach(captureEvents, function(e, fn) { captureEvents[e] = $entry(fn); });
+
+ // Add capture event listeners
+ foreach(captureEvents, function(e, fn) { $wnd.addEventListener(e, fn, true); });
}-*/;
@Override
- protected native void initEventSystem() /*-{
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent = $entry(
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent(*)
- );
+ protected native void disposeEventSystem() /*-{
+ var foreach = @com.google.gwt.user.client.impl.DOMImplStandard::foreach(*);
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent = $entry(
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent(*)
- );
-
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent = $entry(
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchUnhandledEvent(*)
- );
-
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent = $entry(
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent(*)
- );
-
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent = $entry(
- @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*)
- );
-
- $wnd.addEventListener('click', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('dblclick', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('mousedown', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('mouseup', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('mousemove', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('mouseover', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('mouseout', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('mousewheel', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('keydown', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
- $wnd.addEventListener('keyup', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
- $wnd.addEventListener('keypress', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent, true);
-
- // Touch and gesture events are not actually mouse events, but we treat
- // them as such, so that DOM#setCapture() and DOM#releaseCapture() work.
- $wnd.addEventListener('touchstart', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('touchmove', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('touchend', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('touchcancel', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('gesturestart', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('gesturechange', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
- $wnd.addEventListener('gestureend', @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent, true);
+ // Remove capture event listeners
+ foreach(captureEvents, function(e, fn) { $wnd.removeEventListener(e, fn, true); });
}-*/;
protected native void sinkBitlessEventImpl(Element elem, String eventTypeName) /*-{
- switch(eventTypeName) {
- case "drag":
- elem.ondrag = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
- break;
- case "dragend":
- elem.ondragend = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
- break;
- case "dragenter":
- elem.ondragenter = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent;
- break;
- case "dragleave":
- elem.ondragleave = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
- break;
- case "dragover":
- elem.ondragover = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent;
- break;
- case "dragstart":
- elem.ondragstart = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
- break;
- case "drop":
- elem.ondrop = @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent;
- break;
- case "canplaythrough":
- case "ended":
- case "loadedmetadata":
- case "progress":
- // First call removeEventListener, so as not to add the same event listener more than once
- elem.removeEventListener(eventTypeName, @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent, false);
- elem.addEventListener(eventTypeName, @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent, false);
- break;
- default:
- // catch missing cases
- throw "Trying to sink unknown event type " + eventTypeName;
- }
+ var dispatchMap = @com.google.gwt.user.client.impl.DOMImplStandard::bitlessEventDispatchers;
+ var dispatcher = dispatchMap[eventTypeName] || dispatchMap['_default_'];
+ elem.addEventListener(eventTypeName, dispatcher, false);
}-*/;
protected native void sinkEventsImpl(Element elem, int bits) /*-{
@@ -359,4 +289,48 @@
evt.stopPropagation();
}
}
+
+ private static native JavaScriptObject getBitlessEventDispatchers() /*-{
+ return {
+ _default_: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchEvent(*),
+ dragenter: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent(*),
+ dragover: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchDragEvent(*),
+ };
+ }-*/;
+
+ private static native JavaScriptObject getCaptureEventDispatchers() /*-{
+ return {
+ // Mouse events
+ click: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ dblclick: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ mousedown: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ mouseup: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ mousemove: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ mouseover: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ mouseout: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ mousewheel: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+
+ // Keyboard events
+ keydown: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent(*),
+ keyup: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent(*),
+ keypress: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedEvent(*),
+
+ // Touch events
+ touchstart: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ touchend: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ touchmove: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ touchcancel: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ gesturestart: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ gestureend: @com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ gesturechange:@com.google.gwt.user.client.impl.DOMImplStandard::dispatchCapturedMouseEvent(*),
+ };
+ }-*/;
+
+ private static native void foreach(JavaScriptObject map, JavaScriptObject fn) /*-{
+ for (var e in map) {
+ if (map.hasOwnProperty(e)) {
+ fn(e, map[e]);
+ }
+ }
+ }-*/;
}