Now the DnD events are listened from tablewrapper element, which contains also grid's header and footer, making it possible to drop on top of them.tags/8.1.0.beta1
@@ -22,7 +22,6 @@ import java.util.Objects; | |||
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.dom.client.TableSectionElement; | |||
import com.google.gwt.user.client.Window; | |||
import com.vaadin.client.ServerConnector; | |||
import com.vaadin.client.WidgetUtil; | |||
@@ -82,10 +81,11 @@ public class GridDropTargetConnector extends DropTargetExtensionConnector { | |||
private String styleDragEmpty; | |||
/** | |||
* The latest row that was dragged on top of, or the grid body if drop is | |||
* not applicable for any rows. Need to store this so that can remove drop | |||
* hint styling when the target has changed since all browsers don't seem to | |||
* always fire the drag-enter drag-exit events in a consistent order. | |||
* The latest row that was dragged on top of, or the tablewrapper element | |||
* returned by {@link #getDropTargetElement()} if drop is not applicable for | |||
* any body rows. Need to store this so that can remove drop hint styling | |||
* when the target has changed since all browsers don't seem to always fire | |||
* the drag-enter drag-exit events in a consistent order. | |||
*/ | |||
private Element latestTargetElement; | |||
@@ -106,7 +106,7 @@ public class GridDropTargetConnector extends DropTargetExtensionConnector { | |||
Element targetElement = getTargetElement( | |||
(Element) dropEvent.getEventTarget().cast()); | |||
// the target element is either the body or one of the rows | |||
// the target element is either the tablewrapper or one of the body rows | |||
if (TableRowElement.is(targetElement)) { | |||
rowKey = getRowData(targetElement.cast()) | |||
.getString(GridState.JSONKEY_ROWKEY); | |||
@@ -237,20 +237,43 @@ public class GridDropTargetConnector extends DropTargetExtensionConnector { | |||
} | |||
private Element getTargetElement(Element source) { | |||
final Element tableWrapper = getDropTargetElement(); | |||
final BodyRowContainer gridBody = getGridBody(); | |||
final TableSectionElement bodyElement = gridBody.getElement(); | |||
while (!Objects.equals(source, bodyElement)) { | |||
final int rowCount = gridBody.getRowCount(); | |||
while (!Objects.equals(source, tableWrapper)) { | |||
// the drop might happen on top of header, body or footer rows | |||
if (TableRowElement.is(source)) { | |||
return source; | |||
String parentTagName = source.getParentElement().getTagName(); | |||
if ("thead".equalsIgnoreCase(parentTagName)) { | |||
// for empty grid or ON_TOP mode, drop as last row, | |||
// otherwise as above first visible row | |||
if (rowCount == 0 | |||
|| getState().dropMode == DropMode.ON_TOP) { | |||
return tableWrapper; | |||
} else { | |||
return gridBody.getRowElement(0); | |||
} | |||
} else if ("tfoot".equalsIgnoreCase(parentTagName)) { | |||
// for empty grid or ON_TOP mode, drop as last row, | |||
// otherwise as below last visible row | |||
if (rowCount == 0 | |||
|| getState().dropMode == DropMode.ON_TOP) { | |||
return tableWrapper; | |||
} else { | |||
return gridBody.getRowElement(rowCount - 1); | |||
} | |||
} else { // parent is tbody | |||
return source; | |||
} | |||
} | |||
source = source.getParentElement(); | |||
} | |||
// the drag is on top of the body | |||
final int rowCount = gridBody.getRowCount(); | |||
// if no rows in grid, or if the drop mode is on top, then there is no | |||
// the drag is on top of the tablewrapper | |||
// if no rows in grid, or if the drop mode is ON_TOP, then there is no | |||
// target row for the drop | |||
if (rowCount == 0 || getState().dropMode == DropMode.ON_TOP) { | |||
return bodyElement; | |||
return tableWrapper; | |||
} else { // if dragged under the last row to empty space, drop target | |||
// needs to be below the last row | |||
return gridBody.getRowElement(rowCount - 1); | |||
@@ -259,7 +282,14 @@ public class GridDropTargetConnector extends DropTargetExtensionConnector { | |||
@Override | |||
protected Element getDropTargetElement() { | |||
return getGridBody().getElement(); | |||
/* | |||
* The drop target element, the <div class="v-grid-tablewrapper" />. | |||
* This is where the event listeners are added since then we can accept | |||
* drops on header, body and footer rows and the "empty area" outside | |||
* rows. Also it is used since then the drop hints for "empty" area can | |||
* be shown properly as the grid body would scroll. | |||
*/ | |||
return getEscalator().getTableWrapper(); | |||
} | |||
private Escalator getEscalator() { |
@@ -6796,6 +6796,20 @@ public class Escalator extends Widget | |||
return null; | |||
} | |||
/** | |||
* Returns the {@code <div class="v-grid-tablewrapper" />} element which has | |||
* the table inside it. | |||
* <p> | |||
* <em>NOTE: you should not do any modifications to the returned element. | |||
* This API is only available for querying data from the element.</em> | |||
* | |||
* @return the table wrapper element | |||
* @since 8.1 | |||
*/ | |||
public Element getTableWrapper() { | |||
return tableWrapper; | |||
} | |||
private Element getSubPartElementTableStructure(SubPartArguments args) { | |||
String type = args.getType(); |
@@ -348,14 +348,16 @@ dropTarget.addGridDropListener(event -> { | |||
The _drop location_ property in the [classname]#GridDropEvent# specifies the dropped location in relative to grid row the drop happened on and depends on the used [classname]#DropMode#. When the drop happened on top of a row, the possible options for the location are `ON_TOP`, `ABOVE` and `BELOW`. | |||
If the grid is empty, or if there was empty space after the last row in grid and the [classname]#DropMode.ON_TOP# was used, then the drop location `EMPTY` will be used. If the drop modes [classname]#DropMode.BETWEEN# or [classname]#DropMode.ON_TOP_OR_BETWEEN# are used, then the location can be `EMPTY` only when the grid was empty; otherwise the drop happened ´BELOW´ the last row. When the drop location is `EMPTY`, the [methodname]#getDropTargetRow# method will also return an empty optional. | |||
If the grid is empty or if the drop was on empty space after the last row in grid, and the [classname]#DropMode.ON_TOP# was used, then the drop location `EMPTY` will be used. If the drop modes [classname]#DropMode.BETWEEN# or [classname]#DropMode.ON_TOP_OR_BETWEEN# are used, then the location can be `EMPTY` only when the grid was empty; otherwise the drop happened `BELOW` the last visible row. When the drop location is `EMPTY`, the [methodname]#getDropTargetRow# method will also return an empty optional. | |||
When dropping on top of the grid's header or footer, the drop location will be `EMPTY` if there are no rows in the grid or if [classname]#DropMode.ON_TOP# was used. If there are rows in the grid, dropping on top of the header will set the drop location to `ABOVE` and the dropped row will be the first currently visible row in grid. Similarly, if dropping on top of the footer, the drop location will be `BELOW` and the dropped row will be the last visible row in the grid. | |||
==== 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 or to the grid body to indicate the drop location. | |||
When dragging on top of a row, `v-grid-row-drag-center` indicates ON_TOP, `v-grid-row-drag-top` indicates ABOVE and `v-grid-row-drag-bottom` indicates BELOW locations. When dragging on top of an empty grid, or when the drop location is ON_TOP and dragged below the last row in grid (and there is empty space visible), the `v-grid-body-body-drag-top` style is applied to the table body element. | |||
When dragging on top of a row, `v-grid-row-drag-center` indicates ON_TOP, `v-grid-row-drag-top` indicates ABOVE and `v-grid-row-drag-bottom` indicates BELOW locations. When dragging on top of an empty grid, or when the drop location is ON_TOP and dragged below the last row in grid (and there is empty space visible), the `v-grid-body-body-drag-top` style is applied to the `v-grid-tablewrapper` element which surrounds the grid header, body and footer. | |||
(((range="endofrange", startref="term.advanced.dragndrop"))) | |||
@@ -87,8 +87,9 @@ public class GridDropEvent<T> extends DropEvent<Grid<T>> { | |||
* Get the location of the drop within the row. | |||
* <p> | |||
* <em>NOTE: when dropped on an empty grid, or when {@link DropMode#ON_TOP} | |||
* is used and the drop happened on empty space after last row, the location | |||
* will be {@link DropLocation#EMPTY}.</em> | |||
* is used and the drop happened on empty space after last row or on top of | |||
* the header / footer, the location will be | |||
* {@link DropLocation#EMPTY}.</em> | |||
* | |||
* @return Location of the drop within the row. | |||
* @see GridDropTarget#setDropMode(DropMode) |
@@ -832,7 +832,7 @@ $v-grid-drag-indicator-color: $v-focus-color; | |||
// Drag and drop | |||
.#{$primary-stylename}-row-drag-top, .#{$primary-stylename}-row-drag-bottom, .#{$primary-stylename}-row-drag-bottom { | |||
z-index: 100; | |||
z-index: 100; // based on what else z-indexes are in grid/escalator | |||
} | |||
.#{$primary-stylename}-row-drag-top:before, | |||
@@ -855,6 +855,10 @@ $v-grid-drag-indicator-color: $v-focus-color; | |||
top: -1px; | |||
} | |||
.#{$primary-stylename}-row-drag-top:first-child:before { | |||
top: 0; | |||
} | |||
.#{$primary-stylename}-row-drag-center:after { | |||
content: ""; | |||
position: absolute; | |||
@@ -877,28 +881,21 @@ $v-grid-drag-indicator-color: $v-focus-color; | |||
} | |||
} | |||
// Expand Grid's body to cover the whole Grid | |||
.#{$primary-stylename}-body-droptarget { | |||
top: 0; | |||
right: 0; | |||
bottom: 0; | |||
left: 0; | |||
} | |||
// Show drop hint when the grid is empty or, | |||
// if the DropMode.ON_TOP is used and dragging below last row | |||
.#{$primary-stylename}-body-drag-top:after { | |||
content: ""; | |||
position: absolute; | |||
top: 0; | |||
right: 2px; | |||
right: 0; | |||
bottom: 0; | |||
left: 0; | |||
pointer-events: none; | |||
border: 2px solid $v-grid-drag-indicator-color; | |||
z-index: 100; // based on what else z-indexes are in grid/escalator | |||
} | |||
} | |||
@include keyframes(valo-grid-editor-footer-animate-in) { | |||
0% { | |||
margin-top: -$v-grid-row-height; |