From 69e47a5010cec7b632ad61dc852f74facbfcf162 Mon Sep 17 00:00:00 2001 From: caalador Date: Thu, 21 Nov 2024 13:59:03 +0200 Subject: [PATCH] fix: attach element when used in drag source (#20490) * fix: attach element when used in drag source Attach elemnt to dom and move it outside of the viewport to have it visible as a drag image. Image can be used without attaching to dom. Hidden elements are also not shown so throw exception when using one as dragImage. Fixes #20426 * Use display none for added element * Log as debug Log attach as debug now that the Co-authored-by: Mikhail Shabarov <61410877+mshabarov@users.noreply.github.com> --------- Co-authored-by: Mikhail Shabarov <61410877+mshabarov@users.noreply.github.com> --- .../vaadin/flow/component/dnd/DragSource.java | 28 ++++++++++++++++--- .../resources/frontend/dndConnector.js | 8 ++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/flow-dnd/src/main/java/com/vaadin/flow/component/dnd/DragSource.java b/flow-dnd/src/main/java/com/vaadin/flow/component/dnd/DragSource.java index 7e799cef943..b3fa8e28227 100644 --- a/flow-dnd/src/main/java/com/vaadin/flow/component/dnd/DragSource.java +++ b/flow-dnd/src/main/java/com/vaadin/flow/component/dnd/DragSource.java @@ -17,6 +17,8 @@ import java.util.Locale; +import org.slf4j.LoggerFactory; + import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEventListener; import com.vaadin.flow.component.ComponentUtil; @@ -25,6 +27,7 @@ import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.dnd.internal.DndUtil; import com.vaadin.flow.dom.Element; +import com.vaadin.flow.dom.Style; import com.vaadin.flow.internal.nodefeature.VirtualChildrenList; import com.vaadin.flow.shared.Registration; @@ -344,6 +347,10 @@ default void setDragImage(Component dragImage) { * the y-offset of the drag image */ default void setDragImage(Component dragImage, int offsetX, int offsetY) { + if (dragImage != null && !dragImage.isVisible()) { + throw new IllegalStateException( + "Drag image element is not visible and will not show.\nMake element visible to use as drag image!"); + } if (getDragImage() != null && getDragImage() != dragImage) { // Remove drag image from the virtual children list if it's there. if (getDraggableElement().getNode() @@ -362,14 +369,12 @@ default void setDragImage(Component dragImage, int offsetX, int offsetY) { getDragSourceComponent().addAttachListener(event -> { if (!dragImage.isAttached() && dragImage.getParent().isEmpty()) { - getDraggableElement() - .appendVirtualChild(dragImage.getElement()); + appendDragElement(dragImage.getElement()); } event.unregisterListener(); }); } else { - getDraggableElement() - .appendVirtualChild(dragImage.getElement()); + appendDragElement(dragImage.getElement()); } } ComponentUtil.setData(getDragSourceComponent(), @@ -380,6 +385,21 @@ default void setDragImage(Component dragImage, int offsetX, int offsetY) { (dragImage == null ? 0 : offsetY), getDraggableElement()); } + private void appendDragElement(Element dragElement) { + if (dragElement.getTag().equals("img")) { + getDraggableElement().appendVirtualChild(dragElement); + } else { + LoggerFactory.getLogger(DragSource.class).debug( + "Attaching child to dom in position -100,-100. Consider adding the component manually to not get overlapping components on drag for element."); + getDraggableElement().appendChild(dragElement); + Style style = dragElement.getStyle(); + style.set("position", "absolute"); + style.set("top", "-100px"); + style.set("left", "-100px"); + style.set("display", "none"); + } + } + /** * Get server side drag image. This image is applied automatically in the * next drag start event in the browser. diff --git a/flow-dnd/src/main/resources/META-INF/resources/frontend/dndConnector.js b/flow-dnd/src/main/resources/META-INF/resources/frontend/dndConnector.js index 853dec45483..5450db3083b 100644 --- a/flow-dnd/src/main/resources/META-INF/resources/frontend/dndConnector.js +++ b/flow-dnd/src/main/resources/META-INF/resources/frontend/dndConnector.js @@ -93,6 +93,10 @@ window.Vaadin.Flow.dndConnector = { event.currentTarget.classList.add('v-dragged'); } if(event.currentTarget.__dragImage) { + if(event.currentTarget.__dragImage.style.display === "none") { + event.currentTarget.__dragImage.style.display = "block"; + event.currentTarget.classList.add('shown'); + } event.dataTransfer.setDragImage( event.currentTarget.__dragImage, event.currentTarget.__dragImageOffsetX, @@ -102,6 +106,10 @@ window.Vaadin.Flow.dndConnector = { __dragendListener: function (event) { event.currentTarget.classList.remove('v-dragged'); + if(event.currentTarget.classList.contains('shown')) { + event.currentTarget.classList.remove('shown'); + event.currentTarget.__dragImage.style.display = "none"; + } }, updateDragSource: function (element) {