summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Wagner <wbadam@users.noreply.github.com>2017-04-07 09:52:06 +0300
committerHenri Sara <henri.sara@gmail.com>2017-04-12 14:58:11 +0300
commita773c8c7b365e4041db87b5d9ddaad0bdc244a91 (patch)
tree422ce4db5bde123c7dc775d70e49e259c17b2dce
parent659313e8c35e68d14fe2599b9bbb4dbba35fb4a3 (diff)
downloadvaadin-framework-a773c8c7b365e4041db87b5d9ddaad0bdc244a91.tar.gz
vaadin-framework-a773c8c7b365e4041db87b5d9ddaad0bdc244a91.zip
Make it possible to drop things between Grid rows (#8979)
Fixes #8401
-rw-r--r--client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetExtensionConnector.java93
-rw-r--r--client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java6
-rw-r--r--server/src/main/java/com/vaadin/event/dnd/grid/GridDropEvent.java27
-rw-r--r--server/src/main/java/com/vaadin/ui/GridDropTargetExtension.java62
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/DropLocation.java40
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.java38
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionRpc.java5
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionState.java4
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java58
9 files changed, 284 insertions, 49 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetExtensionConnector.java b/client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetExtensionConnector.java
index 9c25f5acb4..dacc8316ad 100644
--- a/client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetExtensionConnector.java
+++ b/client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetExtensionConnector.java
@@ -15,18 +15,21 @@
*/
package com.vaadin.client.connectors.grid;
-import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.TableRowElement;
+import com.google.gwt.user.client.Window;
import com.vaadin.client.ServerConnector;
+import com.vaadin.client.WidgetUtil;
import com.vaadin.client.extensions.DropTargetExtensionConnector;
import com.vaadin.client.widget.escalator.RowContainer;
import com.vaadin.client.widgets.Escalator;
import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.DropLocation;
+import com.vaadin.shared.ui.grid.DropMode;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionRpc;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionState;
import com.vaadin.shared.ui.grid.GridState;
@@ -46,6 +49,21 @@ import elemental.json.JsonObject;
public class GridDropTargetExtensionConnector extends
DropTargetExtensionConnector {
+ // Drag over class name suffixes
+ private final static String CLASS_SUFFIX_BEFORE = "-before";
+ private final static String CLASS_SUFFIX_AFTER = "-after";
+
+ // Drag over class names
+ private final static String CLASS_DRAG_OVER_BEFORE =
+ CLASS_DRAG_OVER + CLASS_SUFFIX_BEFORE;
+ private final static String CLASS_DRAG_OVER_AFTER =
+ CLASS_DRAG_OVER + CLASS_SUFFIX_AFTER;
+
+ /**
+ * Current drag over class name
+ */
+ private String dragOverClassName;
+
private GridConnector gridConnector;
@Override
@@ -60,15 +78,19 @@ public class GridDropTargetExtensionConnector extends
Event dropEvent) {
String rowKey = null;
+ DropLocation dropLocation = null;
+
Optional<TableRowElement> targetRow = getTargetRow(
(Element) dropEvent.getTarget());
if (targetRow.isPresent()) {
rowKey = getRowData(targetRow.get())
.getString(GridState.JSONKEY_ROWKEY);
+ dropLocation = getDropLocation(targetRow.get(),
+ (NativeEvent) dropEvent);
}
getRpcProxy(GridDropTargetExtensionRpc.class)
- .drop(dataTransferText, rowKey);
+ .drop(dataTransferText, rowKey, dropLocation);
}
private JsonObject getRowData(TableRowElement row) {
@@ -77,16 +99,71 @@ public class GridDropTargetExtensionConnector extends
return gridConnector.getDataSource().getRow(rowIndex);
}
+ /**
+ * Returns the location of the event within the row.
+ */
+ private DropLocation getDropLocation(Element target, NativeEvent event) {
+ if (getState().dropMode == DropMode.BETWEEN) {
+ if (getRelativeY(target, event) < (target.getOffsetHeight() / 2)) {
+ return DropLocation.ABOVE;
+ } else {
+ return DropLocation.BELOW;
+ }
+ }
+ return DropLocation.ON_TOP;
+ }
+
+ private int getRelativeY(Element element, NativeEvent event) {
+ int relativeTop = element.getAbsoluteTop() - Window.getScrollTop();
+ return WidgetUtil.getTouchOrMouseClientY(event) - relativeTop;
+ }
+
@Override
- protected void addTargetIndicator(Event event) {
- getTargetRow(((Element) event.getTarget()))
- .ifPresent(e -> e.addClassName(CLASS_DRAG_OVER));
+ protected void setTargetIndicator(Event event) {
+ getTargetRow(((Element) event.getTarget())).ifPresent(target -> {
+
+ // Get required class name
+ String className = getTargetClassName(target, (NativeEvent) event);
+
+ // Add or replace class name if changed
+ if (!target.hasClassName(className)) {
+ if (dragOverClassName != null) {
+ target.removeClassName(dragOverClassName);
+ }
+ target.addClassName(className);
+ dragOverClassName = className;
+ }
+ });
+ }
+
+ private String getTargetClassName(Element target, NativeEvent event) {
+ String classSuffix;
+
+ switch (getDropLocation(target, event)) {
+ case ABOVE:
+ classSuffix = CLASS_SUFFIX_BEFORE;
+ break;
+ case BELOW:
+ classSuffix = CLASS_SUFFIX_AFTER;
+ break;
+ case ON_TOP:
+ default:
+ classSuffix = "";
+ break;
+ }
+
+ return CLASS_DRAG_OVER + classSuffix;
}
@Override
protected void removeTargetIndicator(Event event) {
- getTargetRow(((Element) event.getTarget()))
- .ifPresent(e -> e.removeClassName(CLASS_DRAG_OVER));
+
+ // Remove all possible drag over class names
+ getTargetRow((Element) event.getTarget()).ifPresent(e -> {
+ e.removeClassName(CLASS_DRAG_OVER);
+ e.removeClassName(CLASS_DRAG_OVER_BEFORE);
+ e.removeClassName(CLASS_DRAG_OVER_AFTER);
+ });
}
private Optional<TableRowElement> getTargetRow(Element source) {
diff --git a/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java b/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
index 473b72237e..8cba063572 100644
--- a/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
+++ b/client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
@@ -117,7 +117,7 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
* browser event to be handled
*/
protected void onDragEnter(Event event) {
- addTargetIndicator(event);
+ setTargetIndicator(event);
}
/**
@@ -137,7 +137,7 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
}
// Add drop target indicator in case the element doesn't have one
- addTargetIndicator(event);
+ setTargetIndicator(event);
// Prevent default to allow drop
nativeEvent.preventDefault();
@@ -230,7 +230,7 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
* @param event
* The drag enter or dragover event that triggered the indication.
*/
- protected void addTargetIndicator(Event event) {
+ protected void setTargetIndicator(Event event) {
getDropTargetElement().addClassName(CLASS_DRAG_OVER);
}
diff --git a/server/src/main/java/com/vaadin/event/dnd/grid/GridDropEvent.java b/server/src/main/java/com/vaadin/event/dnd/grid/GridDropEvent.java
index 07ba1327a6..98d1b3495b 100644
--- a/server/src/main/java/com/vaadin/event/dnd/grid/GridDropEvent.java
+++ b/server/src/main/java/com/vaadin/event/dnd/grid/GridDropEvent.java
@@ -17,11 +17,12 @@ package com.vaadin.event.dnd.grid;
import com.vaadin.event.dnd.DragSourceExtension;
import com.vaadin.event.dnd.DropEvent;
+import com.vaadin.shared.ui.grid.DropLocation;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Grid;
/**
- * Server side drop event on an HTML5 drop target {@link Grid} row.
+ * Drop event on an HTML5 drop target {@link Grid} row.
*
* @param <T>
* The Grid bean type.
@@ -32,9 +33,10 @@ import com.vaadin.ui.Grid;
public class GridDropEvent<T> extends DropEvent<Grid<T>> {
private final T dropTargetRow;
+ private final DropLocation dropLocation;
/**
- * Creates a server side Grid row drop event.
+ * Creates a Grid row drop event.
*
* @param target
* Grid that received the drop.
@@ -44,16 +46,18 @@ public class GridDropEvent<T> extends DropEvent<Grid<T>> {
* @param dragSourceExtension
* Drag source extension of the component that initiated the drop
* event.
- * @param dropTargetRowKey
- * Key of the target row that received the drop.
+ * @param dropTargetRow
+ * Target row that received the drop.
+ * @param dropLocation
+ * Location of the drop within the target row.
*/
public GridDropEvent(Grid<T> target, String dataTransferText,
DragSourceExtension<? extends AbstractComponent> dragSourceExtension,
- String dropTargetRowKey) {
+ T dropTargetRow, DropLocation dropLocation) {
super(target, dataTransferText, dragSourceExtension);
- dropTargetRow = target.getDataCommunicator().getKeyMapper()
- .get(dropTargetRowKey);
+ this.dropTargetRow = dropTargetRow;
+ this.dropLocation = dropLocation;
}
/**
@@ -64,4 +68,13 @@ public class GridDropEvent<T> extends DropEvent<Grid<T>> {
public T getDropTargetRow() {
return dropTargetRow;
}
+
+ /**
+ * Get the location of the drop within the row.
+ *
+ * @return Location of the drop within the row.
+ */
+ public DropLocation getDropLocation() {
+ return dropLocation;
+ }
}
diff --git a/server/src/main/java/com/vaadin/ui/GridDropTargetExtension.java b/server/src/main/java/com/vaadin/ui/GridDropTargetExtension.java
index 1fcb7160f4..17633fa5ce 100644
--- a/server/src/main/java/com/vaadin/ui/GridDropTargetExtension.java
+++ b/server/src/main/java/com/vaadin/ui/GridDropTargetExtension.java
@@ -19,6 +19,7 @@ import com.vaadin.event.dnd.DropTargetExtension;
import com.vaadin.event.dnd.grid.GridDropEvent;
import com.vaadin.event.dnd.grid.GridDropListener;
import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.grid.DropMode;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionRpc;
import com.vaadin.shared.ui.grid.GridDropTargetExtensionState;
@@ -32,18 +33,47 @@ import com.vaadin.shared.ui.grid.GridDropTargetExtensionState;
* @since
*/
public class GridDropTargetExtension<T> extends DropTargetExtension<Grid<T>> {
- public GridDropTargetExtension(Grid<T> target) {
+
+ /**
+ * Extends a Grid and makes it's rows drop targets for HTML5 drag and drop.
+ *
+ * @param target
+ * Grid to be extended.
+ * @param dropMode
+ * Drop mode that describes the allowed drop locations within the
+ * Grid's row.
+ * @see GridDropEvent#getDropLocation()
+ */
+ public GridDropTargetExtension(Grid<T> target, DropMode dropMode) {
super(target);
+
+ setDropMode(dropMode);
}
- @Override
- protected void registerDropTargetRpc(Grid<T> target) {
- registerRpc((GridDropTargetExtensionRpc) (dataTransferText, rowKey) -> {
- GridDropEvent<T> event = new GridDropEvent<>(target,
- dataTransferText, getUI().getActiveDragSource(), rowKey);
+ /**
+ * Sets the drop mode of this drop target.
+ *
+ * @param dropMode
+ * Drop mode that describes the allowed drop locations within the
+ * Grid's row.
+ * @see GridDropEvent#getDropLocation()
+ */
+ public void setDropMode(DropMode dropMode) {
+ if (dropMode == null) {
+ throw new IllegalArgumentException("Drop mode cannot be null");
+ }
+
+ getState().dropMode = dropMode;
+ }
- fireEvent(event);
- });
+ /**
+ * Gets the drop mode of this drop target.
+ *
+ * @return Drop mode that describes the allowed drop locations within the
+ * Grid's row.
+ */
+ public DropMode getDropMode() {
+ return getState(false).dropMode;
}
/**
@@ -61,6 +91,22 @@ public class GridDropTargetExtension<T> extends DropTargetExtension<Grid<T>> {
}
@Override
+ protected void registerDropTargetRpc(Grid<T> target) {
+ registerRpc(
+ (GridDropTargetExtensionRpc) (dataTransferText, rowKey, dropLocation) -> {
+
+ T dropTargetRow = target.getDataCommunicator()
+ .getKeyMapper().get(rowKey);
+
+ GridDropEvent<T> event = new GridDropEvent<>(target,
+ dataTransferText, getUI().getActiveDragSource(),
+ dropTargetRow, dropLocation);
+
+ fireEvent(event);
+ });
+ }
+
+ @Override
protected GridDropTargetExtensionState getState() {
return (GridDropTargetExtensionState) super.getState();
}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/DropLocation.java b/shared/src/main/java/com/vaadin/shared/ui/grid/DropLocation.java
new file mode 100644
index 0000000000..1453c05c71
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/DropLocation.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.shared.ui.grid;
+
+/**
+ * Defines drop locations within a Grid row.
+ *
+ * @author Vaadin Ltd.
+ * @since
+ */
+public enum DropLocation {
+
+ /**
+ * Drop on top of the row.
+ */
+ ON_TOP,
+
+ /**
+ * Drop above or before the row.
+ */
+ ABOVE,
+
+ /**
+ * Drop below or after the row.
+ */
+ BELOW
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.java b/shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.java
new file mode 100644
index 0000000000..2db639be7d
--- /dev/null
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/DropMode.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.grid;
+
+/**
+ * Defines the locations within the Grid row where an element can be dropped.
+ *
+ * @author Vaadin Ltd.
+ * @since
+ */
+public enum DropMode {
+
+ /**
+ * The drop event can happen between Grid rows. The drop is above a row
+ * when the cursor is over the top 50% of a row, otherwise below the
+ * row.
+ */
+ BETWEEN,
+
+ /**
+ * The drop event can happen on top of Grid rows. The target of the drop
+ * is the row under the cursor at the time of the drop event.
+ */
+ ON_TOP,
+}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionRpc.java b/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionRpc.java
index ef0dc405b5..212081d486 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionRpc.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionRpc.java
@@ -34,6 +34,9 @@ public interface GridDropTargetExtensionRpc extends ServerRpc {
* object.
* @param rowKey
* Key of the row on which the drop event occured.
+ * @param dropLocation
+ * Location of the drop within the row.
*/
- public void drop(String dataTransferText, String rowKey);
+ public void drop(String dataTransferText, String rowKey,
+ DropLocation dropLocation);
}
diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionState.java b/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionState.java
index c911d529d0..50b50a5d24 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionState.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/grid/GridDropTargetExtensionState.java
@@ -25,4 +25,8 @@ import com.vaadin.shared.ui.dnd.DropTargetState;
*/
public class GridDropTargetExtensionState extends DropTargetState {
+ /**
+ * Stores the drop mode of the drop target Grid.
+ */
+ public DropMode dropMode;
}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java b/uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java
index 83adbad218..9c89177167 100644
--- a/uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java
+++ b/uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java
@@ -20,16 +20,16 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
-import com.vaadin.event.dnd.grid.GridDropListener;
import com.vaadin.server.Page;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.grid.DropMode;
import com.vaadin.tests.components.AbstractTestUIWithLog;
-import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Grid;
import com.vaadin.ui.GridDragSourceExtension;
import com.vaadin.ui.GridDropTargetExtension;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Layout;
+import com.vaadin.ui.RadioButtonGroup;
import elemental.json.Json;
import elemental.json.JsonObject;
@@ -37,9 +37,10 @@ import elemental.json.JsonObject;
public class GridDragAndDrop extends AbstractTestUIWithLog {
@Override
protected void setup(VaadinRequest request) {
+
// Drag source Grid
Grid<Bean> dragSourceComponent = new Grid<>();
- dragSourceComponent.setItems(createItems(50));
+ dragSourceComponent.setItems(createItems(50, "left"));
dragSourceComponent.addColumn(Bean::getId).setCaption("ID");
dragSourceComponent.addColumn(Bean::getValue).setCaption("Value");
@@ -47,48 +48,61 @@ public class GridDragAndDrop extends AbstractTestUIWithLog {
dragSourceComponent);
dragSource.setDragDataGenerator(bean -> {
JsonObject ret = Json.createObject();
- ret.put("val", bean.getValue());
+ ret.put("generatedId", bean.getId());
+ ret.put("generatedValue", bean.getValue());
return ret;
});
// Drop target Grid
Grid<Bean> dropTargetComponent = new Grid<>();
- dropTargetComponent.setItems(createItems(5));
+ dropTargetComponent.setItems(createItems(5, "right"));
dropTargetComponent.addColumn(Bean::getId).setCaption("ID");
dropTargetComponent.addColumn(Bean::getValue).setCaption("Value");
GridDropTargetExtension<Bean> dropTarget = new GridDropTargetExtension<>(
- dropTargetComponent);
+ dropTargetComponent, DropMode.ON_TOP);
dropTarget.addGridDropListener(event -> {
log(event.getDataTransferText() + ", targetId=" + event
- .getDropTargetRow().getId());
+ .getDropTargetRow().getId() + ", location=" + event
+ .getDropLocation());
});
- // Layout grids
- Layout layout = new HorizontalLayout();
- layout.addComponents(dragSourceComponent, dropTargetComponent);
-
- // Selection mode combo box
- ComboBox<Grid.SelectionMode> selectionModeSwitch = new ComboBox<>(
- "Change selection mode");
- selectionModeSwitch.setItems(Arrays.asList(Grid.SelectionMode.SINGLE,
- Grid.SelectionMode.MULTI));
- selectionModeSwitch.setEmptySelectionAllowed(false);
- selectionModeSwitch.addValueChangeListener(event -> dragSourceComponent
+ // Layout the two grids
+ Layout grids = new HorizontalLayout();
+ grids.addComponents(dragSourceComponent, dropTargetComponent);
+
+ // Selection modes
+ List<Grid.SelectionMode> selectionModes = Arrays.asList(
+ Grid.SelectionMode.SINGLE, Grid.SelectionMode.MULTI);
+ RadioButtonGroup<Grid.SelectionMode> selectionModeSelect = new RadioButtonGroup<>(
+ "Selection mode", selectionModes);
+ selectionModeSelect.setSelectedItem(Grid.SelectionMode.SINGLE);
+ selectionModeSelect.addValueChangeListener(event -> dragSourceComponent
.setSelectionMode(event.getValue()));
- selectionModeSwitch.setSelectedItem(Grid.SelectionMode.SINGLE);
- addComponents(selectionModeSwitch, layout);
+ // Drop locations
+ List<DropMode> dropLocations = Arrays.asList(DropMode.values());
+ RadioButtonGroup<DropMode> dropLocationSelect = new RadioButtonGroup<>(
+ "Allowed drop location", dropLocations);
+ dropLocationSelect.setSelectedItem(DropMode.ON_TOP);
+ dropLocationSelect.addValueChangeListener(
+ event -> dropTarget.setDropMode(event.getValue()));
+
+ Layout controls = new HorizontalLayout(selectionModeSelect,
+ dropLocationSelect);
+
+ addComponents(controls, grids);
// Set dragover styling
Page.getCurrent().getStyles().add(".v-drag-over {color: red;}");
}
- private List<Bean> createItems(int num) {
+ private List<Bean> createItems(int num, String prefix) {
List<Bean> items = new ArrayList<>(num);
IntStream.range(0, num)
- .forEach(i -> items.add(new Bean("id_" + i, "value_" + i)));
+ .forEach(i -> items
+ .add(new Bean(prefix + "_" + i, "value_" + i)));
return items;
}