From eb743d965278d263a4c496bb4e39c067fe2b1a8c Mon Sep 17 00:00:00 2001 From: Adam Wagner Date: Tue, 16 May 2017 10:21:31 +0300 Subject: Add API to store any type of data in the dataTransfer object (#9319) --- .../vaadin/ui/components/grid/GridDropEvent.java | 24 +++-- .../vaadin/ui/components/grid/GridDropTarget.java | 11 +- .../com/vaadin/ui/dnd/DragSourceExtension.java | 113 +++++++++++++++++++-- .../com/vaadin/ui/dnd/DropTargetExtension.java | 29 ++++-- .../java/com/vaadin/ui/dnd/event/DragEndEvent.java | 1 - .../java/com/vaadin/ui/dnd/event/DropEvent.java | 56 +++++++--- 6 files changed, 189 insertions(+), 45 deletions(-) (limited to 'server') diff --git a/server/src/main/java/com/vaadin/ui/components/grid/GridDropEvent.java b/server/src/main/java/com/vaadin/ui/components/grid/GridDropEvent.java index 40df9f254f..08d0dad956 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/GridDropEvent.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/GridDropEvent.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui.components.grid; +import java.util.Map; + import com.vaadin.shared.ui.dnd.DropEffect; import com.vaadin.shared.ui.grid.DropLocation; import com.vaadin.ui.AbstractComponent; @@ -40,25 +42,25 @@ public class GridDropEvent extends DropEvent> { * Creates a Grid row drop event. * * @param target - * Grid that received the drop. - * @param dataTransferText - * Data of type {@code "text"} from the {@code DataTransfer} - * object. + * Grid that received the drop. + * @param data + * Map containing all types and corresponding data from the {@code + * DataTransfer} object. * @param dropEffect - * the desired drop effect + * the desired drop effect * @param dragSourceExtension - * Drag source extension of the component that initiated the drop - * event. + * Drag source extension of the component that initiated the drop + * event. * @param dropTargetRow - * Target row that received the drop. + * Target row that received the drop. * @param dropLocation - * Location of the drop within the target row. + * Location of the drop within the target row. */ - public GridDropEvent(Grid target, String dataTransferText, + public GridDropEvent(Grid target, Map data, DropEffect dropEffect, DragSourceExtension dragSourceExtension, T dropTargetRow, DropLocation dropLocation) { - super(target, dataTransferText, dropEffect, dragSourceExtension); + super(target, data, dropEffect, dragSourceExtension); this.dropTargetRow = dropTargetRow; this.dropLocation = dropLocation; diff --git a/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java b/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java index 435f40da6e..07c81c9981 100644 --- a/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java +++ b/server/src/main/java/com/vaadin/ui/components/grid/GridDropTarget.java @@ -15,6 +15,9 @@ */ package com.vaadin.ui.components.grid; +import java.util.LinkedHashMap; +import java.util.Map; + import com.vaadin.shared.Registration; import com.vaadin.shared.ui.dnd.DropEffect; import com.vaadin.shared.ui.grid.DropMode; @@ -130,14 +133,18 @@ public class GridDropTarget extends DropTargetExtension> { @Override protected void registerDropTargetRpc() { - registerRpc((GridDropTargetRpc) (dataTransferText, dropEffect, rowKey, + registerRpc((GridDropTargetRpc) (types, data, dropEffect, rowKey, dropLocation) -> { + // Create a linked map that preserves the order of types + Map dataPreserveOrder = new LinkedHashMap<>(); + types.forEach(type -> dataPreserveOrder.put(type, data.get(type))); + T dropTargetRow = getParent().getDataCommunicator().getKeyMapper() .get(rowKey); GridDropEvent event = new GridDropEvent<>(getParent(), - dataTransferText, + dataPreserveOrder, DropEffect.valueOf(dropEffect.toUpperCase()), getUI().getActiveDragSource(), dropTargetRow, dropLocation); diff --git a/server/src/main/java/com/vaadin/ui/dnd/DragSourceExtension.java b/server/src/main/java/com/vaadin/ui/dnd/DragSourceExtension.java index 24192fa592..42c29f738a 100644 --- a/server/src/main/java/com/vaadin/ui/dnd/DragSourceExtension.java +++ b/server/src/main/java/com/vaadin/ui/dnd/DragSourceExtension.java @@ -15,6 +15,9 @@ */ package com.vaadin.ui.dnd; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Objects; import com.vaadin.server.AbstractExtension; @@ -163,6 +166,14 @@ public class DragSourceExtension * Returns the allowed effects for the current drag source element. Used to * set client side {@code DataTransfer.effectAllowed} parameter for the drag * event. + *

+ * You can use different types of data to support dragging to different + * targets. Accepted types depend on the drop target and those can be + * platform specific. See https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types + * for examples on different types. + *

+ * NOTE: IE11 only supports type ' text', which can be set using {@link + * #setDataTransferText(String data)} * * @return Effects that are allowed for this draggable element. */ @@ -171,15 +182,81 @@ public class DragSourceExtension } /** - * Sets data for this drag source element. The data is set for the client - * side draggable element using the {@code DataTransfer.setData("text", - * data)} method. + * Sets data for this drag source element with the given type. The data is + * set for the client side draggable element using {@code + * DataTransfer.setData(type, data)} method. + *

+ * Note that {@code "text"} is the only cross browser supported data type. + * Use {@link #setDataTransferText(String)} method instead if your + * application supports IE11. * + * @param type + * Type of the data to be set for the client side draggable element, + * e.g. {@code text/plain}. Cannot be {@code null}. * @param data - * Data to be set for the client side draggable element. + * Data to be set for the client side draggable element. Cannot be + * {@code null}. + */ + public void setDataTransferData(String type, String data) { + if (type == null) { + throw new IllegalArgumentException("Data type cannot be null"); + } + + if (data == null) { + throw new IllegalArgumentException("Data cannot be null"); + } + + if (!getState(false).types.contains(type)) { + getState().types.add(type); + } + getState().data.put(type, data); + } + + /** + * Returns the data stored with type {@code type} in this drag source + * element. + * + * @param type + * Type of the requested data, e.g. {@code text/plain}. + * @return Data of type {@code type} stored in this drag source element. + */ + public String getDataTransferData(String type) { + return getState(false).data.get(type); + } + + /** + * Returns the map of data stored in this drag source element. The returned + * map preserves the order of storage and is unmodifiable. + * + * @return Unmodifiable copy of the map of data in the order the data was + * stored. + */ + public Map getDataTransferData() { + Map data = getState(false).data; + + // Create a map of data that preserves the order of types + LinkedHashMap orderedData = new LinkedHashMap<>( + data.size()); + getState(false).types + .forEach(type -> orderedData.put(type, data.get(type))); + + return Collections.unmodifiableMap(orderedData); + } + + /** + * Sets data of type {@code "text"} for this drag source element. The data + * is set for the client side draggable element using the {@code + * DataTransfer.setData("text", data)} method. + *

+ * Note that {@code "text"} is the only cross browser supported data type. + * Use this method if your application supports IE11. + * + * @param data + * Data to be set for the client side draggable element. + * @see #setDataTransferData(String, String) */ public void setDataTransferText(String data) { - getState().dataTransferText = data; + setDataTransferData(DragSourceState.DATA_TYPE_TEXT, data); } /** @@ -189,7 +266,31 @@ public class DragSourceExtension * @return Data of type {@code "text"} stored in this drag source element. */ public String getDataTransferText() { - return getState(false).dataTransferText; + return getDataTransferData(DragSourceState.DATA_TYPE_TEXT); + } + + /** + * Clears data with the given type for this drag source element when + * present. + * + * @param type + * Type of data to be cleared. Cannot be {@code null}. + */ + public void clearDataTransferData(String type) { + if (type == null) { + throw new IllegalArgumentException("Data type cannot be null"); + } + + getState().types.remove(type); + getState().data.remove(type); + } + + /** + * Clears all data for this drag source element. + */ + public void clearDataTransferData() { + getState().types.clear(); + getState().data.clear(); } /** diff --git a/server/src/main/java/com/vaadin/ui/dnd/DropTargetExtension.java b/server/src/main/java/com/vaadin/ui/dnd/DropTargetExtension.java index 24a0372f50..fddb636f70 100644 --- a/server/src/main/java/com/vaadin/ui/dnd/DropTargetExtension.java +++ b/server/src/main/java/com/vaadin/ui/dnd/DropTargetExtension.java @@ -15,6 +15,9 @@ */ package com.vaadin.ui.dnd; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Objects; import com.vaadin.server.AbstractExtension; @@ -62,12 +65,11 @@ public class DropTargetExtension * Override this method if you need to have a custom RPC interface for * transmitting the drop event with more data. If just need to do additional * things before firing the drop event, then you should override - * {@link #onDrop(String, DropEffect)} instead. + * {@link #onDrop(List, Map, DropEffect)} instead. */ protected void registerDropTargetRpc() { - registerRpc((DropTargetRpc) (dataTransferText, dropEffect) -> { - onDrop(dataTransferText, - DropEffect.valueOf(dropEffect.toUpperCase())); + registerRpc((DropTargetRpc) (types, data, dropEffect) -> { + onDrop(types, data, DropEffect.valueOf(dropEffect.toUpperCase())); }); } @@ -75,13 +77,22 @@ public class DropTargetExtension * Invoked when a drop has been received from client side. * Fires the {@link DropEvent}. * - * @param dataTransferText - * the data transfer of type 'text' for the drop + * @param types + * List of data types from {@code DataTransfer.types} object. + * @param data + * Map containing all types and corresponding data from the {@code + * DataTransfer} object. * @param dropEffect - * the drop effect + * the drop effect */ - protected void onDrop(String dataTransferText, DropEffect dropEffect) { - DropEvent event = new DropEvent<>(getParent(), dataTransferText, + protected void onDrop(List types, Map data, + DropEffect dropEffect) { + + // Create a linked map that preserves the order of types + Map dataPreserveOrder = new LinkedHashMap<>(); + types.forEach(type -> dataPreserveOrder.put(type, data.get(type))); + + DropEvent event = new DropEvent<>(getParent(), dataPreserveOrder, dropEffect, getUI().getActiveDragSource()); fireEvent(event); diff --git a/server/src/main/java/com/vaadin/ui/dnd/event/DragEndEvent.java b/server/src/main/java/com/vaadin/ui/dnd/event/DragEndEvent.java index 592a81497f..de0ba64a5e 100644 --- a/server/src/main/java/com/vaadin/ui/dnd/event/DragEndEvent.java +++ b/server/src/main/java/com/vaadin/ui/dnd/event/DragEndEvent.java @@ -64,7 +64,6 @@ public class DragEndEvent extends Component.Event { * dragend event. * @see DragSourceExtension#setEffectAllowed(EffectAllowed) * @see DropTargetExtension#setDropEffect(DropEffect) - * @see DropTargetExtension#setDragOverCriteria(String) * @see DropTargetExtension#setDropCriteria(String) */ public DropEffect getDropEffect() { diff --git a/server/src/main/java/com/vaadin/ui/dnd/event/DropEvent.java b/server/src/main/java/com/vaadin/ui/dnd/event/DropEvent.java index 45dabd0a62..db0e4aa7a9 100644 --- a/server/src/main/java/com/vaadin/ui/dnd/event/DropEvent.java +++ b/server/src/main/java/com/vaadin/ui/dnd/event/DropEvent.java @@ -15,8 +15,10 @@ */ package com.vaadin.ui.dnd.event; +import java.util.Map; import java.util.Optional; +import com.vaadin.shared.ui.dnd.DragSourceState; import com.vaadin.shared.ui.dnd.DropEffect; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Component; @@ -33,7 +35,7 @@ import com.vaadin.ui.dnd.DropTargetExtension; * @since 8.1 */ public class DropEvent extends Component.Event { - private final String dataTransferText; + private final Map data; private final DragSourceExtension dragSourceExtension; private final AbstractComponent dragSource; private final DropEffect dropEffect; @@ -42,37 +44,59 @@ public class DropEvent extends Component.Event { * Creates a server side drop event. * * @param target - * Component that received the drop. - * @param dataTransferText - * Data of type {@code "text"} from the {@code DataTransfer} - * object. + * Component that received the drop. + * @param data + * Map containing all types and corresponding data from the {@code + * DataTransfer} object. * @param dropEffect - * the desired drop effect + * the desired drop effect * @param dragSourceExtension - * Drag source extension of the component that initiated the drop - * event. + * Drag source extension of the component that initiated the drop + * event. */ - public DropEvent(T target, String dataTransferText, DropEffect dropEffect, + public DropEvent(T target, Map data, DropEffect dropEffect, DragSourceExtension dragSourceExtension) { super(target); - this.dataTransferText = dataTransferText; + this.data = data; this.dropEffect = dropEffect; - this.dragSourceExtension = dragSourceExtension; this.dragSource = Optional.ofNullable(dragSourceExtension) .map(DragSourceExtension::getParent).orElse(null); } /** - * Get data of type {@code "text"} from the client side {@code DataTransfer} - * object. + * Get data from the {@code DataTransfer} object. + * + * @param type + * Data format, e.g. {@code text/plain} or {@code text/uri-list}. + * @return Optional data for the given format if exists in the {@code + * DataTransfer}, otherwise {@code Optional.empty()}. + */ + public Optional getDataTransferData(String type) { + return Optional.ofNullable(data.get(type)); + } + + /** + * Get data of type {@code "text"} from the {@code DataTransfer} object. * - * @return Data of type {@code "text"} if exists in the client side {@code - * DataTransfer} object, otherwise {@literal null}. + * @return Data of type {@code "text"} if exists in the {@code DataTransfer} + * object, otherwise {@literal null}. */ public String getDataTransferText() { - return dataTransferText; + return data.get(DragSourceState.DATA_TYPE_TEXT); + } + + /** + * Get all of the transfer data from the {@code DataTransfer} object. The + * data can be iterated to find the most relevant data as it preserves the + * order in which the data was set to the drag source element. + * + * @return Map of type/data pairs, containing all the data from the {@code + * DataTransfer} object. + */ + public Map getDataTransferData() { + return data; } /** -- cgit v1.2.3