Skip to end of metadata
Go to start of metadata

The prototypes here were used for getting the feedback of other developers, during the first part (design part) of GSOC project. They are all obsolete now, and only kept as a reference example for future students .

See how some component libraries handle drag and drop (not HTML5 though):
PrimeFacesDraggable
PrimeFacesDroppable
RichFacesDnD
ADFDnD
IceFacesDnD

<fx:dragSource>

Extends: ClientBehavior
Attributes:

Name

Required?

Values

Description

action

required

Comma separated set or String[] or Collection<String> of copy, copyLink, copyMove, link, linkMove, move, all.

Allowed DnD drag action from this source

dropTargetTypes

optional

Can be comma separated set or String[] or Collection<String>

With this property, we can specify which types of drop zones we can make DnD from this source

param

optional

EL and literal

Parameter to send to server when drop operation is done.

Notes: 
References:

<fx:dropTarget>

Extends: AjaxBehavior
Attributes:

Name

Required?

Values

Description

actions

required

Comma separated set or String[] or Collection<String> of copy, copyLink, copyMove, link, linkMove, move, all.

Allowed DnD actions.
If action of dragEvent are not one of these, DnD will stop.

dropListener

optional

EL

Listener method to handle DnD operation on server side.

rerender

optional

EL and literal

same with <f:ajax> rerender attribute.

types

optional

Can be comma separated set or String[] or Collection<String>.

Used in conjunction with <fx:dragSource>'s dropTargetTypes attribute. Types of this dropTarget.

acceptMimeTypes

optional

Can be comma separated set or String[] or Collection<String>.

If this is set, only content dropped into this zone with defined mime type will be accepted and sent to server-side drop listener.
HTML5 DnD allows us to drop anything into drop zone[2] : files from desktop, images on some other document[3] , etc. So this property is a filter.
If value is "*", any content dropped into this zone will be accepted. All type info and data of dropped stuff will be sent to dropListener.
For example, if this is true and we dragNdrop some image on any Html page(even not generated by JSF), dropListener will be triggered with the following data:
content-type | value
text/uri-list | http://example.org/someImage.pngText | http://example.org/someImage.pngtext/plain | http://example.org/someImage.pngURL | http://example.org/someImage.png
Another example may be dropping files from your desktop, but what to do with them? We'll have <hx:inputFileUpload> for DnD file uploading. So better not to accept files, or even they're accepted, we'd better not to send their information to server.
Mime type can be something like "text/x-myfaces-html5-dnd-source" for MyFaces generated components.
Default to "text/x-myfaces-html5-dnd-source", thus only MyFaces generated components can be dropped into this zone.

Notes: 
References:

http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dnd

http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#embedding-custom-non-visible-data

http://html5demos.com/drag-anything

http://apirocks.com/html5/html5.html#slide13

https://developer.mozilla.org/En/DragDrop/Drag_and_Drop

https://developer.mozilla.org/En/DragDrop/DataTransfer

https://developer.mozilla.org/En/DragDrop/Recommended_Drag_Types

https://developer.mozilla.org/En/DragDrop/Drag_Operations

<hx:panel>

