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;
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;
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);
+ 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);
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;
@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 -> {
* 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
}
/**
- * 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();
}, 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) {
dragStartEvent.getDataTransfer()
.setDragImage(dragImage.getElement(), 0, 0);
} else {
- fixDragImageForSafari(
- (Element) dragStartEvent.getCurrentEventTarget().cast());
+ Element draggedElement = (Element) dragStartEvent
+ .getCurrentEventTarget().cast();
+ fixDragImageForDesktopSafari(draggedElement);
+ fixDragImageTransformForMobile(draggedElement);
}
}