Built-in Drag and Drop support in h-smile core

As far as I understand there are two distinct drag-n-drop mechanisms:

  • Global drag-n-drop when objects are dragged from one window/application on desktop to another. In most cases this is very close to clipboard cut-n-paste but with some additional visualization.
  • Window local drag-n-drop when objects are dragged inside single window/form. For example some shopping cart implementation.

I have added support of latter one to the h-smile core – local drag-n-drop of DOM elements. Details are here.

Consider following task:

For these two select elements:

<select id="source" size="5">
  <option>First<</option>  
  <option>Second<</option>  
  <option>Third<</option>  
</select>
<select id="destination" size="5"></select>

we would like to provide ability to drag <option> elements from #source element to the #destination. In case of htmlayout or the Sciter (both are based on h-smile core) it is enough to write following:

   select#source > option
   {
      dragging: only-move; /* we can only move options out here*/ 
   }
   select#destination
   {
      accept-drag: selector( select#source > option ); 
                  /* we accept only options from select#source*/ 
      drop: append; 
                 /* order of items is not relevant, 
                     always append dropped option */
   }

and this is it – our users now are able to drag items from first <select> to second.

But what about one of main principles of good UI design – “discoverability”? User should have a visual clue while dragging: where and when he/she can drop dragged item. Following additional pseudo-classes will help us in this tasks:

   option:moving /* moving (dragging ) option */
   {
      background:blue; color:white;
      opacity:0.5;
   }
   select:drop-target /* active drop target element(s) */
   {
      background: yellow; 
      /* after D&D operation was started all active drop-targets 
          will be highlighted by yellow color */ 
   }
   select:drag-over /* drop target element under the dragged item.*/
   {
      outline: 1px solid green; 
      /* green outline to show that at current mouse position  
          dragged element can be dropped in this particular drop-target */ 
   }

And that is all we need to enable drag-n-drop in our application.

Oh, forgot to add: what if we need to drag options in both directions – from #destination back to the #source? The same simple idea:

   select#destination > option
   {
      dragging: only-move;  
   }
   select#source
   {
      accept-drag: selector( select#destination > option ); 
      drop: append; 
   }

And one small piece left: drop:recycle will declare element it is applied to (drop-target) as a “black hole” – all items dropped here will be deleted.