Page 1 sur 3

Drag and Drop

Posté : 28 août 2007, 16:04
par orgerix
Bonjour,

J'aimerai faire un effet de drag and drop afin de faciliter la gestions d'effectifs et pouvoir facilement les changer d'équipe.

En gros, je prend un nom, le dépose dans une zone correspondant à une équipe, et ca revoie une requete AJAX avec les id de la zone et du nom. Le problème, c'est que je ne sais pas du tout faire ca...

Est ce que quelqu'un pourrai m'aider ?

Posté : 28 août 2007, 16:18
par sadeq
Oui moi, mais pas maintenant, attend.

Posté : 28 août 2007, 16:58
par Calimero
Commence par faire ce que tu sais faire... Et après tu reviens nous voir en nous montrant ce que tu as réussi à faire et on pourra t'aiguiller vers ce qui te manque :D

:arrow: Ou sinon tu peux toujours attendre sadeq, il va bientôt reviendre !

Posté : 28 août 2007, 17:23
par orgerix
Le problème, c'est que je ne sais rien faire...

Mes connaissances en javascript sont plus que réduites et je ne sais gérer les évenement que par DHTML, ce qui n'est pas suffisant.

Je vais donc attendre Sadeq

Posté : 29 août 2007, 00:02
par sadeq
oui, je suis à toi.
Si j'ai bien compris, tu veux déplacer graphiquement des noms de personnes sélectionnés d'une zone représentant une équipe vers une autre en faisant un drag&drop et quand il seront placés dans la zone de destination tu veux que Ajax transmette automatiquement les paramètres (zone/noms) au serveur pour déclencher une requête SQL et les enregistrer dans la base. N'est-ce pas?

Si oui, mes questions sont:
  • 1. Peut-on sélectionner plusieurs noms à la fois pour en effectuer le déplacement dans une zone équipe?
    2. Quelle est la structure de la table (base de données) qui mémorise ses affectations personnes/équipe?

Posté : 29 août 2007, 09:34
par orgerix
C'est exactement ca

1e question : non, les déplacement se font individuellement

2e question : Ma base de donnée est MySQL

Code : Tout sélectionner

