Surveiller ce forum | Commencer une nouvelle discussion Commencer une nouvelle discussion
RE: Drag'n'drop [ Répondre ]
Par : Xavier PRINCE on 2007-02-19 04:00
[forum:52506]
Nous allons travailler à l'intégration de ce module dans le Framework Ergonomique en complétant celui-ci :
- de sa documentation sous format JsDoc,
- de la gestion du curseur pour identifier les zones sources et destination,
- de la gestion d'un mode activation, désactivation permettant dynamiquement de rendre possible ou impossible soit l'ensemble des Drag'n'drop, soit une source ou une destination particulière.

Un des premiers cas d'utilisation que nous mettrons en place par la suite sera la création d'un nouveau composant arborescence permettant de gérer par Drag'n'drop le déplacement d'un élément ou d'un noeud.

RE: Drag'n'drop [ Répondre ]
Par : Xavier PRINCE on 2007-01-14 02:38
[forum:52408]
Pour ma part, je préfére comme indiqué dans l'autre sujet une solution baser sur un wysiwyg intégrable à eclipse comme solution de génération du méta xml, cette solution s'intégrera plus facilement dans l'environnement mutualisé de développement ACube.

RE: Drag'n'drop [ Répondre ]
Par : Thierry RIGAL on 2007-01-14 02:33
[forum:52406]
il serait intéressant d'utiliser le drag & drop dans un outil "front end" destiné à générer la création automatique du fichier XML de description d'un formulaire ACube (voir le fil de discussion ACube-XML dans la partie J2EE-LISE).

RE: Drag'n'drop [ Répondre ]
Par : Benjamin Leperchey on 2007-01-10 12:03
[forum:52395]
Voir le feature-request FRED pour un exemple concret (un peu débile)

RE: Drag'n'drop [ Répondre ]
Par : Steve PEGUET on 2007-01-04 15:53
[forum:52388]
Cette première version est intéressante et pourrait être incluse dans la prochaine version de FRED.
La limitation sur les objets DOM n'est pas prioritaire pour la prochaine version.
Les éléments à ajouter sont plutôt par ordre de priorité :
1/ Gestion du curseur pour mettre en valeur les objets sources.
2/ Documentation sous la forme de JSDoc pour cette nouvelle bibliothèque du Framework Technique de FRED.
3/ Prendre en compte les frames d'une manière optionnelle.

Drag'n'drop [ Répondre ]
Par : Benjamin Leperchey on 2007-01-04 15:17
[forum:52387]

Proposition de bibliothèque pour le drag'n'drop. Attention, il ne s'agit pas de déplacer des objets (du genre fenêtre) avec la souris, mais bien de prendre des données à un endroit et de les déposer à un autre.

Plus spécifiquement, chaque source offre un ou plusieurs objets, et chaque destination accepte un ou plusieurs types d'objets. Ces objets sont des collections { type:(type de l'objet), (autres attributs) }. Les types d'objets sont de simples chaînes de caractères. Le "drag" est complètement automatique, et le "drop" appelle un callback en passant l'objet en paramètre.

[dans le code joint, le format des objet est forcément {type,caption,value}, et la méthode appelée est callback(item.type,item.caption,item.value). Il faudrait le changer en callback(item) pour être vraiment générique]

Lorsqu'on amène un objet sur une destination compatible (qui accepte le type d'un des objets fournis par la source), elle est mise en valeur par un changement sa classe CSS.

Concrètement :

- on initialise les frames qui sont concernées par le drag&drop avec dragDropRegisterFrame(nom de la frame). On pourrait s'en passer s'il n'y a pas de frame, avec un bémol pour IE (on sélectionne le texte en draggant, ce qui est très moche)

- pour créer un objet "dragable", on appelle attributesForDragSource(items,frameId), où items est un tableau qui contient les différents objets qu'on peut tirer de cet élément. Ca renvoie une chaine de caractère à insérer entre le "<" et le ">" (définition de onmousedown etc.)

- pour créer un élément destination, on appelle attributesForDragTarget(types,callback,altClassName), où types est la liste des types acceptés, callback est la fonction a appeler lorsqu'un objet compatible est déposer, et altClassName est le nom de la classe CSS qui met en valeur l'objet.


Par l'exemple :

var dragItems = [ { type:'member', caption:caption, value:allMember },
{ type:'set', caption:caption, value:'{'+allMember+'}' },
{ type:'hierarchy', caption:caption, value:uniqueName } ];

var html='';
html += '<span ';
html += parent.attributesForDragSource(dragItems,frameId);
html += '>';
html += caption;
html += '</span>';

on a créé un span qui fournit trois types d'objets : 'member', 'set' et 'hierarchy' (ceux qui connaissent XMLA verront ce à quoi ça peut se référer), avec chacun des attributs 'caption' et 'value'. Ca suffit pour faire le "drag" (les attributs supplémentaires sont arbitraires)

html += '<div class="deposer" ';
html += parent.attributesForDragTarget(
['set','hierarchy'],
this.id+".insertItem",
'deposerOutlined');
html += '>';
html += "déposer ici";
html += '</div>'

avec ceci, on crée un DIV qui accepte les objets de type 'set' et 'hierarchy'. La fonction this.id+".insertItem" doit prendre un paramètre [dans le code fourni, encore une fois, trois paramètre type, caption et value, mais il faudrait le changer]. Lorsqu'on amène un objet de type 'set' ou 'hierarchy' sur l'objet, la classe est "deposerOutlined" remplace "deposer". Il suffit d'implémenter le callback pou faire le drop.

Quelques remarques :

