On rajoute un formulaire drag & drop pour les votes à classement
This commit is contained in:
parent
5c7d992dc0
commit
6d29267ef8
2 changed files with 173 additions and 11 deletions
|
@ -4,29 +4,105 @@
|
|||
|
||||
{% block extra_head %}
|
||||
<script>
|
||||
const nb_options = {{ nb_options }};
|
||||
var ranks_used = 1;
|
||||
var rank_zones = new Array(nb_options + 1);
|
||||
var ranked = 0;
|
||||
|
||||
function getLabelText($input) {
|
||||
var label = $input.closest('.field').querySelector('.label label').innerHTML;
|
||||
return label.substring(0, label.length - 1).trim();
|
||||
}
|
||||
|
||||
// Fonction auxilliaires gérant le drag & drop
|
||||
function dragstart_handler(event) {
|
||||
event.dataTransfer.setData('text/plain', event.target.id);
|
||||
}
|
||||
|
||||
function dragover_handler(event) {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
|
||||
function drop_handler(event) {
|
||||
event.preventDefault();
|
||||
// On récupère l'id de la tuile à déplacer
|
||||
const data = event.dataTransfer.getData('text/plain');
|
||||
|
||||
var $target = event.target.closest('.drop-zone');
|
||||
|
||||
if ($target.id == 'rank-add') {
|
||||
ranks_used += 1;
|
||||
|
||||
// Si on a autant de rangs que d'option, on cache le bouton +
|
||||
if (ranks_used == nb_options) {
|
||||
$target.parentElement.classList.add('is-hidden');
|
||||
}
|
||||
|
||||
$target = rank_zones[ranks_used];
|
||||
$target.parentElement.classList.remove('is-hidden');
|
||||
}
|
||||
|
||||
// On déplace l'option
|
||||
var $tile = document.getElementById(data);
|
||||
$target.appendChild($tile);
|
||||
|
||||
// On enregistre le rang dans le formulaire
|
||||
const rank = $target.dataset.rank;
|
||||
var $input = document.getElementById($tile.dataset.input);
|
||||
$input.value = rank;
|
||||
|
||||
// On modifie ranked pour savoir combien d'option on a classé
|
||||
ranked += ($target.id == 'unranked' ? -1 : 1);
|
||||
|
||||
// On décale pour éviter les rangs vides
|
||||
for (let i = 1; i <= ranks_used && i < nb_options; i++) {
|
||||
// On a au moins le tag avec le numéro du rang
|
||||
if (rank_zones[i].childElementCount == 1) {
|
||||
while (rank_zones[i + 1].childElementCount > 1) {
|
||||
let $tile = rank_zones[i + 1].lastChild;
|
||||
let $input = document.getElementById($tile.dataset.input);
|
||||
$input.value = i.toString();
|
||||
rank_zones[i].append($tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// On cache la dernière zone si elle est vide, mias on garde au moins la première
|
||||
if (ranks_used > 1 && rank_zones[ranks_used].childElementCount == 1) {
|
||||
// On affiche le bouton + si besoin
|
||||
if (ranks_used == nb_options) {
|
||||
let $add_rank = document.getElementById('rank-add');
|
||||
$add_rank.parentElement.classList.remove('is-hidden')
|
||||
}
|
||||
|
||||
rank_zones[ranks_used].parentElement.classList.add('is-hidden');
|
||||
ranks_used -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Affiche le modal et remplit le récapitulatif
|
||||
document.getElementById('confirm-button').addEventListener('click', () => {
|
||||
var $modal_body = document.getElementById('modal-body');
|
||||
|
||||
var ranks = new Array({{ nb_options }} + 1);
|
||||
var ranks = new Array(nb_options + 1);
|
||||
|
||||
(document.querySelectorAll('.control .input') || []).forEach($input => {
|
||||
var rank = parseInt($input.value);
|
||||
if ($input.value == '') {
|
||||
rank = {{ nb_options }};
|
||||
}
|
||||
var rank = parseInt($input.value) || nb_options;
|
||||
|
||||
var option = $input.closest('.field').querySelector('.label label').innerHTML;
|
||||
option = option.substring(0, option.length - 1).trim();
|
||||
var option = getLabelText($input)
|
||||
|
||||
if (rank > 0 && rank <= {{ nb_options }}) {
|
||||
ranks[rank] = (ranks[rank] || []).concat([option]); // TODO: chercher une meilleure méthode
|
||||
if (rank > 0 && rank <= nb_options) {
|
||||
ranks[rank] = (ranks[rank] || []).concat([option]);
|
||||
} else {
|
||||
ranks[nb_options] = (ranks[nb_options] || []).concat([option]);
|
||||
}
|
||||
});
|
||||
|
||||
var table_rows = '';
|
||||
|
||||
for (let i = 1; i <= {{ nb_options }}; i++) {
|
||||
for (let i = 1; i <= nb_options; i++) {
|
||||
var option_list = '';
|
||||
|
||||
if (!(typeof ranks[i] === 'undefined')) {
|
||||
|
@ -49,7 +125,55 @@
|
|||
${table_rows}
|
||||
</tbody>
|
||||
</table>`;
|
||||
});
|
||||
|
||||
// Change le mode de remplissge de formulaire (input vs drag & drop)
|
||||
document.getElementById('change-method').addEventListener('click', () => {
|
||||
var $hide = document.getElementById('hide-form');
|
||||
var $drag_zone = document.getElementById('drag-zone');
|
||||
var $method_button = document.getElementById('change-method');
|
||||
|
||||
// On échange ce qui est visible
|
||||
$hide.classList.toggle('is-hidden');
|
||||
$drag_zone.classList.toggle('is-hidden');
|
||||
|
||||
if ($hide.classList.contains('is-hidden')) {
|
||||
$method_button.innerHTML = "{% trans "Utiliser le formulaire classique" %}";
|
||||
} else {
|
||||
$method_button.innerHTML = "{% trans "Utiliser le cliquer-déposer" %}";
|
||||
}
|
||||
});
|
||||
|
||||
// Initialise les éléments pour le formulaire interactif
|
||||
var $unranked = document.getElementById('unranked');
|
||||
|
||||
for (let i = 1; i <= nb_options; i++) {
|
||||
rank_zones[i] = document.getElementById(`rank-${i}`);
|
||||
}
|
||||
|
||||
(document.querySelectorAll('.control .input') || []).forEach($input => {
|
||||
var option = getLabelText($input);
|
||||
|
||||
// On créé une tuile avec le nom de l'option
|
||||
var $tile = document.createElement('div');
|
||||
|
||||
$tile.classList.add('tile', 'is-parent', 'is-flex-grow-0');
|
||||
$tile.id = `tile-${$input.id}`;
|
||||
$tile.dataset.input = $input.id;
|
||||
$tile.innerHTML = `<p class="tile is-child notification is-primary">${option}</p>`;
|
||||
|
||||
$tile.setAttribute('draggable', true);
|
||||
$tile.addEventListener('dragstart', dragstart_handler);
|
||||
|
||||
// On rajoute la tuile dans le classement ou dans les non classées
|
||||
const rank = parseInt($input.value);
|
||||
if (!(typeof rank === 'undefined') && rank > 0 && rank <= nb_options) {
|
||||
rank_zones[rank].appendChild($tile);
|
||||
} else {
|
||||
$unranked.appendChild($tile);
|
||||
// On enlève les valeurs non règlementaires
|
||||
$input.value = '';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -58,5 +182,42 @@
|
|||
|
||||
|
||||
{% block vote_form %}
|
||||
<div class="tile is-ancestor">
|
||||
<div class="tile is-parent">
|
||||
<a id="change-method" class="tile is-child notification has-text-centered is-size-5 is-primary">
|
||||
{% trans "Utiliser le formulaire classique" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="drag-zone" class="tile is-ancestor">
|
||||
<div class="tile is-vertical">
|
||||
{% for i in range_options %}
|
||||
<div class="tile is-parent is-flex-grow-0 {% if not forloop.first %}is-hidden{% endif %}" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">
|
||||
<div id="rank-{{ i }}" class="tile is-child notification is-primary is-light pl-3 pt-3 drop-zone" data-rank="{{ i }}">
|
||||
<div class="tag is-medium is-primary">{% blocktrans %}Rang {{ i }}{% endblocktrans %}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="tile is-parent is-flex-grow-0" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">
|
||||
<div id="rank-add" class="tile is-child notification has-text-centered drop-zone">
|
||||
<span class="icon-text subtitle has-text-primary">
|
||||
<span class="icon">
|
||||
<i class="fas fa-plus"></i>
|
||||
</span>
|
||||
<span>{% trans "Ajouter un rang" %}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="unranked" class="tile is-vertical drop-zone" ondrop="drop_handler(event)" ondragover="dragover_handler(event)" data-rank="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="hide-form" class="block is-hidden">
|
||||
{% include "forms/formset.html" %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -529,6 +529,7 @@ class VoteView(OpenElectionOnlyMixin, DetailView):
|
|||
context["q_index"] = questions.index(self.object) + 1
|
||||
context["q_total"] = len(questions)
|
||||
context["nb_options"] = self.object.options.count()
|
||||
context["range_options"] = range(1, context["nb_options"] + 1)
|
||||
context["vote_rule"] = VOTE_RULES[self.object.type].format(**context)
|
||||
return context
|
||||
|
||||
|
|
Loading…
Reference in a new issue