summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java139
-rw-r--r--client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java223
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DragEndEvent.java77
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DragEndListener.java40
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DragSourceExtension.java226
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DragStartEvent.java77
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DragStartListener.java40
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DropEvent.java77
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DropListener.java38
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/DropTargetExtension.java145
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceRpc.java35
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceState.java55
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/dnd/DropEffect.java41
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetRpc.java42
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetState.java38
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/dnd/EffectAllowed.java81
-rw-r--r--themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss2
-rw-r--r--themes/src/main/themes/VAADIN/themes/valo/shared/_overlay.scss6
-rw-r--r--uitest/src/main/java/com/vaadin/tests/dnd/DragAndDropCardShuffle.java153
19 files changed, 1535 insertions, 0 deletions
diff --git a/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java b/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
new file mode 100644
index 0000000000..25e2912b7a
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/extensions/DragSourceExtensionConnector.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.extensions;
+
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.dom.client.DataTransfer;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.event.dnd.DragSourceExtension;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.dnd.DragSourceRpc;
+import com.vaadin.shared.ui.dnd.DragSourceState;
+
+import elemental.events.Event;
+import elemental.events.EventListener;
+import elemental.events.EventTarget;
+
+/**
+ * Extension to add drag source functionality to a widget for using HTML5 drag
+ * and drop. Client side counterpart of {@link DragSourceExtension}.
+ */
+@Connect(DragSourceExtension.class)
+public class DragSourceExtensionConnector extends AbstractExtensionConnector {
+
+ private static final String CLASS_DRAGGABLE = "v-draggable";
+
+ // Create event listeners
+ private final EventListener dragStartListener = this::onDragStart;
+ private final EventListener dragEndListener = this::onDragEnd;
+
+ @Override
+ protected void extend(ServerConnector target) {
+ Element dragSourceElement = getDraggableElement();
+
+ dragSourceElement.setDraggable(Element.DRAGGABLE_TRUE);
+ dragSourceElement.addClassName(CLASS_DRAGGABLE);
+
+ EventTarget dragSource = dragSourceElement.cast();
+
+ // dragstart
+ dragSource.addEventListener(Event.DRAGSTART, dragStartListener);
+
+ // dragend
+ dragSource.addEventListener(Event.DRAGEND, dragEndListener);
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+
+ EventTarget dragSource = (EventTarget) getDraggableElement();
+
+ // Remove listeners
+ dragSource.removeEventListener(Event.DRAGSTART, dragStartListener);
+ dragSource.removeEventListener(Event.DRAGEND, dragEndListener);
+ }
+
+ /**
+ * Event handler for the {@code dragstart} event. Called when {@code
+ * dragstart} event occurs.
+ *
+ * @param event
+ * browser event to be handled
+ */
+ protected void onDragStart(Event event) {
+ // Convert elemental event to have access to dataTransfer
+ NativeEvent nativeEvent = (NativeEvent) event;
+
+ // Set effectAllowed parameter
+ if (getState().effectAllowed != null) {
+ setEffectAllowed(nativeEvent.getDataTransfer(),
+ getState().effectAllowed.getValue());
+ }
+
+ // Set data parameter
+ List<String> types = getState().types;
+ Map<String, String> data = getState().data;
+ for (String format : types) {
+ nativeEvent.getDataTransfer().setData(format, data.get(format));
+ }
+
+ // Initiate firing server side dragstart event when there is a
+ // DragStartListener attached on the server side
+ if (hasEventListener(DragSourceState.EVENT_DRAGSTART)) {
+ getRpcProxy(DragSourceRpc.class).dragStart();
+ }
+ }
+
+ /**
+ * Event handler for the {@code dragend} event. Called when {@code dragend}
+ * event occurs.
+ *
+ * @param event
+ */
+ protected void onDragEnd(Event event) {
+ // Initiate server start dragend event when there is a DragEndListener
+ // attached on the server side
+ if (hasEventListener(DragSourceState.EVENT_DRAGEND)) {
+ getRpcProxy(DragSourceRpc.class).dragEnd();
+ }
+ }
+
+ /**
+ * Finds the draggable element within the widget. By default, returns the
+ * topmost element.
+ *
+ * @return the draggable element in the parent widget.
+ */
+ protected Element getDraggableElement() {
+ return ((ComponentConnector) getParent()).getWidget().getElement();
+ }
+
+ private native void setEffectAllowed(DataTransfer dataTransfer,
+ String effectAllowed)/*-{
+ dataTransfer.effectAllowed = effectAllowed;
+ }-*/;
+
+ @Override
+ public DragSourceState getState() {
+ return (DragSourceState) super.getState();
+ }
+}
diff --git a/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java b/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
new file mode 100644
index 0000000000..5d72a76696
--- /dev/null
+++ b/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.extensions;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.dom.client.BrowserEvents;
+import com.google.gwt.dom.client.DataTransfer;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.event.dnd.DropTargetExtension;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.dnd.DropTargetRpc;
+import com.vaadin.shared.ui.dnd.DropTargetState;
+
+import elemental.events.Event;
+import elemental.events.EventListener;
+import elemental.events.EventTarget;
+
+/**
+ * Extension to add drop target functionality to a widget for using HTML5 drag
+ * and drop. Client side counterpart of {@link DropTargetExtension}.
+ */
+@Connect(DropTargetExtension.class)
+public class DropTargetExtensionConnector extends AbstractExtensionConnector {
+
+ private static final String CLASS_DRAG_OVER = "v-drag-over";
+
+ // Create event listeners
+ private final EventListener dragEnterListener = this::onDragEnter;
+ private final EventListener dragOverListener = this::onDragOver;
+ private final EventListener dragLeaveListener = this::onDragLeave;
+ private final EventListener dropListener = this::onDrop;
+
+ @Override
+ protected void extend(ServerConnector target) {
+ EventTarget dropTarget = getDropTargetElement().cast();
+
+ // dragenter event
+ dropTarget.addEventListener(BrowserEvents.DRAGENTER, dragEnterListener);
+
+ // dragover event
+ dropTarget.addEventListener(BrowserEvents.DRAGOVER, dragOverListener);
+
+ // dragleave event
+ dropTarget.addEventListener(BrowserEvents.DRAGLEAVE, dragLeaveListener);
+
+ // drop event
+ dropTarget.addEventListener(BrowserEvents.DROP, dropListener);
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+
+ EventTarget dropTarget = getDropTargetElement().cast();
+
+ // Remove listeners
+ dropTarget.removeEventListener(BrowserEvents.DRAGENTER,
+ dragEnterListener);
+ dropTarget.removeEventListener(BrowserEvents.DRAGOVER,
+ dragOverListener);
+ dropTarget.removeEventListener(BrowserEvents.DRAGLEAVE,
+ dragLeaveListener);
+ dropTarget.removeEventListener(BrowserEvents.DROP, dropListener);
+ }
+
+ /**
+ * Finds the drop target element within the widget. By default, returns the
+ * topmost element.
+ *
+ * @return the drop target element in the parent widget.
+ */
+ protected Element getDropTargetElement() {
+ return ((ComponentConnector) getParent()).getWidget().getElement();
+ }
+
+ /**
+ * Event handler for the {@code dragenter} event.
+ *
+ * @param event
+ * browser event to be handled
+ */
+ protected void onDragEnter(Event event) {
+ addTargetIndicator(getDropTargetElement());
+ }
+
+ /**
+ * Event handler for the {@code dragover} event.
+ *
+ * @param event
+ * browser event to be handled
+ */
+ protected void onDragOver(Event event) {
+ NativeEvent nativeEvent = (NativeEvent) event;
+ if (isDragOverAllowed(nativeEvent)) {
+ // Set dropEffect parameter
+ if (getState().dropEffect != null) {
+ nativeEvent.getDataTransfer().setDropEffect(
+ DataTransfer.DropEffect
+ .valueOf(getState().dropEffect.name()));
+ }
+
+ // Prevent default to allow drop
+ nativeEvent.preventDefault();
+ nativeEvent.stopPropagation();
+ } else {
+ // Remove drop effect
+ nativeEvent.getDataTransfer()
+ .setDropEffect(DataTransfer.DropEffect.NONE);
+
+ // Remove drop target indicator
+ removeTargetIndicator(getDropTargetElement());
+ }
+ }
+
+ /**
+ * Determines if dragover event is allowed on this drop target according to
+ * the dragover criteria.
+ *
+ * @param event
+ * Native dragover event.
+ * @return {@code true} if dragover is allowed, {@code false} otherwise.
+ * @see DropTargetExtension#setDragOverCriteria(String)
+ */
+ protected boolean isDragOverAllowed(NativeEvent event) {
+ if (getState().dragOverCriteria != null) {
+ return executeScript(event, getState().dragOverCriteria);
+ }
+
+ // Allow when criteria not set
+ return true;
+ }
+
+ /**
+ * Event handler for the {@code dragleave} event.
+ *
+ * @param event
+ * browser event to be handled
+ */
+ protected void onDragLeave(Event event) {
+ removeTargetIndicator(getDropTargetElement());
+ }
+
+ /**
+ * Event handler for the {@code drop} event.
+ *
+ * @param event
+ * browser event to be handled
+ */
+ protected void onDrop(Event event) {
+ NativeEvent nativeEvent = (NativeEvent) event;
+ if (dropAllowed(nativeEvent)) {
+ nativeEvent.preventDefault();
+ nativeEvent.stopPropagation();
+
+ // Initiate firing server side drop event
+ JsArrayString typesJsArray = getTypes(
+ nativeEvent.getDataTransfer());
+ List<String> types = new ArrayList<>();
+ Map<String, String> data = new HashMap<>();
+ for (int i = 0; i < typesJsArray.length(); i++) {
+ types.add(typesJsArray.get(i));
+ data.put(typesJsArray.get(i), nativeEvent.getDataTransfer()
+ .getData(typesJsArray.get(i)));
+ }
+
+ getRpcProxy(DropTargetRpc.class)
+ .drop(types, data, getState().dropEffect);
+ }
+
+ removeTargetIndicator(getDropTargetElement());
+ }
+
+ private boolean dropAllowed(NativeEvent event) {
+ if (getState().dropCriteria != null) {
+ return executeScript(event, getState().dropCriteria);
+ }
+
+ // Allow when criteria not set
+ return true;
+ }
+
+ private void addTargetIndicator(Element element) {
+ element.addClassName(CLASS_DRAG_OVER);
+ }
+
+ private void removeTargetIndicator(Element element) {
+ element.removeClassName(CLASS_DRAG_OVER);
+ }
+
+ private native boolean executeScript(NativeEvent event, String script)/*-{
+ return new Function('event', script)(event);
+ }-*/;
+
+ private native JsArrayString getTypes(DataTransfer dataTransfer)/*-{
+ return dataTransfer.types;
+ }-*/;
+
+ @Override
+ public DropTargetState getState() {
+ return (DropTargetState) super.getState();
+ }
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DragEndEvent.java b/server/src/main/java/com/vaadin/event/dnd/DragEndEvent.java
new file mode 100644
index 0000000000..6f094ce9e2
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DragEndEvent.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.vaadin.shared.ui.dnd.EffectAllowed;
+import com.vaadin.ui.Component;
+
+/**
+ * Server side dragend event. Fired when an HTML5 dragend happens.
+ *
+ * @see DragSourceExtension#addDragEndListener(DragEndListener)
+ */
+public class DragEndEvent extends Component.Event {
+ private final Map<String, String> data;
+ private final EffectAllowed effectAllowed;
+
+ /**
+ * Creates a new server side dragend event.
+ *
+ * @param source
+ * Draggable component.
+ * @param types
+ * List of data types from {@code DataTransfer.types}.
+ * @param data
+ * Map of all data from {@code DataTransfer}.
+ * @param effectAllowed
+ * Parameter from {@code DataTransfer.effectAllowed}.
+ */
+ public DragEndEvent(Component source, List<String> types,
+ Map<String, String> data, EffectAllowed effectAllowed) {
+ super(source);
+
+ // Create a linked map that preserves the order of types
+ this.data = new LinkedHashMap<>();
+ types.forEach(type -> this.data.put(type, data.get(type)));
+
+ this.effectAllowed = effectAllowed;
+ }
+
+ /**
+ * Get data from the client side {@code DataTransfer} object.
+ *
+ * @param format
+ * Data format, e.g. {@code text/plain} or {@code text/uri-list}.
+ * @return Data for the given format if exists in the client side {@code
+ * DataTransfer}, otherwise {@code null}.
+ */
+ public String getTransferData(String format) {
+ return data != null ? data.get(format) : null;
+ }
+
+ /**
+ * Returns the {@code effectAllowed} parameter of this event.
+ *
+ * @return This event's {@code effectAllowed} parameter.
+ */
+ public EffectAllowed getEffectAllowed() {
+ return effectAllowed;
+ }
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DragEndListener.java b/server/src/main/java/com/vaadin/event/dnd/DragEndListener.java
new file mode 100644
index 0000000000..00a020353d
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DragEndListener.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.lang.reflect.Method;
+
+import com.vaadin.event.ConnectorEventListener;
+
+/**
+ * Interface to be implemented when creating a dragend listener on a drag
+ * source for HTML5 drag and drop.
+ *
+ * @see DragSourceExtension#addDragEndListener(DragEndListener)
+ */
+@FunctionalInterface
+public interface DragEndListener extends ConnectorEventListener {
+ static final Method DRAGEND_METHOD = DragEndListener.class
+ .getDeclaredMethods()[0];
+
+ /**
+ * Called when a server side dragend event is fired.
+ *
+ * @param event
+ * The dragend event that is fired.
+ */
+ void dragEnd(DragEndEvent event);
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DragSourceExtension.java b/server/src/main/java/com/vaadin/event/dnd/DragSourceExtension.java
new file mode 100644
index 0000000000..d90e1bd8b8
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DragSourceExtension.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import com.vaadin.server.AbstractClientConnector;
+import com.vaadin.server.AbstractExtension;
+import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.dnd.DragSourceRpc;
+import com.vaadin.shared.ui.dnd.DragSourceState;
+import com.vaadin.shared.ui.dnd.EffectAllowed;
+import com.vaadin.ui.AbstractComponent;
+
+/**
+ * Extension to add drag source functionality to a component for using HTML5
+ * drag and drop.
+ */
+public class DragSourceExtension extends AbstractExtension {
+
+ /**
+ * Constructor for {@link DragSourceExtension}
+ */
+ public DragSourceExtension() {
+ registerRpc(new DragSourceRpc() {
+ @Override
+ public void dragStart() {
+ DragStartEvent event = new DragStartEvent(
+ (AbstractComponent) getParent(), getState(false).types,
+ getState(false).data, getState(false).effectAllowed);
+ fireEvent(event);
+ }
+
+ @Override
+ public void dragEnd() {
+ DragEndEvent event = new DragEndEvent(
+ (AbstractComponent) getParent(), getState(false).types,
+ getState(false).data, getState(false).effectAllowed);
+ fireEvent(event);
+ }
+ });
+ }
+
+ /**
+ * Makes {@code target} component a drag source.
+ *
+ * @param target
+ * Component to be extended.
+ */
+ public void extend(AbstractComponent target) {
+ super.extend(target);
+ }
+
+ /**
+ * Sets the allowed effects for the current drag source element. Used for
+ * setting client side {@code DataTransfer.effectAllowed} parameter for the
+ * drag event.
+ * <p>
+ * By default the value is {@link EffectAllowed#UNINITIALIZED} which is
+ * equivalent to {@link EffectAllowed#ALL}.
+ *
+ * @param effect
+ * Effects to allow for this draggable element. Cannot be {@code
+ * null}.
+ */
+ public void setEffectAllowed(EffectAllowed effect) {
+ if (effect == null) {
+ throw new IllegalArgumentException("Allowed effect cannot be null");
+ }
+ if (!Objects.equals(getState(false).effectAllowed, effect)) {
+ getState().effectAllowed = effect;
+ }
+ }
+
+ /**
+ * Returns the allowed effects for the current drag source element. Used to
+ * set client side {@code DataTransfer.effectAllowed} parameter for the drag
+ * event.
+ *
+ * @return Effects that are allowed for this draggable element.
+ */
+ public EffectAllowed getEffectAllowed() {
+ return getState(false).effectAllowed;
+ }
+
+ /**
+ * Sets the data for this drag source element. Used to set data for client
+ * side drag element using {@code DataTransfer.setData()}. To be used as a
+ * map, key-value pairs are stored. Order of entries are preserved.
+ * <p>
+ * Note that by HTML specification, the browser will change data type
+ * "{@code text}" to "{@code text/plain}" and "{@code url}" to "{@code
+ * text/uri-list}" during client side drag event.
+ *
+ * @param format
+ * Data type to store, e.g. {@code text/plain} or {@code
+ * text/uri-list}. Cannot be {@code null}.
+ * @param data
+ * Data to store for the data type. Cannot be {@code null}.
+ */
+ public void setTransferData(String format, String data) {
+ if (format == null) {
+ throw new IllegalArgumentException("Data type cannot be null");
+ }
+
+ if (data == null) {
+ throw new IllegalArgumentException("Data cannot be null");
+ }
+
+ if (!getState(false).types.contains(format)) {
+ getState().types.add(format);
+ }
+ getState().data.put(format, data);
+ }
+
+ /**
+ * Returns the data stored for {@code format} type in this drag source
+ * element.
+ *
+ * @param format
+ * Data type of the requested data, e.g. {@code text/plain} or
+ * {@code text/uri-list}.
+ * @return Data that is stored for {@code format} data type.
+ */
+ public String getTransferData(String format) {
+ return getState(false).data.get(format);
+ }
+
+ /**
+ * 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<String, String> getTransferData() {
+ Map<String, String> data = getState(false).data;
+
+ // Create a map of data that preserves the order of types
+ LinkedHashMap<String, String> orderedData = new LinkedHashMap<>(
+ data.size());
+ getState(false).types
+ .forEach(type -> orderedData.put(type, data.get(type)));
+
+ return Collections.unmodifiableMap(orderedData);
+ }
+
+ /**
+ * Clears data with the given type for this drag source element when
+ * present.
+ *
+ * @param format
+ * Type of data to be cleared. Cannot be {@code null}.
+ */
+ public void clearTransferData(String format) {
+ if (format == null) {
+ throw new IllegalArgumentException("Data type cannot be null");
+ }
+
+ getState().types.remove(format);
+ getState().data.remove(format);
+ }
+
+ /**
+ * Clears all data for this drag source element.
+ */
+ public void clearTransferData() {
+ getState().types.clear();
+ getState().data.clear();
+ }
+
+ /**
+ * Attaches dragstart listener for the current drag source. {@link
+ * DragStartListener#dragStart(DragStartEvent)} is called when dragstart
+ * event happens on the client side.
+ *
+ * @param listener
+ * Listener to handle dragstart event.
+ * @return Handle to be used to remove this listener.
+ */
+ public Registration addDragStartListener(DragStartListener listener) {
+ return addListener(DragSourceState.EVENT_DRAGSTART,
+ DragStartEvent.class, listener,
+ DragStartListener.DRAGSTART_METHOD);
+ }
+
+ /**
+ * Attaches dragend listener for the current drag source. {@link
+ * DragEndListener#dragEnd(DragEndEvent)} is called when dragend
+ * event happens on the client side.
+ *
+ * @param listener
+ * Listener to handle dragend event.
+ * @return Handle to be used to remove this listener.
+ */
+ public Registration addDragEndListener(DragEndListener listener) {
+ return addListener(DragSourceState.EVENT_DRAGEND, DragEndEvent.class,
+ listener, DragEndListener.DRAGEND_METHOD);
+ }
+
+ @Override
+ protected DragSourceState getState() {
+ return (DragSourceState) super.getState();
+ }
+
+ @Override
+ protected DragSourceState getState(boolean markAsDirty) {
+ return (DragSourceState) super.getState(markAsDirty);
+ }
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DragStartEvent.java b/server/src/main/java/com/vaadin/event/dnd/DragStartEvent.java
new file mode 100644
index 0000000000..591a0e61a7
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DragStartEvent.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.vaadin.shared.ui.dnd.EffectAllowed;
+import com.vaadin.ui.Component;
+
+/**
+ * Server side dragstart event. Fired when an HTML5 dragstart happens.
+ *
+ * @see DragSourceExtension#addDragStartListener(DragStartListener)
+ */
+public class DragStartEvent extends Component.Event {
+ private final Map<String, String> data;
+ private final EffectAllowed effectAllowed;
+
+ /**
+ * Creates a new server side dragend event.
+ *
+ * @param source
+ * Draggable component.
+ * @param types
+ * List of data types from {@code DataTransfer.types}.
+ * @param data
+ * Map of all data from {@code DataTransfer}.
+ * @param effectAllowed
+ * Parameter from {@code DataTransfer.effectAllowed}.
+ */
+ public DragStartEvent(Component source, List<String> types,
+ Map<String, String> data, EffectAllowed effectAllowed) {
+ super(source);
+
+ // Create a linked map that preserves the order of types
+ this.data = new LinkedHashMap<>();
+ types.forEach(type -> this.data.put(type, data.get(type)));
+
+ this.effectAllowed = effectAllowed;
+ }
+
+ /**
+ * Get data from the client side {@code DataTransfer} object.
+ *
+ * @param format
+ * Data format, e.g. {@code text/plain} or {@code text/uri-list}.
+ * @return Data for the given format if exists in the client side {@code
+ * DataTransfer}, otherwise {@code null}.
+ */
+ public String getTransferData(String format) {
+ return data != null ? data.get(format) : null;
+ }
+
+ /**
+ * Returns the {@code effectAllowed} parameter of this event.
+ *
+ * @return This event's {@code effectAllowed} parameter.
+ */
+ public EffectAllowed getEffectAllowed() {
+ return effectAllowed;
+ }
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DragStartListener.java b/server/src/main/java/com/vaadin/event/dnd/DragStartListener.java
new file mode 100644
index 0000000000..8d691dee6b
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DragStartListener.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.lang.reflect.Method;
+
+import com.vaadin.event.ConnectorEventListener;
+
+/**
+ * Interface to be implemented when creating a dragstart listener on a drag
+ * source for HTML5 drag and drop.
+ *
+ * @see DragSourceExtension#addDragStartListener(DragStartListener)
+ */
+@FunctionalInterface
+public interface DragStartListener extends ConnectorEventListener {
+ static final Method DRAGSTART_METHOD = DragStartListener.class
+ .getDeclaredMethods()[0];
+
+ /**
+ * Called when a server side dragstart event is fired.
+ *
+ * @param event
+ * The dragstart event that is fired.
+ */
+ void dragStart(DragStartEvent event);
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DropEvent.java b/server/src/main/java/com/vaadin/event/dnd/DropEvent.java
new file mode 100644
index 0000000000..382b93bc55
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DropEvent.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.vaadin.shared.ui.dnd.DropEffect;
+import com.vaadin.ui.Component;
+
+/**
+ * Server side drop event. Fired when an HTML5 drop happens.
+ *
+ * @see DropTargetExtension#addDropListener(DropListener)
+ */
+public class DropEvent extends Component.Event {
+ private final Map<String, String> data;
+ private final DropEffect dropEffect;
+
+ /**
+ * Creates a new server side drop event.
+ *
+ * @param source
+ * Drop target component.
+ * @param types
+ * List of data types from {@code DataTransfer.types}.
+ * @param data
+ * Map of all data from {@code DataTransfer}.
+ * @param dropEffect
+ * Parameter from {@code DataTransfer.dropEffect}.
+ */
+ public DropEvent(Component source, List<String> types,
+ Map<String, String> data, DropEffect dropEffect) {
+ super(source);
+
+ // Create a linked map that preserves the order of types
+ this.data = new LinkedHashMap<>();
+ types.forEach(type -> this.data.put(type, data.get(type)));
+
+ this.dropEffect = dropEffect;
+ }
+
+ /**
+ * Get data from the client side {@code DataTransfer} object.
+ *
+ * @param format
+ * Data format, e.g. {@code text/plain} or {@code text/uri-list}.
+ * @return Data for the given format if exists in the client side {@code
+ * DataTransfer}, otherwise {@code null}.
+ */
+ public String getTransferData(String format) {
+ return data != null ? data.get(format) : null;
+ }
+
+ /**
+ * Get drop effect set for the current drop target.
+ *
+ * @return {@code dropEffect} parameter set for the current drop target.
+ */
+ public DropEffect getDropEffect() {
+ return dropEffect;
+ }
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DropListener.java b/server/src/main/java/com/vaadin/event/dnd/DropListener.java
new file mode 100644
index 0000000000..8cb96d1852
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DropListener.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.lang.reflect.Method;
+
+import com.vaadin.event.ConnectorEventListener;
+
+/**
+ * Interface to be implemented when creating a drop listener on a drop target
+ * for HTML5 drag and drop. See {@link DropTargetExtension#addDropListener(DropListener)}.
+ */
+@FunctionalInterface
+public interface DropListener extends ConnectorEventListener {
+ static final Method DROP_METHOD = DropListener.class
+ .getDeclaredMethods()[0];
+
+ /**
+ * Called when a server side drop event is fired.
+ *
+ * @param event
+ * The drop event that is fired.
+ */
+ void drop(DropEvent event);
+}
diff --git a/server/src/main/java/com/vaadin/event/dnd/DropTargetExtension.java b/server/src/main/java/com/vaadin/event/dnd/DropTargetExtension.java
new file mode 100644
index 0000000000..20819ec70f
--- /dev/null
+++ b/server/src/main/java/com/vaadin/event/dnd/DropTargetExtension.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.event.dnd;
+
+import java.util.Objects;
+
+import com.vaadin.server.AbstractClientConnector;
+import com.vaadin.server.AbstractExtension;
+import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.dnd.DropEffect;
+import com.vaadin.shared.ui.dnd.DropTargetRpc;
+import com.vaadin.shared.ui.dnd.DropTargetState;
+import com.vaadin.ui.AbstractComponent;
+
+/**
+ * Extension to add drop target functionality to a widget for using HTML5 drag
+ * and drop.
+ */
+public class DropTargetExtension extends AbstractExtension {
+
+ /**
+ * Constructor for {@link DropTargetExtension}.
+ */
+ public DropTargetExtension() {
+ registerRpc((DropTargetRpc) (types, data, dropEffect) -> {
+ DropEvent event = new DropEvent((AbstractComponent) getParent(),
+ types, data, dropEffect);
+
+ fireEvent(event);
+ });
+ }
+
+ /**
+ * Makes {@code target} component a drop target.
+ *
+ * @param target
+ * Component to be extended.
+ */
+ public void extend(AbstractComponent target) {
+ super.extend(target);
+ }
+
+ /**
+ * Sets the drop effect for the current drop target. Used for the client
+ * side {@code DataTransfer.dropEffect} parameter.
+ * <p>
+ * Default value is browser dependent and can depend on e.g. modifier keys.
+ *
+ * @param dropEffect
+ * The drop effect to be set. Cannot be {@code null}.
+ */
+ public void setDropEffect(DropEffect dropEffect) {
+ if (dropEffect == null) {
+ throw new IllegalArgumentException("Drop effect cannot be null.");
+ }
+
+ if (!Objects.equals(getState(false).dropEffect, dropEffect)) {
+ getState().dropEffect = dropEffect;
+ }
+ }
+
+ /**
+ * Returns the drop effect for the current drop target.
+ *
+ * @return The drop effect of this drop target.
+ */
+ public DropEffect getDropEffect() {
+ return getState(false).dropEffect;
+ }
+
+ /**
+ * Sets criteria to allow dragover event on the current drop target. The
+ * script executes when dragover event happens and stops the event in case
+ * the script returns {@code false}.
+ *
+ * @param criteriaScript
+ * JavaScript to be executed when dragover event happens or {@code
+ * null} to clear.
+ */
+ public void setDragOverCriteria(String criteriaScript) {
+ if (!Objects.equals(getState(false).dragOverCriteria, criteriaScript)) {
+ getState().dragOverCriteria = criteriaScript;
+ }
+ }
+
+ /**
+ * Sets criteria to allow drop event on the current drop target. The script
+ * executes when drop event happens and stops the event in case the script
+ * returns {@code false}.
+ *
+ * @param criteriaScript
+ * JavaScript to be executed when drop event happens or {@code null}
+ * to clear.
+ */
+ public void setDropCriteria(String criteriaScript) {
+ if (!Objects.equals(getState(false).dropCriteria, criteriaScript)) {
+ getState().dropCriteria = criteriaScript;
+ }
+ }
+
+ /**
+ * Returns the criteria for allowing drop event on the current drop target.
+ *
+ * @return JavaScript that executes when drop event happens.
+ */
+ public String getDropCriteria() {
+ return getState(false).dropCriteria;
+ }
+
+ /**
+ * Attaches drop listener for the current drop target. {@link
+ * DropListener#drop(DropEvent)} is called when drop event happens on the
+ * client side.
+ *
+ * @param listener
+ * Listener to handle drop event.
+ * @return Handle to be used to remove this listener.
+ */
+ public Registration addDropListener(DropListener listener) {
+ return addListener(DropEvent.class, listener, DropListener.DROP_METHOD);
+ }
+
+ @Override
+ protected DropTargetState getState() {
+ return (DropTargetState) super.getState();
+ }
+
+ @Override
+ protected DropTargetState getState(boolean markAsDirty) {
+ return (DropTargetState) super.getState(markAsDirty);
+ }
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceRpc.java b/shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceRpc.java
new file mode 100644
index 0000000000..bbad423044
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceRpc.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.dnd;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * RPC for firing server side event when client side dragstart event happens on
+ * drag source.
+ */
+public interface DragSourceRpc extends ServerRpc {
+
+ /**
+ * Called when dragsource event happens on client side.
+ */
+ public void dragStart();
+
+ /**
+ * Called when dragend event happens on client side.
+ */
+ public void dragEnd();
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceState.java b/shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceState.java
new file mode 100644
index 0000000000..aeb4dd816b
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/dnd/DragSourceState.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.dnd;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.vaadin.shared.communication.SharedState;
+
+/**
+ * State class containing parameters for DragSourceExtension.
+ */
+public class DragSourceState extends SharedState {
+
+ /**
+ * Event identifier for dragend event.
+ */
+ public static final String EVENT_DRAGEND = "dragend";
+
+ /**
+ * Event identifier for dragstart event.
+ */
+ public static final String EVENT_DRAGSTART = "dragstart";
+
+ /**
+ * {@code DataTransfer.effectAllowed} parameter for the drag event.
+ */
+ public EffectAllowed effectAllowed = EffectAllowed.UNINITIALIZED;
+
+ /**
+ * {@code DataTransfer.types} parameter. Used to keep track of data formats
+ * set for the drag event.
+ */
+ public List<String> types = new ArrayList<>();
+
+ /**
+ * Used to store data in the {@code DataTransfer} object for the drag event.
+ */
+ public Map<String, String> data = new HashMap<>();
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/dnd/DropEffect.java b/shared/src/main/java/com/vaadin/shared/ui/dnd/DropEffect.java
new file mode 100644
index 0000000000..5056ecfd78
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/dnd/DropEffect.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.dnd;
+
+/**
+ * Used to specify the drop effect to use on dragenter or dragover events.
+ */
+public enum DropEffect {
+ /**
+ * A copy of the source item is made at the new location.
+ */
+ COPY,
+
+ /**
+ * An item is moved to a new location.
+ */
+ MOVE,
+
+ /**
+ * A link is established to the source at the new location.
+ */
+ LINK,
+
+ /**
+ * The item may not be dropped.
+ */
+ NONE
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetRpc.java b/shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetRpc.java
new file mode 100644
index 0000000000..dd21278277
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetRpc.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.dnd;
+
+import java.util.List;
+import java.util.Map;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * RPC for firing server side drop event when client side drop event happens on
+ * drop target.
+ */
+public interface DropTargetRpc extends ServerRpc {
+
+ /**
+ * Called when drop event happens on client side.
+ *
+ * @param types
+ * Data types that are present in {@code data} map in the same order
+ * as found in {@code DataTransfer.types}.
+ * @param data
+ * Contains data from {@code DataTransfer} object.
+ * @param dropEffect
+ * Drop effect set for the drop target where drop happened.
+ */
+ public void drop(List<String> types, Map<String, String> data,
+ DropEffect dropEffect);
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetState.java b/shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetState.java
new file mode 100644
index 0000000000..3021c0bd6b
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/dnd/DropTargetState.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.dnd;
+
+import com.vaadin.shared.communication.SharedState;
+
+/**
+ * State class containing parameters for DropTargetExtension.
+ */
+public class DropTargetState extends SharedState {
+ /**
+ * {@code DataTransfer.dropEffect} parameter for the drag event
+ */
+ public DropEffect dropEffect;
+
+ /**
+ * Criteria script to allow dragOver event on the element
+ */
+ public String dragOverCriteria;
+
+ /**
+ * Criteria script to allow drop event on the element
+ */
+ public String dropCriteria;
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/dnd/EffectAllowed.java b/shared/src/main/java/com/vaadin/shared/ui/dnd/EffectAllowed.java
new file mode 100644
index 0000000000..2ff9f21980
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/dnd/EffectAllowed.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.dnd;
+
+/**
+ * Used to specify the effect that is allowed for a drag operation.
+ */
+public enum EffectAllowed {
+ /**
+ * The item may not be dropped.
+ */
+ NONE("none"),
+
+ /**
+ * A copy of the source item may be made at the new location.
+ */
+ COPY("copy"),
+
+ /**
+ * An item may be moved to a new location.
+ */
+ MOVE("move"),
+
+ /**
+ * A link may be established to the source at the new location.
+ */
+ LINK("link"),
+
+ /**
+ * A copy or move operation is permitted.
+ */
+ COPY_MOVE("copyMove"),
+
+ /**
+ * A copy or link operation is permitted.
+ */
+ COPY_LINK("copyLink"),
+
+ /**
+ * A link or move operation is permitted.
+ */
+ LINK_MOVE("linkMove"),
+
+ /**
+ * All operations are permitted.
+ */
+ ALL("all"),
+
+ /**
+ * Default state, equivalent to ALL
+ */
+ UNINITIALIZED("uninitialized");
+
+ private final String value;
+
+ EffectAllowed(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Get the string value that is accepted by the client side drag event.
+ *
+ * @return String value accepted by the client side drag event.
+ */
+ public String getValue() {
+ return value;
+ }
+}
diff --git a/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss b/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss
index 3c4761ad32..441e073dcf 100644
--- a/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss
+++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss
@@ -345,6 +345,8 @@ $valo-shared-pathPrefix: null;
@include valo-drag-element;
+ @include valo-draggable;
+
@include valo-tooltip;
@include valo-contextmenu;
diff --git a/themes/src/main/themes/VAADIN/themes/valo/shared/_overlay.scss b/themes/src/main/themes/VAADIN/themes/valo/shared/_overlay.scss
index 1c6f0c6fbc..5b44e94cac 100644
--- a/themes/src/main/themes/VAADIN/themes/valo/shared/_overlay.scss
+++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_overlay.scss
@@ -275,6 +275,12 @@ $v-selection-item-selection-color: $v-selection-color !default;
}
}
+@mixin valo-draggable {
+ .v-draggable {
+ user-select: none !important;
+ }
+}
+
/**
* Outputs the styles for generic dragging ghost elements.
*
diff --git a/uitest/src/main/java/com/vaadin/tests/dnd/DragAndDropCardShuffle.java b/uitest/src/main/java/com/vaadin/tests/dnd/DragAndDropCardShuffle.java
new file mode 100644
index 0000000000..24c3940737
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/dnd/DragAndDropCardShuffle.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.dnd;
+
+import java.util.Optional;
+
+import com.vaadin.event.dnd.DragSourceExtension;
+import com.vaadin.event.dnd.DropTargetExtension;
+import com.vaadin.server.Extension;
+import com.vaadin.server.Page;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+
+public class DragAndDropCardShuffle extends AbstractTestUIWithLog {
+
+ // Data type for storing card position
+ private static final String DATA_INDEX = "index";
+
+ // Create cards
+ private final Label ace = new Label("A");
+ private final Label jack = new Label("J");
+ private final Label queen = new Label("Q");
+ private final Label king = new Label("K");
+
+ // Create desk
+ private final HorizontalLayout desk = new HorizontalLayout();
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ // Create UI and add extensions
+ desk.addComponents(ace, jack, queen, king);
+
+ ace.setStyleName("card");
+ addDragSourceExtension(ace);
+ addDropTargetExtension(ace);
+
+ jack.setStyleName("card");
+ addDragSourceExtension(jack);
+ addDropTargetExtension(jack);
+
+ queen.setStyleName("card");
+ addDragSourceExtension(queen);
+ addDropTargetExtension(queen);
+
+ king.setStyleName("card");
+ addDragSourceExtension(king);
+ addDropTargetExtension(king);
+
+ addComponent(desk);
+
+ // Add styling
+ setStyle();
+ }
+
+ private void addDragSourceExtension(Label source) {
+ // Create and attach extension
+ DragSourceExtension dragSource = new DragSourceExtension();
+ dragSource.extend(source);
+
+ // Set component position as transfer data
+ dragSource.setTransferData(DATA_INDEX,
+ String.valueOf(desk.getComponentIndex(source)));
+
+ // Add listeners
+ dragSource.addDragStartListener(event -> {
+ event.getComponent().addStyleName("dragged");
+ log(((Label) event.getComponent()).getValue() + " dragstart");
+ });
+
+ dragSource.addDragEndListener(event -> {
+ event.getComponent().removeStyleName("dragged");
+ log(((Label) event.getComponent()).getValue() + " dragend");
+ });
+ }
+
+ private void addDropTargetExtension(Label target) {
+ // Create and attach extension
+ DropTargetExtension dropTarget = new DropTargetExtension();
+ dropTarget.extend(target);
+
+ // Add listener
+ dropTarget.addDropListener(event -> {
+ // Retrieve the source's position
+ int sourceIndex = Integer
+ .valueOf(event.getTransferData(DATA_INDEX));
+
+ // Find source component
+ Component source = desk.getComponent(sourceIndex);
+
+ // Swap source and target components
+ desk.replaceComponent(target, source);
+
+ // Get DragSource extension for target component and set position data
+ Optional<Extension> targetExt = target.getExtensions().stream()
+ .filter(e -> e instanceof DragSourceExtension).findFirst();
+ targetExt.ifPresent(extension -> {
+ ((DragSourceExtension) extension).setTransferData(DATA_INDEX,
+ String.valueOf(desk.getComponentIndex(target)));
+ });
+
+ // Get DragSource extension for source component and set position data
+ Optional<Extension> sourceExt = source.getExtensions().stream()
+ .filter(e -> e instanceof DragSourceExtension).findFirst();
+ sourceExt.ifPresent(extension -> {
+ ((DragSourceExtension) extension).setTransferData(DATA_INDEX,
+ String.valueOf(desk.getComponentIndex(source)));
+ });
+
+ log(((Label) source).getValue() + " dropped onto " + ((Label) event
+ .getComponent()).getValue());
+ });
+ }
+
+ private void setStyle() {
+ Page.Styles styles = Page.getCurrent().getStyles();
+
+ styles.add(".card {"
+ + "width: 150px;"
+ + "height: 200px;"
+ + "border: 1px solid black;"
+ + "border-radius: 7px;"
+ + "padding-left: 10px;"
+ + "color: red;"
+ + "font-weight: bolder;"
+ + "font-size: 25px;"
+ + "background-color: gainsboro;"
+ + "}");
+ styles.add(".v-drag-over {border-style: dashed;}");
+ styles.add(".dragged {opacity: .4;}");
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Shuffle cards with pure HTML5 drag and drop";
+ }
+}