FLUID-187 - columns as drop targets.

Joseph Scheuhammer clown at utoronto.ca
Fri Feb 15 20:57:07 UTC 2008

Here are some thoughts on how to handle FLUID-187, allowing portlets to 
be dropped into an empty column:

Apologies for the length.

The terminology uses a short cut in that it refers to the things that 
are dragged and dropped in the context of the Reorderer and portlets.  
That is, I'm going to  refer to "portlets", "columns", and so on, and 
not something more abstract, partly to make the discussion concrete.  
Once the problem is better understood, then more abstract terminology 
can be used.

dnd:  drag-and-drop.

movable:  a portlet that can move.  Some portlets are locked or fixed 
and cannot move.

draggable, dragged:  the portlet that is being moved via a dnd.

avatar:  the semi-transparent clone of the dragged portlet that moves 
with the mouse during the drag.  Note that the draggable itself stays in 
its current location until the drop is performed.  It is the avatar that 
moves with the mouse during dnd.

drop target, droppable:  the thing that detects mouse movement over it 
and signals that it is a drop location.  Currently, only the movable 
portlets are drop targets (and are implemented as jQuery droppables).

drop target permissions:  data that is consulted to determine if a 
draggable can be dropped relative to the drop target.  The permissions 
are based on a combination of whether a droppable portlet is fixed 
(hence, nothing can be dropped above it), and a portlet's precedence 
(dragged portlets with lower precedence cannot be dropped above 
droppable portlets with higher precedence).  The fixed nature and 
precedence of a portlet is captured by the drop target permissions data.

drop marker:  the thing that is displayed to indicate a drop point, 
either above or below a droppable portlet.  In terms of the DOM, it is 
an element that is the same type of tag as the draggable.  It is styled 
to be a "thin" coloured bar.

drop point:  the location to display the drop marker.

column:  a vertical container of portlets.

interstitial space: the white space in a column between the portlets 

Overall Problem
------- -------

At present, the Reorderer consider only the movable portlets as drop 
targets.  The initial problem is that when all portlets are moved out of 
a column, and that column is empty, then it contains no drop targets.  
Any attempt to drag a portlet to the empty column fails because there is 
no drop target to signal that the mouse is over it.

A corollary is that if the column contains a single portlet at the top, 
users expect to be able to drag a portlet anywhere below that single 
portlet. But, they cannot.  They have to drag over the single portlet in 
order to drop below it.  Similar behaviour occurs even when dragging in 
a full column, where users have to place the mouse over a portlet in 
order to drop.  They cannot drop on the white space between portlets.  
This is easily seen in the current implementation where the drop marker 
vanishes when the mouse is over these interstitial spaces.

What is needed is the ability to detect the mouse position:
- between droppable portlets,
- below a single portlet in a column,
- in an empty column.

Two Problems:
--- --------

Part of the solution is to make the columns drop targets as well.  That 
results in the mouse movement being detected in a column even when the 
mouse is not over a portlet.  Also, making a column a target is a 
restriction of sorts:  not just any white space will detect mouse 
movement over it; only white space within the column under the mouse.

Making columns drop targets leads to two main new problems.

1. Determining where one is in a column when not over a droppable portlet.

A preliminary coding experiment was done to see what would happen if one 
simply added the columns as drop targets.  The result was that the 
column did signal that the mouse was over it. However, given the 
permissions data structure, when the mouse is over interstitial space 
and not over a droppable portlet, then the permissions indicate that 
there is no drop point available.  No drop marker was displayed, and 
releasing the mouse resulted in no movement of the dragged portlet.

Also, as the mouse moved over a droppable portlet during the drag, the 
system reverted to its normal behaviour:  drop markers showed up as 
appropriate.  (This is a good thing).

The issue then becomes how to use the current mouse coordinates during a 
drag over interstitial space in a column to determine the nearest drop 
target portlet or pair of drop target portlets.  Once the droppable 
portlet(s) are discovered, one can check against their drop target 
permissions, and display the drop marker at the drop point as appropriate.

Currently, I am looking into how jQuery captures and defines mouse 
coordinates.   For example:

2. What is the drop marker in DOM-speak?  Or, how to decide on the right 

Currently, when a portlet is marked as draggable, a drop marker is 
created such that it is of the same type of tag as the draggable.  In 
the case of uPortal, that is a <div> element.

One might suspect that if columns are added as drop targets, then the 
drop marker would be of the wrong type of tag.

First, it is undesirable to create a drop marker whose tag is the same 
as the column's.  (In the case of uPortal, that is a <td> element).  
Fortunately, that can't happen if the drop marker is instantiated in the 
context of the draggable, and is of the same type as the draggable.

Secondly, it is potentially illegal html to place the drop marker 
outside of the column (before or after), and the current code might well 
do that.  But, this is a problem in another way:  The drop marker should 
never be placed between *columns*, but (1) only between portlets, (2) 
after the last portlet in a column, or (3) in place of the first portlet 
in an empty column.

Overall, if the first problem of finding the permissble location of the 
drop point is solved (see, Determining where one is in a column when not 
over a droppable portlet above), then configuring the drop target as the 
draggable tag type should be sufficient.

Final thought
----- -------

If (when) this works, why not make the columns the only drop targets?  
Why have columns *and* portlets as drop targets?  Is there any need to 
have portlets as drop targets any more?

One other idea
--- ----- ----

Can the event horizon of the portlets be expanded to "fill" the 
interstitial space?  That is, what if there is no white space between 
porlets?  It may look like there is white space, but actually the 
portlets are separated by no more than a pixel.  In that case, the mouse 
will always be over some portlet, and never over the column underneath.  
This probably won't work since it's the css content box that the mouse 
is sensitive to.  That is, once you reach the element's margins, or even 
its padding, the mouse is no longer considered to be over the element.  
And, filling the column does not address the empty column issue.


'This is not war -- this is pest control!'
      - "Doomsday", Dalek Leader -

More information about the fluid-work mailing list