CREATE TABLE `membre` ( `login` varchar(20) collate latin1_general_ci NOT NULL, `equipe` varchar(20) collate latin1_general_ci NOT NULL, PRIMARY KEY (`login`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

Posté : 29 août 2007, 13:41
par sadeq
Ok, on peut travailler maintenant sur 2 axes:
  • 1. L'interface utilisateur pour le drag&drop et le déclenchement d'Ajax
    2. Le programme serveur qui applique la requête de mise à jour de la table membre en modifiant l'équipe du membre déplacé
Commençons par le 2. sachant que le programme serveur doit recevoir 2 paramètres : le login du membre déplacé et son équipe d'accueil
Il faut écrire le code du programme qui:
  • 1. reçoit les 2 paramètres postés
    2. determine la requête UPDATE à appliquer, l'exécute et renvoi une réponse : "Affectation effectuée" ou "Affectation non effectué"
Allez, à toi.

Une fois c'est fait, on nommera ce programme "membre.affecter.php" et on verra la suite ...

Posté : 29 août 2007, 14:23
par orgerix
Ca c'est facile, c'est PHP :P
<?php
include('../bzw.php');
$connexion = mysql_connect($host,$user,$password) or die("connexion impossible au serveur");
mysql_select_db($database,$connexion) or die("la base de donnée n'a pas pu être ouverte");
$equipe=html_entity_decode($_GET['equipe']);
$login=html_entity_decode($_GET['login']);
$requet="UPDATE membre SET equipe='".mysql_real_escape_string($equipe,$connexion)."' WHERE login='".mysql_real_escape_string($login,$connexion)."'";
$result=mysql_query($requet,$connexion);
if($result) {
	echo 'Affectation effectuée'
}
else {
	echo 'Affectation non effectuée'
}
?>
	

Posté : 29 août 2007, 20:25
par sadeq
Wow, c'est trés bien. Je sens que ça va être rapide.

Quoique, je te rajoute quelques réglages à ton code:
Page: affecter.membre.serveur.php
<?php
//reçoit 2 paramètres: equipe et login du membre
//print_r($_GET);
$equipe = trim(html_entity_decode($_GET['equipe']));
$login = trim(html_entity_decode($_GET['login']));
if ($equipe && $login && file_exists('../bzw.php')){
	include('../bzw.php');
	//Affecter le membre à l'équipe 
	$connexion = mysql_connect($host,$user,$password) or die("connexion impossible au serveur");
	mysql_select_db($database,$connexion) or die("la base de donnée n'a pas pu être ouverte");
	$requet = "UPDATE membre SET equipe='".mysql_real_escape_string($equipe,$connexion)."' WHERE login='".mysql_real_escape_string($login,$connexion)."'";
	$result = mysql_query($requet,$connexion);
	//Vérifier si la mise à jour est effectuée
	if ($result) {
    	echo utf8_encode('Affectation effectuée');
		exit;
	}
}
//Dans tous les cas d'erreur
echo utf8_encode('Affectation non effectuée');
?>
Bien, après avoir tester ce programme sur un navigateur par l'URL de test suivante:

Code : Tout sélectionner

affecter.membre.serveur.php?equipe=e1&login=m1
où m1 est le login existant d'un membre dans la table membre.

Maintenant, côté interface, on va programmer Ajax pour tester l'appel au programme serveur avec la même URL précédente.

Le principe Ajax est simple, il faut créer une instance de l'objet HTTPRequest et l'utiliser pour appeler une page serveur, recevoir son résultat XML/HTML et l'afficher sur le document HTML actif sans que ce dernier ne se recharge.
L'astuce courante pour afficher les résultats d'Ajax et de spécifier la balise qui recevera la réponse dans la fonction Ajax.

Voici un module Ajax générique qu'on peut réutiliser et adapter à toute solution. Ici, je l'ai adapté à notre test:
Page: affecter.membre.client.php

Code : Tout sélectionner

<script> /** * Moteur Ajax */ function getXhr(){ var xhr = null; if(window.XMLHttpRequest) // Firefox et autres xhr = new XMLHttpRequest(); else if(window.ActiveXObject){ // Internet Explorer try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } } else { // XMLHttpRequest non supporté par le navigateur alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest..."); xhr = false; } return xhr; } /** * Méthode qui appelle un script serveur et renvoit sa réponse * * serveur: l'url du script serveur appelé * reponse: objet HTML donné par référence à un conteneur HTML de la page chargée * paramètres: liste des paramètres éventuellement passés au script serveur (param1=valeur1&param2=valeur2...) **/ function getByAjax(serveur, reponse, methode, parametres){ var xhr = getXhr(); //Nouvelle instance Ajax if (xhr && serveur){ // On défini la fonction observant la communication Ajax/serveur xhr.onreadystatechange = function(){ // le code 4/200: détermine que Ajax a reçu une réponse du serveur if(xhr.readyState == 4 && xhr.status == 200){ reponse.innerHTML = xhr.responseText; //renvoit la réponse du serveur dans le conteneur reponse } } // Déclenchement de l'appel Ajax/serveur + envoi paramètres POST ou GET if (methode == "POST"){ xhr.open("POST", serveur, true); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.send(parametres); } else { xhr.open("GET", serveur+"?"+parametres, true); xhr.send(null); } } } </script> <!-- bouton de test de l'URL --> <input type="button" value="Tester Ajax" onClick="getByAjax('affecter.membre.serveur.php', document.getElementById('div_reponse'), 'GET', 'equipe=e1&login=m1');"> <!-- Div de réponse Ajax --> <div id="div_reponse"></div>
J'explique: la fonction getByAjax attend 4 paramètres:
  • 1. serveur: le nom de la page "serveur",
    2. reponse: la balise HTML qui recevera la réponse Ajax du serveur, c'est le div "div_reponse" dans notre cas.
    3. methode de postage POST ou GET dans notre cas c'est GET
    4. la liste des paramètres à transmettre, dans notre cas c'est la chaîne 'equipe=e1&login=m1'
Une fois cliqué le bouton exécute (onClick) la fonction getByAjax qui appelle le serveur et retourne le résultat dans le div réponse prévu pour ça.

Ok?

Posté : 29 août 2007, 21:16
par orgerix
Jusque la, c'est dans mes cordes donc je suis. Et maintenant, je rentre en terrain inconnu.

Posté : 29 août 2007, 22:09
par sadeq
Je sais pas si t'as testé et compris cette première approche Ajax de notre problème pour qu'on puisse continuer et attaquer l'interface graphique et le jeu de drag&drop qui va automatiser la rédaction et l'envoi des paramètres membre et equipe.

J'attends ton feu vert.

Posté : 30 août 2007, 08:06
par mojorisin
Personnelement j'utiiserais la combinaison prototype.js + scriptaculous qui permet de gerer cela de manière très simple.
Exemple avec un panier : shop

Posté : 30 août 2007, 09:33
par orgerix
C'est bon, j'ai compris, on peut continuer.

Posté : 30 août 2007, 20:29
par AB
Personnelement j'utiiserais la combinaison prototype.js + scriptaculous qui permet de gerer cela de manière très simple.
Exemple avec un panier : shop
Sans doute une bonne adresse mais ici on fait des scripts autonomes avec nos petits doigts qui tapotent sur le clavier.

Intégrer un script tout fait c'est bien et rapide, jusqu'au moment où tu veux ajouter une nouvelle fonctionnalité. Dans ce cas il te faut alors déchiffrer tout le code qui n'est généralement pas documenté. Alors autant le faire soi-même avec des méthodes que l'on sait gérer et progresser pas à pas :)

Enfin bon, ne le prends pas mal. Mais comme je suis ce topic, j'aimerais bien qu'il aille jusqu'au bout :wink:

He sadeq, ça pourrait faire un bon tuto. Un exercice un peu ludique pour mettre en valeur et commencer l'AJAX, c'est pas courant et tellement plus motivant :)

Posté : 31 août 2007, 00:18
par sadeq
Effectivement, AB notre démarche est formative et non productive, et je salut en passant notre ami mojorisin qui a tout à fait raison de proposer sa solution qui s'inscrit tout à fait dans l'esprit. On va continuer néaumoins dans notre démarche pas à pas.

On était où? Ah, on a écrit le serveur paramétré, on l'a testé par appel d'URL simple , ça marche, on a écrit le client Ajax qui fait l'appel automatisé au serveur, ça marche, on a tout compris jusqu'à maintenant. Parfait, la suite alors:

Maintenant, on doit créer l'interface graphique qui représente le dispatching membres/équipes.

Voici, une première ébauche:
on suppose qu'on a dans la base 2 équipes avec 1 membre chacune :

Code : Tout sélectionner

INSERT INTO `membre` (`login`, `equipe`) VALUES ('m1', 'e1'), ('m2', 'e2');
L'interface client, doit afficher alors 2 cadres (div) pour représenter les 2 équipes e1 et e2
et dans chaque cadre apparaîtra 1 membre sous forme d'icône avec le nom du membre.
m1 dans le cadre e1 et m2 dans le cadre e2.

En dur, celà peut s'écrire en HTML comme ça:

Code : Tout sélectionner

<!-- Une équipe --> <div id='e1' class="equipe"><b>e1</b><hr> <!-- Un membre --> <div id='m1' class="membre">m1</div> </div> <!-- Une équipe --> <div id='e2' class="equipe"><b>e2</b><hr> <!-- Un membre --> <div id='m2' class="membre">m2</div> </div>
Avec biensûr 2 classes de style CSS membre et equipe pour mettre en forme les objets div comme ça par exemple:

Code : Tout sélectionner

<style> .equipe {width:200px; height:200px; border: 1px solid #eeeeee; background-image:url(equipe.gif); background-repeat:no-repeat; cursor:pointer; text-align:center; margin:10} .membre {width:30px; height:30px; line-height:70px; border-style:none; background-image:url(membre.gif); background-repeat:no-repeat; cursor:pointer; ; text-align:center; margin:10} </style>
Eu, tu remarques les 2 images equipe.gif et membre.gif, ils sont affichées par le style CSS en tant qu'images d'arrière-plan (background-image) pour représenter respectivement, l'espace équipe et l'icône membre.

Ok, tu suis ?

L'idée maintenant est de programmer un drag&drop sur chaque membre et cadre équipe
Le drag doit se faire sur les div membres et sera représenté par l'événement onMouseDown c'est à dire qu'on va programmer par javascript l'action de pression sur la souris en pointant un membre
Celà s'écrirait par exemple pour le membre m1 comme suit:

Code : Tout sélectionner

<div id='m1' onMouseDown="selectMembre(this);" class="membre">m1</div>
où la fonction qu'on a nommé "selectMembre(this)" est la procédure javascript qu'il faudra écrire pour programmer le drag.

Alors, que doit faire cette fonction? en principe au début l'utilisateur va pointer la souris sur le div d'un membre et va presser le bouton de la souris pour commencer le déplacement du membre, c'est ça le drag, et donc la fonction "selectMembre(this)" doit simplement mémoriser l'objet membre pointé c'est pourquoi on le lui a passé comme paramètre par le mot javascript "this" qui veut dire "l'objet en cours"

Effectivement, puisque c'est le div membre qui déclenche le "onMouseDown" le "this" dans la fonction "selectMembre(this)" lui fait référence. on passe donc la référence de l'objet membre à cette fonction qui doit tout simplement le mémoriser dans une variable globale pour le marquer comme membre sélectionné.

Cette technique permettra plutard au contexte "drop" de savoir quel membre a été pointé et donc sujet du déplacement.

Voici donc l'algorithme de la fonction "selectMembre(this)" :

Code : Tout sélectionner

<script> //CODE POUR LE DRAG&DROP //mémoire globale d'un membre sélectionné var membre_select = null; //fonction pour sélectionner le membre pointé = commencement du drag&drop function selectMembre(membre){ membre_select = membre; } </script>
Voilà la signature de la fonction selectMembre, elle recevra dans le paramètre "membre" un objet membre transmis par "this" par le onMouseDown et le mémorisera dans la variable globale "membre_select"

L'intérêt de la variable "membre_select" est qu'elle est visible par toutes les fonctions javascript du document. On l'utilisera alors dans la fonction à venir qui s'occupera du "drop" c'est à dire quand l'utilisateur pointera sa souris toujours préssée sur un cadre équipe en vue de déplacer le membre qu'il a sélectionné.

As tu compris? as-tu des questions, jusque là?