Places:Drag & Drop

From MozillaWiki
Jump to: navigation, search

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

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:

  1. Extracts current DataTransfer object from the event.
  2. Null the current viewer, this way we won't rebuild the view while wrapping nodes.
  3. Add the Places node to dragged items, using correct flavor for every node's type.
  4. 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:

  1. Get a valid insertion point
  2. 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:

  1. 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).
  2. In case this is a tab drag & drop converts data to an acceptable flavor.
  3. Unwrap the data, generate insertion or copy transactions, aggregates the transaction and executes them through the transaction manager.