Places:Drag & Drop
Places' views use the new drag & drop API introduced with Firefox 3.5 (Gecko 1.9.1). See: https://developer.mozilla.org/En/DragDrop/Drag_and_Drop
Contents
Toolbar Drag & Drop Handling
Toolbar handles drag & drop on its contained toolbarbuttons, while drag & drop on sub-menupopups (attached to menu type toolbarbuttons) is handled by their own handlers.
On dragstart
event we special handle containers, we want to drag them only if the gesture is not toward down, since in such a case a container should open to allow for "click, down, release" behavior.
Then we cache the current dragged Places node and activate the controller with a focus event, that's needed to ensure controller is active for the correct view and ready to catch our data.
Then we call the controller's setDataTransfer
method that executes the following tasks:
- Extracts current
DataTransfer
object from the event. - Null the current viewer, this way we won't rebuild the view while wrapping nodes.
- Add the Places node to dragged items, using correct flavor for every node's type.
- restore the viewer.
While moving over the toolbar within a drag session, the dragover
event will ensure the drop indicator bar is correctly positioned, and will automatically open the menu type toolbarbuttons when we drag over them.
We use PlacesControllerDragHelper.canDrop
and the local _getDropPoint
helper to ensure we can drop at a valid insertionPoint.
The dragleave
event works in a similar way, hiding the indicator bar and setting timers to close menu type toolbarbuttons when we are not anymore dragging over them.
Finally drop
event takes care of checking we have a valid drop point, and calls the controller drop helper.
Menu Drag & Drop Handling
Places menupopups use a special popup binding that supports drag & drop.
On dragstart
we cache the current dragged Places node, set the correct drag action (setting the effectAllowed
property of the DataTransfer</code object), activate the controller, and finally add data to the <code>DataTransfer
object through the controller setDataTransfer
method (See toolbar for a description of how this method is working).
dragover
and dragleave
events get an actual drop point through the _getDropPoint
local helper method, and ensure we can drop inside it through PlacesControllerDragHelper.canDrop
. Based on the results they will show or hide the drop indicator, and open or close popups when overing or leaving a menu node.
Finally on drop
the current DataTransfer
is cached, we check for a valid dropPoint and call the controller drop helper.
Tree Drag & Drop Handling
The Places Tree View (tree.xml) implements drag & drop event handlers.
On dragstart
we extract nodes from the tree selection, if any of those is not movable the drag will perform a "copy" operation, so we set the effectAllowed
property of DataTransfer
accordingly.
Then we fill the DataTransfer
object calling the controller's setDataTransfer
method.
On dragover
we call the view's canDrop
method, that will calculate the current drop point and pass correct informations to the treeview.js canDrop
method. That will ensure we can drop in the current position, showing or hiding the drop indicator and opening containers when needed (all of this is handled by nsTreeBodyFrame
).
On drop
the treeview.js drop handler will be called (since we implement nsINavHistoryResultViewObserver
), that will execute:
- Get a valid insertion point
- Call the controller's onDrop helper
Controller Drop Handling Helper
The PlacesControllerDragHelper
is an helper object providing methods and informations to views.
Every drag & drop event in our views saves the current DataTransfer object (https://developer.mozilla.org/En/DragDrop/DataTransfer) to PlacesControllerDragHelper.currentDataTransfer
. Helper methods will use this cached value to check for drop validity and perform it.
It provides an onDrop
method that performs view-agnostic drop handling.
For each dropped item this method performs the following actions:
- Determine what mime types of objects are being dragged (from the
PlacesControllerDragHelper.currentDataTransfer
cached object), and compares this list of types supported as droppable with the list of flavors supported by Places' Views (PlacesControllerDragHelper.GENERIC_VIEW_DROP_TYPES
). - In case this is a tab drag & drop converts data to an acceptable flavor.
- Unwrap the data, generate insertion or copy transactions, aggregates the transaction and executes them through the transaction manager.