aboutsummaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorPekka Hyvönen <pekka@vaadin.com>2017-05-11 14:36:27 +0300
committerGitHub <noreply@github.com>2017-05-11 14:36:27 +0300
commitf72ac12fd257e218c370a4d686be4cc99c2a22d6 (patch)
treedf7937c1835dcd6517717332147cae383a27c05c /client
parente2e3058a497f43f34f2fcfadf6b63de9211be659 (diff)
downloadvaadin-framework-f72ac12fd257e218c370a4d686be4cc99c2a22d6.tar.gz
vaadin-framework-f72ac12fd257e218c370a4d686be4cc99c2a22d6.zip
Add mobile html5 dnd support using polyfill (#9282)
First step of mobile DND support. - Add mobile html5 dnd support using polyfill - Adds a switch for enabling mobile html5 dnd support - Adds polyfill only when needed - Ignore native Android Chrome drag start because doesn't work properly (no dragend event fired) - Add documentation on enabling mobile HTML5 DnD support - Add mention of drag-drop-polyfill license - Fixed issue in polyfill when not using "snapback" - Add mention of forked polyfill Fixes #9174
Diffstat (limited to 'client')
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceConnector.java25
-rw-r--r--client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java60
-rw-r--r--client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java5
-rw-r--r--client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java27
4 files changed, 108 insertions, 9 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceConnector.java
index 134e76e7e5..64e9c2e7b5 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceConnector.java
@@ -74,8 +74,9 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
protected void extend(ServerConnector target) {
gridConnector = (GridConnector) target;
- // Do not make elements draggable on touch devices
- if (BrowserInfo.get().isTouchDevice()) {
+ // HTML5 DnD is by default not enabled for mobile devices
+ if (BrowserInfo.get().isTouchDevice() && !getConnection()
+ .getUIConnector().isMobileHTML5DndEnabled()) {
return;
}
@@ -89,6 +90,15 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
@Override
protected void onDragStart(Event event) {
+ NativeEvent nativeEvent = (NativeEvent) event;
+
+ // Do not allow drag starts from native Android Chrome, since it doesn't
+ // work properly (doesn't fire dragend reliably)
+ if (isAndoidChrome() && isNativeDragEvent(nativeEvent)) {
+ event.preventDefault();
+ event.stopPropagation();
+ return;
+ }
// Collect the keys of dragged rows
draggedItemKeys = getDraggedRows(event).stream()
@@ -195,8 +205,17 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
@Override
protected void onDragEnd(Event event) {
+ NativeEvent nativeEvent = (NativeEvent) event;
+
+ // for android chrome we use the polyfill, in case browser fires a
+ // native dragend event after the polyfill, we need to ignore that one
+ if (isAndoidChrome() && isNativeDragEvent((nativeEvent))) {
+ event.preventDefault();
+ event.stopPropagation();
+ return;
+ }
// Ignore event if there are no items dragged
- if (draggedItemKeys.size() > 0) {
+ if (draggedItemKeys != null && draggedItemKeys.size() > 0) {
super.onDragEnd(event);
}
diff --git a/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java b/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
index e718fb90d7..9e0a76788d 100644
--- a/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
+++ b/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
@@ -67,8 +67,9 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
protected void extend(ServerConnector target) {
dragSourceWidget = ((ComponentConnector) target).getWidget();
- // Do not make elements draggable on touch devices
- if (BrowserInfo.get().isTouchDevice()) {
+ // HTML5 DnD is by default not enabled for mobile devices
+ if (BrowserInfo.get().isTouchDevice() && !getConnection()
+ .getUIConnector().isMobileHTML5DndEnabled()) {
return;
}
@@ -159,6 +160,14 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
// Convert elemental event to have access to dataTransfer
NativeEvent nativeEvent = (NativeEvent) event;
+ // Do not allow drag starts from native Android Chrome, since it doesn't
+ // work properly (doesn't fire dragend reliably)
+ if (isAndoidChrome() && isNativeDragEvent(nativeEvent)) {
+ event.preventDefault();
+ event.stopPropagation();
+ return;
+ }
+
// Set effectAllowed parameter
if (getState().effectAllowed != null) {
setEffectAllowed(nativeEvent.getDataTransfer(),
@@ -281,11 +290,20 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
* browser event to be handled
*/
protected void onDragEnd(Event event) {
+ NativeEvent nativeEvent = (NativeEvent) event;
+
+ // for android chrome we use the polyfill, in case browser fires a
+ // native dragend event after the polyfill dragend, we need to ignore
+ // that one
+ if (isNativeDragEvent((nativeEvent))) {
+ event.preventDefault();
+ event.stopPropagation();
+ return;
+ }
// Initiate server start dragend event when there is a DragEndListener
// attached on the server side
if (hasEventListener(DragSourceState.EVENT_DRAGEND)) {
- String dropEffect = getDropEffect(
- ((NativeEvent) event).getDataTransfer());
+ String dropEffect = getDropEffect(nativeEvent.getDataTransfer());
assert dropEffect != null : "Drop effect should never be null";
@@ -318,6 +336,40 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
return dragSourceWidget.getElement();
}
+ /**
+ * Returns whether the given event is a native (android) drag start/end
+ * event, and not produced by the drag-drop-polyfill.
+ *
+ * @param nativeEvent
+ * the event to test
+ * @return {@code true} if native event, {@code false} if not (polyfill
+ * event)
+ */
+ protected boolean isNativeDragEvent(NativeEvent nativeEvent) {
+ return isTrusted(nativeEvent) || isComposed(nativeEvent);
+ }
+
+ /**
+ * Returns whether the current browser is Android Chrome.
+ *
+ * @return {@code true} if Android Chrome, {@code false} if not
+ *
+ */
+ protected boolean isAndoidChrome() {
+ BrowserInfo browserInfo = BrowserInfo.get();
+ return browserInfo.isAndroid() && browserInfo.isChrome();
+ }
+
+ private native boolean isTrusted(NativeEvent event)
+ /*-{
+ return event.isTrusted;
+ }-*/;
+
+ private native boolean isComposed(NativeEvent event)
+ /*-{
+ return event.isComposed;
+ }-*/;
+
private native void setEffectAllowed(DataTransfer dataTransfer,
String effectAllowed)
/*-{
diff --git a/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java b/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
index 49592488de..acd6d48575 100644
--- a/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
+++ b/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
@@ -80,8 +80,9 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
protected void extend(ServerConnector target) {
dropTargetWidget = ((ComponentConnector) target).getWidget();
- // Do not make elements drop target on touch devices
- if (BrowserInfo.get().isTouchDevice()) {
+ // HTML5 DnD is by default not enabled for mobile devices
+ if (BrowserInfo.get().isTouchDevice() && !getConnection()
+ .getUIConnector().isMobileHTML5DndEnabled()) {
return;
}
diff --git a/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java b/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
index 96e7aa1498..49a7e181b2 100644
--- a/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
@@ -69,6 +69,8 @@ import com.vaadin.client.ValueMap;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.client.extensions.DragSourceExtensionConnector;
+import com.vaadin.client.extensions.DropTargetExtensionConnector;
import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
import com.vaadin.client.ui.ClickEventHandler;
@@ -165,6 +167,11 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
Window.Location.reload();
}
+
+ @Override
+ public void initializeMobileHtml5DndPolyfill() {
+ initializeMobileDndPolyfill();
+ }
});
registerRpc(ScrollClientRpc.class, new ScrollClientRpc() {
@Override
@@ -1160,6 +1167,20 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
return activeTheme;
}
+ /**
+ * Returns whether HTML5 DnD extensions {@link DragSourceExtensionConnector}
+ * and {@link DropTargetExtensionConnector} and alike should be enabled for
+ * mobile devices.
+ * <p>
+ * By default, it is disabled.
+ *
+ * @return {@code true} if enabled, {@code false} if not
+ * @since 8.1
+ */
+ public boolean isMobileHTML5DndEnabled() {
+ return getState().enableMobileHTML5DnD;
+ }
+
private static Logger getLogger() {
return Logger.getLogger(UIConnector.class.getName());
}
@@ -1209,4 +1230,10 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
return result;
}
}
+
+ // TODO add configuration to use custom drag start decider
+ private static native void initializeMobileDndPolyfill()
+ /*-{
+ $wnd.DragDropPolyfill.Initialize();
+ }-*/;
}