]> source.dussan.org Git - vaadin-framework.git/commitdiff
Fix drag image offset for Grid rows for mobile (#9336)
authorPekka Hyvönen <pekka@vaadin.com>
Wed, 17 May 2017 11:20:26 +0000 (14:20 +0300)
committerGitHub <noreply@github.com>
Wed, 17 May 2017 11:20:26 +0000 (14:20 +0300)
Asks the polyfill to always center the drag image based on the touch coordinates.
Also temporarely removes the transform offset for the row.

client/src/main/java/com/vaadin/client/connectors/grid/GridDragSourceConnector.java
client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
uitest/src/main/java/com/vaadin/tests/dnd/DragImage.java

index 5e83fef65103d42b0ca28ec4720e8249dc2ab349..7f8fb429a2997243c9caff505558610ea818b2e6 100644 (file)
@@ -26,7 +26,8 @@ import java.util.stream.Collectors;
 import com.google.gwt.animation.client.AnimationScheduler;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
-import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Float;
+import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.dom.client.TableRowElement;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Window;
@@ -39,7 +40,6 @@ import com.vaadin.client.widget.escalator.RowContainer;
 import com.vaadin.client.widget.grid.selection.SelectionModel;
 import com.vaadin.client.widgets.Escalator;
 import com.vaadin.client.widgets.Grid;
-import com.vaadin.server.SerializableFunction;
 import com.vaadin.shared.Range;
 import com.vaadin.shared.ui.Connect;
 import com.vaadin.shared.ui.dnd.DragSourceState;
@@ -150,8 +150,8 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
     protected void setDragImage(NativeEvent dragStartEvent) {
         // do not call super since need to handle specifically
         // 1. use resource if set (never needs safari hack)
-        // 2. add number badge if necessary (with safari hack if needed)
-        // 3. just use normal (with safari hack if needed)
+        // 2. add row count badge if necessary
+        // 3. apply hacks for safari/mobile drag image if needed
 
         // Add badge showing the number of dragged columns
         String imageUrl = getResourceUrl(DragSourceState.RESOURCE_DRAG_IMAGE);
@@ -171,13 +171,18 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
                                 + STYLE_SUFFIX_DRAG_BADGE);
                 badge.setInnerHTML(draggedItemKeys.size() + "");
 
-                badge.getStyle().setMarginLeft(
-                        getRelativeX(draggedRowElement, dragStartEvent) + 10,
-                        Style.Unit.PX);
-                badge.getStyle().setMarginTop(
-                        getRelativeY(draggedRowElement, dragStartEvent)
-                                - draggedRowElement.getOffsetHeight() + 10,
-                        Style.Unit.PX);
+                if (BrowserInfo.get().isTouchDevice()) {
+                    // the drag image is centered on the touch coordinates
+                    // -> show the badge on the right edge of the row
+                    badge.getStyle().setFloat(Float.RIGHT);
+                    badge.getStyle().setMarginRight(20, Unit.PX);
+                } else {
+                    badge.getStyle().setMarginLeft(
+                            getRelativeX(draggedRowElement, dragStartEvent)
+                                    + 10,
+                            Unit.PX);
+                }
+                badge.getStyle().setMarginTop(-20, Unit.PX);
 
                 draggedRowElement.appendChild(badge);
 
@@ -187,15 +192,11 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
                     badge.removeFromParent();
                 }, (Element) dragStartEvent.getEventTarget().cast());
             }
-            fixDragImageForSafari(draggedRowElement);
+            fixDragImageForDesktopSafari(draggedRowElement);
+            fixDragImageTransformForMobile(draggedRowElement);
         }
     }
 
