cObject
---cWebObject
------cWebDragDropHelper
---------cWebDragDropFileHelper
Adds drag and drop fuctionality to web controls.
The following classes support elements being dragged for specific actions using the following constants:
cWebList: C_WebDragListRow
cWebTreeView: C_WebDragTreeviewFolder, C_WebDragTreeviewItem
cWebTagsForm: C_WebDragTagsFormTag
Attempting to add an unsupported drag action to a control will result in an Error.
Every visual web control, including containers like cWebPanel or cWebGroup, supports the C_WebDropOnControl action. This allows the entire control to function as a drop zone.
The following classes support elements being dropped onto for specific actions using the following constants:
All web controls: C_WebDropOnControl
cWebList: C_WebDropListRow
cWebTreeView: C_WebDropTreeviewRoot, C_WebDropTreeviewFolder, C_WebDropTreeviewItem
cWebTagsForm: C_WebDropTagsFormInput
1. Add a cWebDragDropHelper object to your view.
Adding a cWebDragDropHelper object to your view unlocks the drag and drop functionality. After creating the cWebDragDropHelper object, configure the allowed actions.
2. Design your drag and drop paths by adding Drag Sources and Drop Targets
Next set up your drag and drop paths, as well as, configure what actions you would like to support.
Adding Drag Sources is done using RegisterDragSource. Adding Drop Targets is done using RegisterDropTarget.
To support multiple drag actions on the same control, such as being able to drag both folders and items in a treeview, you would call RegisterDragSource again on the same control passing different actions. The same applies to supporting multiple drop actions.
Note that each Drag Source in a specific helper can drop on each Drop Target added inside. Controls can also function as both a Drag Source and a Drop Target at the same time, allowing for omnidirectional drag and drop interaction.
In the example below, we allow drag actions from 5 different controls. Items dragged from these controls can be dropped onto 6 controls. Some of these controls are registered as both a Drag Source and a Drop Target.
Object oDragDropHelper is a cWebDragDropHelper Send RegisterDragSource oAllCustomers C_WebDragListRow Send RegisterDragSource oNiceCustomers C_WebDragListRow Send RegisterDragSource oBadCustomers C_WebDragListRow Send RegisterDragSource oImportantCustomers C_WebDragTagsFormTag Send RegisterDragSource oSortedCustomers C_WebDragTreeviewItem Send RegisterDropTarget oNiceCustomers C_WebDropListRow Send RegisterDropTarget oBadCustomers C_WebDropListRow Send RegisterDropTarget oImportantCustomers C_WebDropTagsFormInput Send RegisterDropTarget oSortedCustomers C_WebDropTreeviewFolder Send RegisterDropTarget oWebFormDrop C_WebDropOnControl Send RegisterDropTarget oWebGroupDrop C_WebDropOnControl
3. Add your business logic to be executed when a drop happens by implementing the OnDrop event
When dropping a draggable element on a valid Drop Target, a call is sent to the server with info of the dragged data and the drop position. This is passed to the OnDrop event, where business logic can be executed to interact with this data.
The sample code below moves a customer from the source control to the target control.
Procedure OnDrop Handle hoDragSource Handle hoDropTarget WebDropPosition eDropPosition RowID riCustomer // Determine which customer is being dragged Get CustomerFromSource hoDragSource to riCustomer If (not(IsNullRowID(riCustomer))) Begin // Remove from the source (except for the oAllCustomers list) If (hoDragSource <> oAllCustomers) Begin Send RemoveCustomerFromSource hoDragSource riCustomer End // Add to the target Send AddCustomerToTarget riCustomer hoDropTarget eDropPosition End End_Procedure
3a. Getting drag and drop data
Both drag and drop data are not passed directly into the OnDrop event. They are set on both the hoDragSource and hoDropTarget at an earlier stage and can be retrieved by using either DragData or DropData. The return value is inherently a Variant, but will return a specific struct based on the control it's being requested from.
The example code below illustrates how to deal with getting the Drag and Drop data from the respective controls, as well as various ways of interacting with the data per individual control.
Function CustomerFromSource Handle hoDropSource Returns RowID If (IsObjectOfClass(hoDropSource, RefClass(cWebTagsForm))) Begin tWebTagsFormDragData tagsDragData Get DragData of hoDropSource to tagsDragData Clear Customer Move tagsDragData.data to Customer.Name Find GE Customer.Name If (Found and Trim(Customer.Name) = Trim(tagsDragData.data)) Begin Function_Return (GetRowID(Customer.File_Number)) End End If (IsObjectOfClass(hoDropSource, RefClass(cWebList))) Begin tWebListDragData listDragData Get DragData of hoDropSource to listDragData Function_Return (DeserializeRowID(listDragData.data.sRowId)) End If (IsObjectOfClass(hoDropSource, RefClass(cWebTreeView))) Begin tWebTreeViewDragData treeDragData Get DragData of hoDropSource to treeDragData Function_Return (DeserializeRowID(treeDragData.data.sId)) End Function_Return (NullRowID()) End_Function // // Adds an item onto the Drop Target based on the provided RowId. Switches between the different target types. // Procedure AddCustomerToTarget RowID riCustomer Handle hoDropTarget WebDropPosition eDropPosition Boolean bFound Move (FindByRowID(RefTable(Customer), riCustomer)) to bFound If (IsObjectOfClass(hoDropTarget, RefClass(cWebTagsForm))) Begin // We don't use the drop data, but just for fun we load it tWebTagsFormDropData tagsDropData Get DropData of hoDropTarget to tagsDropData Send AddTag of hoDropTarget (Customer.Name) End If (IsObjectOfClass(hoDropTarget, RefClass(cWebForm))) Begin WebSet psValue of hoDropTarget to (Trim(Customer.Name)) End If (IsObjectOfClass(hoDropTarget, RefClass(cWebGroup))) Begin String sMsg Move ('Dropped customer: "' + Trim(Customer.Name) + '" on WebGroup') to sMsg Send ShowInfoBox sMsg End If (IsObjectOfClass(hoDropTarget, RefClass(cWebList))) Begin tWebListDropData listDropData Get DropData of hoDropTarget to listDropData // Check if customer isn't already in the list RowID[] riRecordsShown WebGet prRecordsShown of hoDropTarget to riRecordsShown If (SearchArray(riCustomer, riRecordsShown) = -1) Begin Move riCustomer to riRecordsShown[SizeOfArray(riRecordsShown)] WebSet prRecordsShown of hoDropTarget to riRecordsShown // Now add it to the list tWebRow tListRow Get LoadGridRow of hoDropTarget to tListRow If (eDropPosition = C_WebDropPosBefore or eDropPosition = C_WebDropPosOn) Begin Send DataSetInsertRowBefore of hoDropTarget listDropData.data.sRowId tListRow End Else If (eDropPosition = C_WebDropPosAfter) Begin Send DataSetInsertRowAfter of hoDropTarget listDropData.data.sRowId tListRow End Else Begin Send DataSetAppendRow of hoDropTarget tListRow End End End If (IsObjectOfClass(hoDropTarget, RefClass(cWebTreeView))) Begin // Figure out drop data tWebTreeViewDropData treeDropData Get DropData of hoDropTarget to treeDropData // Remove to be sure we don't get duplicates Send RemoveNode of hoDropTarget (SerializeRowID(riCustomer)) // Create new node tWebTreeItem newItem Move (SerializeRowID(riCustomer)) to newItem.sId Move Customer.Name to newItem.sName Move Customer.City to newItem.sAltText Move False to newItem.bFolder Move treeDropData.data.sId to newItem.sParentId // Make it a child of what we dropped it on Send InsertNode of hoDropTarget newItem End End_Procedure // // Removes an item from the Drag Source. Switches between the different source types. // Procedure RemoveCustomerFromSource Handle hoDragSource RowID riCustomer If (IsObjectOfClass(hoDragSource, RefClass(cWebTagsForm))) Begin Boolean bFound Move (FindByRowID(RefTable(Customer), riCustomer)) to bFound If (bFound) Begin Send RemoveTag of hoDragSource (Customer.Name) End End If (IsObjectOfClass(hoDragSource, RefClass(cWebList))) Begin RowID[] riRecordsShown Integer iIndex // Update the extra list of shown customers we keep for both weblists. WebGet prRecordsShown of hoDragSource to riRecordsShown Move (SearchArray(riCustomer, riRecordsShown)) to iIndex If (iIndex <> -1) Begin Move (RemoveFromArray(riRecordsShown, iIndex)) to riRecordsShown WebSet prRecordsShown of hoDragSource to riRecordsShown Send DataSetRemoveRow of hoDragSource (SerializeRowID(riCustomer)) End End If (IsObjectOfClass(hoDragSource, RefClass(cWebTreeView))) Begin Send RemoveNode of hoDragSource (SerializeRowID(riCustomer)) End End_Procedure