Extends: <t:div> or something (I don't think a dependency to Tomahawk is good. So, need to rewrite that stuff or copy them, preferably with maven-dependency-plugin)
Attributes:

ondragstart, ondragend, ondragenter, ondragover, ondrop, other DnD behavioral attributes
dragStartStyle, dragStartStyleClass: CSS stuff to set when this component is being dragged
dragOverStyle, dragOverStyleClass: CSS stuff to set when something is dragged onto this component
other stuff that wrapped components don't support (not clear yet!)

Notes: 
  • This is just like <t:div> or <rich:panel>. For example DnD does not work with components that dont support "dragstart" clientbehavior event. That is why <hx:panel> is necessary. We can wrap those components (ie. h:inputText, h:panelGrid) with <hx:panel>.
References:

Usage of prototypes:

usage: <fx:dragSource> with dropTargetType
<hx:panel id="draggable1" >
	<!-- SOME CONTENT -->
	<fx:dragSource action="copy" dropTargetTypes="#{someBean.optionaldropTargetTypes}" 
		param="#{someBean.dndParamToSendToServer}"/>
</hx:panel>
expected HTML5 code
<div id="draggable1" draggable="true"
		ondragstart="return dragStart(event, 'copy', {'firstdropTargetType','seconddropTargetType'}, 'literalDndParamToSendToServer')"
		>
	<!-- RENDERED CONTENT -->
</div>



usage: <fx:dragSource> with event handler chains
<hx:panel id="draggable2" 
		ondragstart="log('dragging');" 
		ondragend="alert('Drag ended. May not have been dropped succesfully though!')">
	<!-- SOME CONTENT -->
	<fx:dragSource action="move" param="anotherDndParamToSendToServer" />
</hx:panel>
expected HTML5 code
<div id="draggable2" draggable="true"
		ondragstart="log('dragging'); return dragStart(event, 'move', null, 'secondDndValueToSendServer')"
		ondragend="alert('Drag ended. May not have been dropped succesfully though!')"
		>
	<!-- RENDERED CONTENT -->
</div>



usage: <fx:dragSource> within <hx:inputText> (allowed with HTML5, doesn't make sense though)
<hx:inputText id="draggableInputText">
	<fx:dragSource action="move"/>
</hx:panel>
expected HTML5 code
<input type="text" id="draggableInputText" draggable="true"
		ondragstart="return dragStart(event, 'move')" />



usage: <fx:dropTarget> with type and rerender
<hx:panel id="dropTarget1">
	<!-- SOME CONTENT -->
	<fx:dropTarget actions="move" dropListener="#{someBean.dropListener}" 
		rerender="draggable1" types="firstdropTargetType"/>
</hx:panel>
expected HTML5 code
<div id="dropTarget1" 
	ondragenter="dragEnter(event,{'move'},{'firstdropTargetType'}), {'text/x-myfaces-html5-dnd-source'}"
	ondragover="dragOver(event)"
	ondrop="drop(event, 'stuff necessary to trigger someBean.dropListener and rerender draggable1 using jsf.ajax.request')">
	<!-- RENDERED CONTENT -->
</div>



usage: <fx:dropTarget> with handler chaining
<hx:panel id="dropTarget2"
	ondragover="makeRedBorder();"
	ondragleave="clearRedBorder();"
	ondrop="makeGreenBorder();"
	>
	<!-- SOME CONTENT -->
	<fx:dropTarget actions="copy,move" dropListener="#{someBean.dropListener}" />
</hx:panel>
expected HTML5 code
<div id="dropTarget2" 
	ondragenter="dragEnter(event,{'copy','move'}), null, {'text/x-myfaces-html5-dnd-source'}"
	ondragover="makeRedBorder(); dragOver(event)"
	ondragleave="clearRedBorder();"
	ondrop="makeGreenBorder();drop(event)">
	<!-- RENDERED CONTENT -->
</div>



usage: <fx:dropTarget> that accepts some specified mime typed content
<hx:panel id="dropTarget3">
	<!-- SOME CONTENT -->
	<fx:dropTarget actions="copy" dropListener="#{someBean.dropListener}" acceptMimeTypes="text/plain, URL" />
</hx:panel>

expected HTML5 code
<div id="dropTarget3" 
	ondragenter="dragEnter(event,{'copy','move'}, null, {'text/plain', 'URL'})"
	ondragover="dragOver(event)"
	ondrop="drop(event)">
	<!-- RENDERED CONTENT -->
</div>



And here is the script:

Javascript Stuff
var paramMimeType = 'text/x-myfaces-html5-dnd-param';
var myFacesComponentSourceMimeType = 'text/x-myfaces-html5-dnd-source';
var dropTargetMimeType = 'text/x-myfaces-html5-drop-zone-type';
var myFacesComponentSourceConstant = 'org.apache.myfaces';

/*
 * This function is only used by MyFaces generated draggable elements, the ones that have <fx:dragSource> behavior.
 */
function dragStart(event, effectAllowed, paramToSendToServer, dropTargetTypes) {

	//set allowed effect
	event.dataTransfer.effectAllowed = effectAllowed;	//only allow some specific event

	//with this, drop zone will understand that source of this dnd operation is some MyFaces component
	event.dataTransfer.setData(myFacesComponentSourceMimeType, myFacesComponentSourceConstant);

	//this will be set if we want to send an optional parameter to the server-side drop listener
	if(paramToSendToServer)
		event.dataTransfer.setData(paramMimeType, valueToSendToServer);		

	//this will be set if we want to make the drop only into specific dropTargets with specific types
	if(dropTargetType)
		event.dataTransfer.setData(dropTargetMimeType, dropTargetTypes);	//in fact, dropTargetTypes is an array. need to iterate 	
      
	return true;
}

function dragEnter(event, allowedEffects, dropTargetTypes, acceptedMimeTypes) {
	//check allowed mime types first
	var found = false;
	var foundTypes = acceptedMimeTypes.filter(function (mimeType) event.dataTransfer.types.contains(mimeType));
	
	//if even one of the event mime types are not allowed, stop DnD  
	if(foundTypes.length == 0)
		return true; //don't cancel the event, thus stop DnD
	
	//check allowed effect
	//changeIt: allowedEffects is an array in fact, so need to iterate
	if (event.dataTransfer.effectAllowed != allowedEffect)		
		return true; //don't cancel the event, thus stop DnD

	//check drop zone type
	//changeIt: in fact these are arrays too. need to iterate or use contains() function
	if (event.dataTransfer.getData(dropTargetMimeType) != dropTargetTypes)
		return true; //don't cancel the event, thus stop DnD

	//cancel the event. this is necessary for DnD execution	
	if (event.preventDefault)	
		event.preventDefault();
	
	return false;
}

function dragOver(event){
	//don't check source, allowedEffect and dropTargetType, since they are checked at dragEnter function
	
	//show same user hint effect specified by drag source 
	event.dataTransfer.dropEffect = event.dataTransfer.effectAllowed;	

	//cancel the event, so effect on screen is updated
	if (event.preventDefault) 
		event.preventDefault(); 

	return false;
}

function drop(event, jsf_ajax_request_necessary_stuff){
	//cancel the event. this is necessary for DnD execution	
	if (event.preventDefault) 
		event.preventDefault();

	//CALL jsf.ajax.request with constructing parameters from jsf_ajax_request_necessary_stuff
	//this call should trigger the dropListener and make the rerender operation
	//need to send event mime types and values too!

	return false;
}