-    private int getRelativeY(Element element, NativeEvent event) {
-        int relativeTop = element.getAbsoluteTop() - Window.getScrollTop();
-        return WidgetUtil.getTouchOrMouseClientY(event) - relativeTop;
-    }
-
     private int getRelativeX(Element element, NativeEvent event) {
         int relativeLeft = element.getAbsoluteLeft() - Window.getScrollLeft();
         return WidgetUtil.getTouchOrMouseClientX(event) - relativeLeft;
@@ -204,8 +205,8 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
     @Override
     protected Map<String, String> createDataTransferData(
             NativeEvent dragStartEvent) {
-        Map<String, String> dataMap = super
-                .createDataTransferData(dragStartEvent);
+        Map<String, String> dataMap = super.createDataTransferData(
+                dragStartEvent);
 
         // Add data provided by the generator functions
         getDraggedRows(dragStartEvent).forEach(row -> {
@@ -331,9 +332,9 @@ public class GridDragSourceConnector extends DragSourceExtensionConnector {
      * Gets drag data provided by the generator functions.
      *
      * @param row
-     *         The row data.
+     *            The row data.
      * @return The generated drag data type mapped to the corresponding drag
-     * data. If there are no generator functions, returns an empty map.
+     *         data. If there are no generator functions, returns an empty map.
      */
     private Map<String, String> getRowDragData(JsonObject row) {
         // Collect a map of data types and data that is provided by the
index 7d79fb74dce8620a60d92089a9b1144ab99c5a59..61ff4dea8a721ef8956544cef86e017da598e46b 100644 (file)
@@ -211,20 +211,22 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
     }
 
     /**
-     * Fixes missing drag image for Safari by making the dragged element
+     * Fixes missing drag image for desktop Safari by making the dragged element
      * position to relative if needed. Safari won't show drag image unless the
      * dragged element position is relative or absolute / fixed, but not with
      * display block for the latter.
      * <p>
-     * This method is a NOOP for non-safari browser.
+     * This method is a NOOP for non-safari browser, or mobile safari which is
+     * using the DnD Polyfill.
      * <p>
      * This fix is not needed if a custom drag image is used on Safari.
      *
      * @param draggedElement
      *            the element that forms the drag image
      */
-    protected void fixDragImageForSafari(Element draggedElement) {
-        if (!BrowserInfo.get().isSafari()) {
+    protected void fixDragImageForDesktopSafari(Element draggedElement) {
+        if (!BrowserInfo.get().isSafari()
+                || BrowserInfo.get().isTouchDevice()) {
             return;
         }
         final Style style = draggedElement.getStyle();
@@ -252,13 +254,41 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
         }, draggedElement);
     }
 
+    /**
+     * Fix drag image offset for touch devices when the dragged image has been
+     * offset with css transform: translate/translate3d.
+     * <p>
+     * This necessary for e.g grid rows.
+     * <p>
+     * This method is NOOP for non-touch browsers.
+     *
+     * @param draggedElement
+     *            the element that forms the drag image
+     */
+    protected void fixDragImageTransformForMobile(Element draggedElement) {
+        if (!BrowserInfo.get().isTouchDevice()) {
+            return;
+        }
+
+        Style style = draggedElement.getStyle();
+        String transition = style.getProperty("transform");
+        if (transition == null || transition.isEmpty()
+                || !transition.startsWith("translate")) {
+            return;
+        }
+        style.clearProperty("transform");
+        AnimationScheduler.get().requestAnimationFrame(timestamp -> {
+            draggedElement.getStyle().setProperty("transform", transition);
+        }, draggedElement);
+    }
+
     /**
      * Creates the data map to be set as the {@code DataTransfer} object's data.
      *
      * @param dragStartEvent
-     *         The drag start event
+     *            The drag start event
      * @return The map from type to data, or {@code null} for not setting any
-     * data. Returning {@code null} will cancel the drag start.
+     *         data. Returning {@code null} will cancel the drag start.
      */
     protected Map<String, String> createDataTransferData(
             NativeEvent dragStartEvent) {
@@ -299,8 +329,10 @@ public class DragSourceExtensionConnector extends AbstractExtensionConnector {
             dragStartEvent.getDataTransfer()
                     .setDragImage(dragImage.getElement(), 0, 0);
         } else {
-            fixDragImageForSafari(
-                    (Element) dragStartEvent.getCurrentEventTarget().cast());
+            Element draggedElement = (Element) dragStartEvent
+                    .getCurrentEventTarget().cast();
+            fixDragImageForDesktopSafari(draggedElement);
+            fixDragImageTransformForMobile(draggedElement);
         }
     }
 
index 49a7e181b29f4cc67f29338a2893c38c117f6fd7..5618cabb19e0ca4ac762efdc22a0875d788025bc 100644 (file)
@@ -1231,9 +1231,11 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
         }
     }
 
-    // TODO add configuration to use custom drag start decider
     private static native void initializeMobileDndPolyfill()
     /*-{
-        $wnd.DragDropPolyfill.Initialize();
+         var conf = new Object();
+         // this is needed or the drag image will offset to weird place in for grid rows
+         conf['dragImageCenterOnTouch'] = true;
+         $wnd.DragDropPolyfill.Initialize(conf);
     }-*/;
 }
index d64958305f03759989e4a2eba29aef043d3d9e40..fcac0b174323322dbadda9302cbb8bc918a0de5c 100644 (file)
@@ -24,6 +24,8 @@ public class DragImage extends AbstractTestUIWithLog {
 
     @Override
     protected void setup(VaadinRequest request) {
+        setMobileHtml5DndEnabled(true);
+
         HorizontalLayout layout1 = new HorizontalLayout();
         layout1.setCaption("No custom drag image");
         Styles styles = Page.getCurrent().getStyles();