* testé sous IE6 et FF 1.5 et 2.0. Limitation de IE : il faut capturer l'évenement "selectstart" au niveau du document, ce qui interdit à jamais de sélectionner du texte dans le reste de la frame. Pour FF, intercepter l'événement "mousedown" suffit à empêcher la selection. A voir : en bidouillant le "returnValue" du event de IE, on arrivearit peut-être à la même chose (IE a son propre système de flot d'événements, qui ne respecte pas le standard DOM)

* ça marche avec les frames, il faudrait changer deux ou trois choses pour que ça marche complètement sans (autoriser un argument null sur dragDropRegisterFrame et endDrag, et agir en conséquence).

* Vu avec Steve : une bonne pratique serait d'ajouter style="cursor:pointer" à tous les objets sources, pour mettre en valeur l'interaction possible. Mais ça ne me semble pas une bonne idée de le mettre dans la boîte à outils (ça entrerait en conflit avec les autres "style" qu'on voudrait ajouter)

* Et bien sûr, il faudrait changer onDragDrop pour passer directement l'objet au callback.

Limitation : les objets "contenus" dans une source sont définis une fois pour toute. On pourrait le changer en faisant un callback qui renvoie un tableau d'objets, mais ça me semble un peu lourd pour un besoin finalement pas évident.
De plus, les objets draggés doivent être "plats" : les seuls attributs peuvent être des nombres ou des chaînes. Ca pourrait être corrigés en faisant une fonction de sérialisation récursive (au lieu de la simple boucle de javascriptForDragStart), mais on obtiendrait de toute façon des *copies* des objets, et pas les originaux. En clair : n'imaginons même pas dragger des morceaux de DOM (je vous vois venir, bande de petits canaillous). Pour faire ce genre de chose, il faudrait dépasser la deuxième limitation -- admirez la transition.

* il manque une version "pure DOM", où on pourrait ajouter un comportement à un élément DOM existant (avec addEventListener et son équivalent Microsoft). D'abord, ça serait classe, et on pourrait utiliser de véritables fonctions anonymes, qui contiendraient les objets draggés *eux-mêmes*, et pas des vulgaires copies réalisées par sérialisation en texte+interprétation. Pas grand-chose à faire somme toute, mais ce n'est pas tout à fait l'esprit ACube, qui privilégie la génération de HTML aux manipulations DOM.

Et maintenant, le code :

/////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Drag/drop
///////////////////////////////////////////////////////////////////////////////

var registeredFrames = [];

function dragDropRegisterFrame(frameId,relationship)
{
registeredFrames[frameId] = relationship;
window.frames[frameId].document.onselectstart=new Function("return false");
}

// content of the drag/drop
var __drag = null;
// old class name, so we can put it back
var __drag_classNameWasChanged = false;
var __drag_oldClassName = null;

function attributesForDragSource(items,frameId)
{
var js = javascriptForDragStart(items,frameId);

return ' onmousedown="'+js+'" ';
}

function javascriptForDragStart(items,frameId)
{
function escapeQuote(s) { return s.replace(/\'/g,"\\'") }

var js = '';
if (frameId!=null)
js += registeredFrames[frameId]+".";

js += "dragStart(event,[";
var firstItem = true;
for (var i=0; i<items.length; i++)
{
if (!firstItem)
js += ', ';
js += '{';
var firstAttr = true;
for (var a in items[i])
{
if (!firstAttr)
js += ',';
js += "'"+a+"':'"+escapeQuote(items[i][a])+"'";
firstAttr = false;
}
js += '}';
firstItem = false;
}
js += ']); return false;';
return js;
}

function attributesForDragTarget(types,callback,altClassName)
{
var typesAsString = '[';
for (var i=0; i<types.length; i++)
{
if (i>0)
typesAsString += ',';
typesAsString += "'"+types[i]+"'";
}
typesAsString += ']';

var html = '';

html += ' onmouseover="parent.onDragEnter(event,'+typesAsString+',\''+altClassName+'\')"';
html += ' onmouseout="parent.onDragLeave(event)"';
html += ' onmouseup="parent.onDragDrop(event,'+typesAsString+','+callback+'); return false;" ';
html += ' onselectstart="return false"" '

return html;
}

function dragStart(event,items)
{
__drag = items;
document.body.style.cursor="move";
document.body.onmouseup=endDrag;

for (var frameId in registeredFrames)
{
window.frames[frameId].document.body.style.cursor="move";
window.frames[frameId].document.onmouseup=endDrag;
}

return false;
}

function endDrag(event)
{
__drag = null;
document.body.style.cursor="auto";
for (var frameId in registeredFrames)
window.frames[frameId].document.body.style.cursor="auto";
return true;
}

// test the compatibility of the dragged items with the expectations of the receiver
// types: the types that can be accepted by the receiver, in order of decreasing preference
// returns: an item that has an acceptable type, null if there is no match
function testDrag(types)
{
if (__drag!=null)
{
for (var i=0; i<types.length; i++)
for (var j=0; j<__drag.length; j++)
if (__drag[j].type==types[i])
return __drag[j];
}

return null;
}

function onDragEnter(event,types,className)
{
var item = testDrag(types);
if (item==null)
return;

var element = (event.target != null) ? event.target : event.srcElement;

__drag_classNameWasChanged = true;
__drag_oldClassName = element.className;
element.className = className;
}

function onDragLeave(event,className)
{
if ((__drag==null) || (!__drag_classNameWasChanged))
return;

__drag_classNameWasChanged = false;
var element = (event.target != null) ? event.target : event.srcElement;
element.className = __drag_oldClassName;
}

function onDragDrop(event,types,callback)
{
var item = testDrag(types);
if ((item != null) && (callback != null))
callback(item.type,item.caption,item.value);

onDragLeave(event);
endDrag();
}

FEDER Powered By FusionForge Collaborative Development Environment Charte d'utilisation / Nous contacter / Mentions légales Haut de page