From 69b43cb346b504d713e458b987e65f4db1b825df Mon Sep 17 00:00:00 2001 From: Pekka Hyvönen Date: Mon, 20 Mar 2017 16:04:56 +0200 Subject: Initial documentation for 8.1 Drag and Drop (#8867) * Initial documentation for 8.1 Drag and Drop Part of #8395 --- documentation/advanced/advanced-dragndrop.asciidoc | 563 +++------------------ 1 file changed, 66 insertions(+), 497 deletions(-) (limited to 'documentation/advanced') diff --git a/documentation/advanced/advanced-dragndrop.asciidoc b/documentation/advanced/advanced-dragndrop.asciidoc index 814883357f..8c9124f6d7 100644 --- a/documentation/advanced/advanced-dragndrop.asciidoc +++ b/documentation/advanced/advanced-dragndrop.asciidoc @@ -9,550 +9,118 @@ layout: page ((("Drag and Drop", id="term.advanced.dragndrop", range="startofrange"))) +IMPORTANT: This feature is currently being developed and only available in the Framework 8.1 prerelease versions, starting from 8.1.0.alpha1. Dragging an object from one location to another by grabbing it with mouse, holding the mouse button pressed, and then releasing the button to "drop" it to the other location is a common way to move, copy, or associate objects. For example, most operating systems allow dragging and dropping files between -folders or dragging a document on a program to open it. In Vaadin, it is -possible to drag and drop components and parts of certain components. - -Dragged objects, or __transferables__, are essentially data objects. You can -drag and drop rows in [classname]#Table# and nodes in [classname]#Tree# -components, either within or between the components. You can also drag entire -components by wrapping them inside [classname]#DragAndDropWrapper#. - -Dragging starts from a __drag source__, which defines the transferable. -Transferables implement the [classname]#Transferable# interfaces. For trees and -tables, which are bound to [classname]#Container# data sources, a node or row -transferable is a reference to an [classname]#Item# in the Vaadin Data Model. -Dragged components are referenced with a [classname]#WrapperTransferable#. -Starting dragging does not require any client-server communication, you only -need to enable dragging. All drag and drop logic occurs in two operations: -determining ( __accepting__) where dropping is allowed and actually dropping. -Drops can be done on a __drop target__, which implements the -[classname]#DropTarget# interface. Three components implement the interface: -[classname]#Tree#, [classname]#Table#, and [classname]#DragAndDropWrapper#. -These accept and drop operations need to be provided in a __drop handler__. -Essentially all you need to do to enable drag and drop is to enable dragging in -the drag source and implement the [methodname]#getAcceptCriterion()# and -[methodname]#drop()# methods in the [classname]#DropHandler# interface. - -The client-server architecture of Vaadin causes special requirements for the -drag and drop functionality. The logic for determining where a dragged object -can be dropped, that is, __accepting__ a drop, should normally be done on the -client-side, in the browser. Server communications are too slow to have much of -such logic on the server-side. The drag and drop feature therefore offers a -number of ways to avoid the server communications to ensure a good user -experience. +folders or dragging a document on a program to open it. Framework version 8.1 adds support for https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API[HTML5 drag and drop] features. This makes it possible to set components as drag sources that user can drag and drop, or to set them as drop targets to drop things on. -[[advanced.dragndrop.drophandler]] -== Handling Drops - -Most of the user-defined drag and drop logic occurs in a __drop handler__, which -is provided by implementing the [methodname]#drop()# method in the -[classname]#DropHandler# interface. A closely related definition is the drop -accept criterion, which is defined in the [methodname]#getAcceptCriterion()# -method in the same interface. It is described in -<> later. - -The [methodname]#drop()# method gets a [classname]#DragAndDropEvent# as its -parameters. The event object provides references to two important object: -[classname]#Transferable# and [classname]#TargetDetails#. - -A [classname]#Transferable# contains a reference to the object (component or -data item) that is being dragged. A tree or table item is represented as a -[classname]#TreeTransferable# or [classname]#TableTransferable# object, which -carries the item identifier of the dragged tree or table item. These special -transferables, which are bound to some data in a container, are -[classname]#DataBoundTransferable#. Dragged components are represented as -[classname]#WrapperTransferable# objects, as the components are wrapped in a -[classname]#DragAndDropWrapper#. - -The [classname]#TargetDetails# object provides information about the exact -location where the transferable object is being dropped. The exact class of the -details object depends on the drop target and you need to cast it to the proper -subclass to get more detailed information. If the target is selection component, -essentially a tree or a table, the [classname]#AbstractSelectTargetDetails# -object tells the item on which the drop is being made. For trees, the -[classname]#TreeTargetDetails# gives some more details. For wrapped components, -the information is provided in a [classname]#WrapperDropDetails# object. In -addition to the target item or component, the details objects provide a __drop -location__. For selection components, the location can be obtained with the -[methodname]#getDropLocation()# and for wrapped components with -[methodname]#verticalDropLocation()# and [methodname]#horizontalDropLocation()#. -The locations are specified as either [classname]#VerticalDropLocation# or -[classname]#HorizontalDropLocation# objects. The drop location objects specify -whether the transferable is being dropped above, below, or directly on (at the -middle of) a component or item. - -Dropping on a [classname]#Tree#, [classname]#Table#, and a wrapped component is -explained further in the following sections. - - -[[advanced.dragndrop.treedrop]] -== Dropping Items On a [classname]#Tree# - -You can drag items from, to, or within a [classname]#Tree#. Making tree a drag -source requires simply setting the drag mode with [methodname]#setDragMode()#. -[classname]#Tree# currently supports only one drag mode, -[literal]#++TreeDragMode.NODE++#, which allows dragging single tree nodes. While -dragging, the dragged node is referenced with a [classname]#TreeTransferable# -object, which is a [classname]#DataBoundTransferable#. The tree node is -identified by the item ID of the container item. - -When a transferable is dropped on a tree, the drop location is stored in a -[classname]#TreeTargetDetails# object, which identifies the target location by -item ID of the tree node on which the drop is made. You can get the item ID with -[methodname]#getItemIdOver()# method in -[classname]#AbstractSelectTargetDetails#, which the -[classname]#TreeTargetDetails# inherits. A drop can occur directly on or above -or below a node; the exact location is a [classname]#VerticalDropLocation#, -which you can get with the [methodname]#getDropLocation()# method. - -In the example below, we have a [classname]#Tree# and we allow reordering the -tree items by drag and drop. +== Drag Source +Any component can be made a drag source that has a set of data that is transferred when it is dragged and dropped. -[source, java] ----- -final Tree tree = new Tree("Inventory"); -tree.setContainerDataSource(TreeExample.createTreeContent()); -layout.addComponent(tree); - -// Expand all items -for (Iterator it = tree.rootItemIds().iterator(); it.hasNext();) - tree.expandItemsRecursively(it.next()); - -// Set the tree in drag source mode -tree.setDragMode(TreeDragMode.NODE); - -// Allow the tree to receive drag drops and handle them -tree.setDropHandler(new DropHandler() { - public AcceptCriterion getAcceptCriterion() { - return AcceptAll.get(); - } +To make a component a drag source, you apply the [classname]#DragSourceExtension# to it. Then you can define the data to transfer, and the allowed drag effect. - public void drop(DragAndDropEvent event) { - // Wrapper for the object that is dragged - Transferable t = event.getTransferable(); - - // Make sure the drag source is the same tree - if (t.getSourceComponent() != tree) - return; - - TreeTargetDetails target = (TreeTargetDetails) - event.getTargetDetails(); - - // Get ids of the dragged item and the target item - Object sourceItemId = t.getData("itemId"); - Object targetItemId = target.getItemIdOver(); - - // On which side of the target the item was dropped - VerticalDropLocation location = target.getDropLocation(); - - HierarchicalContainer container = (HierarchicalContainer) - tree.getContainerDataSource(); - - // Drop right on an item -> make it a child - if (location == VerticalDropLocation.MIDDLE) - tree.setParent(sourceItemId, targetItemId); - - // Drop at the top of a subtree -> make it previous - else if (location == VerticalDropLocation.TOP) { - Object parentId = container.getParent(targetItemId); - container.setParent(sourceItemId, parentId); - container.moveAfterSibling(sourceItemId, targetItemId); - container.moveAfterSibling(targetItemId, sourceItemId); - } - - // Drop below another item -> make it next - else if (location == VerticalDropLocation.BOTTOM) { - Object parentId = container.getParent(targetItemId); - container.setParent(sourceItemId, parentId); - container.moveAfterSibling(sourceItemId, targetItemId); - } - } -}); ----- - -[[advanced.dragndrop.treedrop.criteria]] -=== Accept Criteria for Trees - -[classname]#Tree# defines some specialized accept criteria for trees. - -[classname]#TargetInSubtree#(client-side):: Accepts if the target item is in the specified sub-tree. The sub-tree is specified by the item ID of the root of the sub-tree in the constructor. The second constructor includes a depth parameter, which specifies how deep from the given root node are drops accepted. Value [literal]#++-1++# means infinite, that is, the entire sub-tree, and is therefore the same as the simpler constructor. -[classname]#TargetItemAllowsChildren#(client-side):: Accepts a drop if the tree has [methodname]#setChildrenAllowed()# enabled for the target item. The criterion does not require parameters, so the class is a singleton and can be acquired with [methodname]#Tree.TargetItemAllowsChildren.get()#. For example, the following composite criterion accepts drops only on nodes that allow children, but between all nodes: -+ [source, java] ---- -return new Or (Tree.TargetItemAllowsChildren.get(), new Not(VerticalLocationIs.MIDDLE)); ----- - -[classname]#TreeDropCriterion#(server-side):: Accepts drops on only some items, which as specified by a set of item IDs. You must extend the abstract class and implement the [methodname]#getAllowedItemIds()# to return the set. While the criterion is server-side, it is lazy-loading, so that the list of accepted target nodes is loaded only once from the server for each drag operation. See <> for an example. - - -In addition, the accept criteria defined in [classname]#AbstractSelect# are -available for a [classname]#Tree#, as listed in -<>. - - +Label draggableLabel = new Label("You can grab and drag me"); +DragSourceExtension