Browse Source

Make it possible for grid drop target to accept dragged data when grid is empty (#9332)

* Make it possible for grid drop target to accept dragged data when grid is empty (#9068)
* Make return type of getDropTargetRow() optional
tags/8.1.0.beta1
Adam Wagner 7 years ago
parent
commit
9dd70e13cd

+ 2
- 2
client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetConnector.java View File

} }


@Override @Override
protected void addTargetClassIndicator(NativeEvent event) {
protected void addDragOverStyle(NativeEvent event) {
getTargetRow(((Element) event.getEventTarget().cast())) getTargetRow(((Element) event.getEventTarget().cast()))
.ifPresent(target -> { .ifPresent(target -> {


} }


@Override @Override
protected void removeTargetClassIndicator(NativeEvent event) {
protected void removeDragOverStyle(NativeEvent event) {


// Remove all possible style names // Remove all possible style names
getTargetRow((Element) event.getEventTarget().cast()).ifPresent(e -> { getTargetRow((Element) event.getEventTarget().cast()).ifPresent(e -> {

+ 53
- 11
client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java View File

*/ */
protected static final String STYLE_SUFFIX_DRAG_BOTTOM = "-drag-bottom"; protected static final String STYLE_SUFFIX_DRAG_BOTTOM = "-drag-bottom";


/**
* Style name suffix for indicating that the element is drop target.
*/
protected static final String STYLE_SUFFIX_DROPTARGET = "-droptarget";

// Create event listeners // Create event listeners
private final EventListener dragEnterListener = this::onDragEnter; private final EventListener dragEnterListener = this::onDragEnter;
private final EventListener dragOverListener = this::onDragOver; private final EventListener dragOverListener = this::onDragOver;
addDropListeners(getDropTargetElement()); addDropListeners(getDropTargetElement());


((AbstractComponentConnector) target).onDropTargetAttached(); ((AbstractComponentConnector) target).onDropTargetAttached();

// Add drop target indicator to the drop target element
addDropTargetStyle();
} }


/** /**


removeDropListeners(getDropTargetElement()); removeDropListeners(getDropTargetElement());
((AbstractComponentConnector) getParent()).onDropTargetDetached(); ((AbstractComponentConnector) getParent()).onDropTargetDetached();

// Remove drop target indicator
removeDropTargetStyle();
} }


/** /**
+ STYLE_SUFFIX_DRAG_CENTER; + STYLE_SUFFIX_DRAG_CENTER;


if (isDropAllowed(nativeEvent)) { if (isDropAllowed(nativeEvent)) {
addTargetClassIndicator(nativeEvent);
addDragOverStyle(nativeEvent);


setDropEffect(nativeEvent); setDropEffect(nativeEvent);


if (isDropAllowed(nativeEvent)) { if (isDropAllowed(nativeEvent)) {
setDropEffect(nativeEvent); setDropEffect(nativeEvent);


// Add drop target indicator in case the element doesn't have one
addTargetClassIndicator(nativeEvent);
// Add drag over indicator in case the element doesn't have one
addDragOverStyle(nativeEvent);


// Prevent default to allow drop // Prevent default to allow drop
nativeEvent.preventDefault(); nativeEvent.preventDefault();
nativeEvent.getDataTransfer() nativeEvent.getDataTransfer()
.setDropEffect(DataTransfer.DropEffect.NONE); .setDropEffect(DataTransfer.DropEffect.NONE);


// Remove drop target indicator
removeTargetClassIndicator(nativeEvent);
// Remove drag over indicator
removeDragOverStyle(nativeEvent);
} }
} }


* browser event to be handled * browser event to be handled
*/ */
protected void onDragLeave(Event event) { protected void onDragLeave(Event event) {
removeTargetClassIndicator((NativeEvent) event);
removeDragOverStyle((NativeEvent) event);
} }


/** /**
.getDropEffect(nativeEvent.getDataTransfer()), nativeEvent); .getDropEffect(nativeEvent.getDataTransfer()), nativeEvent);
} }


removeTargetClassIndicator(nativeEvent);
removeDragOverStyle(nativeEvent);
} }


private boolean isDropAllowed(NativeEvent event) { private boolean isDropAllowed(NativeEvent event) {
} }


/** /**
* Add class that indicates that the component is a target.
* Add class name for the drop target element indicating that data can be
* dropped onto it. The class name has the following format:
* <pre>
* [primaryStyleName]-droptarget
* </pre>
* The added class name is update
* automatically by the framework when the primary style name changes.
*/
protected void addDropTargetStyle() {
getDropTargetElement().addClassName(
getStylePrimaryName(getDropTargetElement())
+ STYLE_SUFFIX_DROPTARGET);
}

/**
* Remove class name from the drop target element indication that data can
* be dropped onto it.
*/
protected void removeDropTargetStyle() {
getDropTargetElement().removeClassName(
getStylePrimaryName(getDropTargetElement())
+ STYLE_SUFFIX_DROPTARGET);
}

/**
* Add class that indicates that the component is a target while data is
* being dragged over it.
* <p> * <p>
* This is triggered on {@link #onDragEnter(Event) dragenter} and * This is triggered on {@link #onDragEnter(Event) dragenter} and
* {@link #onDragOver(Event) dragover} events pending if the drop is * {@link #onDragOver(Event) dragover} events pending if the drop is
* @param event * @param event
* the dragenter or dragover event that triggered the indication. * the dragenter or dragover event that triggered the indication.
*/ */
protected void addTargetClassIndicator(NativeEvent event) {
protected void addDragOverStyle(NativeEvent event) {
getDropTargetElement().addClassName(styleDragCenter); getDropTargetElement().addClassName(styleDragCenter);
} }


/** /**
* Remove the drag target indicator class name from the target element.
* Remove the drag over indicator class name from the target element.
* <p> * <p>
* This is triggered on {@link #onDrop(Event) drop}, * This is triggered on {@link #onDrop(Event) drop},
* {@link #onDragLeave(Event) dragleave} and {@link #onDragOver(Event) * {@link #onDragLeave(Event) dragleave} and {@link #onDragOver(Event)
* @param event * @param event
* the event that triggered the removal of the indicator * the event that triggered the removal of the indicator
*/ */
protected void removeTargetClassIndicator(NativeEvent event) {
protected void removeDragOverStyle(NativeEvent event) {
getDropTargetElement().removeClassName(styleDragCenter); getDropTargetElement().removeClassName(styleDragCenter);
} }


return new Function('event', script)(event); return new Function('event', script)(event);
}-*/; }-*/;


private native boolean getStylePrimaryName(Element element)
/*-{
return @com.google.gwt.user.client.ui.UIObject::getStylePrimaryName(Lcom/google/gwt/dom/client/Element;)(element);
}-*/;

@Override @Override
public DropTargetState getState() { public DropTargetState getState() {
return (DropTargetState) super.getState(); return (DropTargetState) super.getState();

+ 9
- 2
documentation/advanced/advanced-dragndrop.asciidoc View File



=== CSS Style Rules === CSS Style Rules


When dragging data over a drop target and the drag over criteria passes, a style name is applied to indicate that the element accepts drops. This style name is the primary style name with `-drag-center` suffix, e.g. `v-label-drag-center`.
Each drop target element have an applied style name, the primary style name with `-droptarget` suffix, e.g. `v-label-droptarget`, to indicate that it is a potential target for data to be dropped onto it.

When dragging data over a drop target and the drag over criteria passes, a style name is applied to indicate that the element accepts the drop. This style name is the primary style name with `-drag-center` suffix, e.g. `v-label-drag-center`.




//// ////
List<Person> items = (List<Person>) dataProvider.getItems(); List<Person> items = (List<Person>) dataProvider.getItems();


// Calculate the target row's index // Calculate the target row's index
int index = items.indexOf(event.getDropTargetRow()) + (
int index = items.size();
if (event.getDropTargetRow().isPresent()) {
index = items.indexOf(event.getDropTargetRow().get()) + (
event.getDropLocation() == DropLocation.BELOW ? 1 : 0); event.getDropLocation() == DropLocation.BELOW ? 1 : 0);
}


// Add dragged items to the target Grid // Add dragged items to the target Grid
items.addAll(index, draggedItems); items.addAll(index, draggedItems);


==== CSS Style Rules ==== CSS Style Rules


A drop target Grid's body has the style name `v-grid-body-droptarget` to indicate that it is a potential target for data to be dropped.

When dragging data over a drop target Grid's row, depending on the drop mode and the mouse position relative to the row, a style name is applied to the row to indicate the drop location. When dragging data over a drop target Grid's row, depending on the drop mode and the mouse position relative to the row, a style name is applied to the row to indicate the drop location.
`v-grid-row-drag-center` indicates ON_TOP, `v-grid-row-drag-top` indicates ABOVE and `v-grid-row-drag-bottom` indicates BELOW locations. `v-grid-row-drag-center` indicates ON_TOP, `v-grid-row-drag-top` indicates ABOVE and `v-grid-row-drag-bottom` indicates BELOW locations.



+ 5
- 3
server/src/main/java/com/vaadin/ui/components/grid/GridDropEvent.java View File

package com.vaadin.ui.components.grid; package com.vaadin.ui.components.grid;


import java.util.Map; import java.util.Map;
import java.util.Optional;


import com.vaadin.shared.ui.dnd.DropEffect; import com.vaadin.shared.ui.dnd.DropEffect;
import com.vaadin.shared.ui.grid.DropLocation; import com.vaadin.shared.ui.grid.DropLocation;
/** /**
* Get the row item source of this event. * Get the row item source of this event.
* *
* @return The row item this event was originated from.
* @return The optional row item if the event was originated from a row,
* otherwise an empty optional.
*/ */
public T getDropTargetRow() {
return dropTargetRow;
public Optional<T> getDropTargetRow() {
return Optional.ofNullable(dropTargetRow);
} }


/** /**

+ 6
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_grid.scss View File

background: darken($v-grid-drag-indicator-color, 10%); background: darken($v-grid-drag-indicator-color, 10%);
} }
} }

// Expand Grid's body to cover the whole Grid
.#{$primary-stylename}-body-droptarget {
width: 100%;
height: 100%;
}
} }





+ 11
- 6
uitest/src/main/java/com/vaadin/tests/components/grid/GridDragAndDrop.java View File

GridDragSource<Person> dragSource = applyDragSource(left); GridDragSource<Person> dragSource = applyDragSource(left);


// Drop target Grid // Drop target Grid
Grid<Person> right = createGridAndFillWithData(5);
Grid<Person> right = createGridAndFillWithData(0);
GridDropTarget<Person> dropTarget = applyDropTarget(right); GridDropTarget<Person> dropTarget = applyDropTarget(right);


// Layout the two grids // Layout the two grids
List<Person> items = (List<Person>) dataProvider.getItems(); List<Person> items = (List<Person>) dataProvider.getItems();


// Calculate the target row's index // Calculate the target row's index
int index = items.indexOf(event.getDropTargetRow())
+ (event.getDropLocation() == DropLocation.BELOW ? 1
: 0);
int index = items.size();
if (event.getDropTargetRow().isPresent()) {
index = items.indexOf(event.getDropTargetRow().get())
+ (event.getDropLocation() == DropLocation.BELOW
? 1 : 0);
}


// Add dragged items to the target Grid // Add dragged items to the target Grid
items.addAll(index, draggedItems); items.addAll(index, draggedItems);
+ ", dragDataJson=" + ", dragDataJson="
+ event.getDataTransferData("application/json") + event.getDataTransferData("application/json")
+ ", target=" + ", target="
+ event.getDropTargetRow().getFirstName() + " "
+ event.getDropTargetRow().getLastName()
+ (event.getDropTargetRow().isPresent() ?
event.getDropTargetRow().get().getFirstName() + " "
+ event.getDropTargetRow().get()
.getLastName() : "[BODY]")
+ ", location=" + event.getDropLocation()); + ", location=" + event.getDropLocation());
} }
}); });

Loading…
Cancel
Save