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:
http://issues.fluidproject.org/browse/FLUID-187
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
therein.
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:
http://docs.jquery.com/Tutorials:Mouse_Position
2. What is the drop marker in DOM-speak? Or, how to decide on the right
tag?
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.
--
;;;;joseph
'This is not war -- this is pest control!'
- "Doomsday", Dalek Leader -