09-09-2010, 02:25 PM
D'accord. Donc ton drag'n'drop devra plutôt déclencher l'action update du contrôleur tiles.
Je précise que le code qui vient n'est pas testé, c'est écrit à la volée. Donc à toi de l'adapter si besoin.
Donc, admettons qu'on est dans l'action edit du contrôleur maps (puisque c'est la page pour éditer une carte. Notre action devrait donc être à peu près comme ça :
Sur chaque élément du DOM qui représente une tuile, ajoute un attributs pour l'URL de modification. Exemple avec Haml (que je te conseille vivement si tu ne l'utilise pas déjà), tu auras donc une vue maps/edit.html.haml contenant quelque chose comme :
Il te faudra une vue partielle : crée un fichier _tile.html.haml dans le répertoire app/views/tiles/tile avec le contenu suivant :
Jusque là, très simple, le code HTML de chaque tuile aura cette tronche :
Et chaque outil ressemblera à :
Voilà pour le HTML : la carte et la palette.
Pour le Javascript, tu auras un code de ce genre :
Ainsi, les outils sont draggable (on peut les déplacer), et les tuiles sont droppable (elles peuvent recevoir des éléments draggable).
Quand on relâche un outil sur une tuile, la méthode onDrop est appelée, on récupère l'URL spécifiée sur la balise de la tuile ainsi que le type de terrain de l'outil. On construit également un hash de paramètres Rails ready
Ensuite, on effectue la requête Ajax. Elle utilisera la méthode PUT puisqu'on va chercher à modifier une tuile existante. On ajoute .js à l'URL pour préciser à Rails que c'est de l'Ajax. Normalement, il gère bien sans d'autant que Prototype est très fidèle aux conventions de Rails, mais n'en étant pas sûr je préfère être bullet-proof.
La vue qui sera rendu par l'appel à l'action demandée (tiles#update, en l'occurrence) devra rendre du Javascript, qui sera interprété comme tel.
Ensuite, on crée la vue pour cette action (app/views/tiles/update.js.haml) et on y place le code suivant.
Là aussi c'est plutôt simple, on génère le HTML pour notre nouvelle tuile, on l'échappe pour Javascript puis on le place dans une variable Ruby html_for_tile.
Ensuite, on génère la partie Javascript de notre vue (puisque rappelons-nous que le texte qui sera produit par notre vu sera utilisé en guise de réponse à la requête asynchrone et interprété comme du Javascript) dans un bloc :plain pour que seules les expression de la forme #{expression} soient interprétées par Ruby.
Et voilà, on a notre éditeur de carte !
Sephi-Chan
Je précise que le code qui vient n'est pas testé, c'est écrit à la volée. Donc à toi de l'adapter si besoin.
Donc, admettons qu'on est dans l'action edit du contrôleur maps (puisque c'est la page pour éditer une carte. Notre action devrait donc être à peu près comme ça :
class MapsController < ApplicationController
def edit
@map = Map.find(params[:id])
@tile_types = @map.tile_types # Les types de terrain disponibles pour cette carte.
end
# Reste du contrôleur…
end
Sur chaque élément du DOM qui représente une tuile, ajoute un attributs pour l'URL de modification. Exemple avec Haml (que je te conseille vivement si tu ne l'utilise pas déjà), tu auras donc une vue maps/edit.html.haml contenant quelque chose comme :
.map{ :id => "map-#{@map.id}" }
- @map.tiles.each do |tile|
= render('tiles/tile', :map => @map, :tile => tile)
%ul#toolbox
- @tile_types.each do |tile_type|
%li.tool{ :id => tile_type.id, :data => { :terrain => tile_type.terrain } }
= image_tag("terrains/#{tile_type.terrain}.png")
Il te faudra une vue partielle : crée un fichier _tile.html.haml dans le répertoire app/views/tiles/tile avec le contenu suivant :
.tile{ :id => "tile-#{tile.id}",
:class => tile.tile_type.terrain,
:data => { :url => map_tile_path(map, tile), :terrain => tile.tile_type.terrain } }
Jusque là, très simple, le code HTML de chaque tuile aura cette tronche :
<div class="tile grass" id="tile-23" data-url="/maps/1/tiles/23" data-terrain="grass" />
Et chaque outil ressemblera à :
<li id="2" data-terrain="grass">
<img src="/images/terrains/grass.png" />
</li>
Voilà pour le HTML : la carte et la palette.
Pour le Javascript, tu auras un code de ce genre :
$$(".tool").each(function(tile){
new Draggable(tile.id);
});
$$(".tile").each(function(tile){
Droppables.add(tile.id, {
onDrop: function(tool, tile, event){
var tileUrl = tile.getAttribute('data-url') + ".js";
var tileTypeId = tool.getAttribute('id');
var parameters = {
tile: {
tile_type_id: tileTypeId
}
};
new Ajax.Request(tileUrl, {
method: "put",
contentType: "text/javascript",
parameters: parameters
});
event.preventDefault();
}
});
});
Ainsi, les outils sont draggable (on peut les déplacer), et les tuiles sont droppable (elles peuvent recevoir des éléments draggable).
Quand on relâche un outil sur une tuile, la méthode onDrop est appelée, on récupère l'URL spécifiée sur la balise de la tuile ainsi que le type de terrain de l'outil. On construit également un hash de paramètres Rails ready
Ensuite, on effectue la requête Ajax. Elle utilisera la méthode PUT puisqu'on va chercher à modifier une tuile existante. On ajoute .js à l'URL pour préciser à Rails que c'est de l'Ajax. Normalement, il gère bien sans d'autant que Prototype est très fidèle aux conventions de Rails, mais n'en étant pas sûr je préfère être bullet-proof.
La vue qui sera rendu par l'appel à l'action demandée (tiles#update, en l'occurrence) devra rendre du Javascript, qui sera interprété comme tel.
class TilesController < ApplicationController
def update
@map = Map.find(params[:map_id])
@tile = @map.tiles.find(params[:id])
if @tile.update_attributes(params[:tile])
# On conserve le comportement par défaut…
else
render tatus => 500
end
end
# Reste du contrôleur…
end
Ensuite, on crée la vue pour cette action (app/views/tiles/update.js.haml) et on y place le code suivant.
html_for_tile =escape_javascript(render('tile', :map => @map, :tile => @tile))
:plain
var tile = $('#{@tile.id}');
tile.insert('#{html_for_tile}');
Là aussi c'est plutôt simple, on génère le HTML pour notre nouvelle tuile, on l'échappe pour Javascript puis on le place dans une variable Ruby html_for_tile.
Ensuite, on génère la partie Javascript de notre vue (puisque rappelons-nous que le texte qui sera produit par notre vu sera utilisé en guise de réponse à la requête asynchrone et interprété comme du Javascript) dans un bloc :plain pour que seules les expression de la forme #{expression} soient interprétées par Ruby.
Et voilà, on a notre éditeur de carte !
Sephi-Chan