Merge branch '165-fragen-reihenfolge-verschieben' into 'master'
Resolve "Fragen Reihenfolge verschieben" Closes #165 See merge request enrichment-2024/qivip!122
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 5.1.7 on 2026-01-17 11:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('library', '0071_quizcriticism_id_question'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='qivipquestion',
|
||||
options={'ordering': ['order']},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='qivipquestion',
|
||||
name='order',
|
||||
field=models.PositiveIntegerField(default=0),
|
||||
),
|
||||
]
|
||||
@@ -113,6 +113,10 @@ class QivipQuestion(models.Model):
|
||||
related_name="questions"
|
||||
)
|
||||
credits=models.TextField(blank=True, editable=True)
|
||||
order = models.PositiveIntegerField(default=0)
|
||||
|
||||
class Meta:
|
||||
ordering = ['order'] # Fragen nach Reihenfolge sortieren
|
||||
|
||||
def __str__(self):
|
||||
return self.data[:50]
|
||||
|
||||
@@ -20,6 +20,8 @@ urlpatterns = [
|
||||
path('detail/copy/<int:pk>/', views.copy_quiz, name='copy_quiz'),
|
||||
path('favorite_quiz/<int:pk>/', views.favorite_quiz, name='favorite_quiz'),
|
||||
path('critique/delete/<int:critique_id>/<int:quiz_id>', views.delete_critique, name='delete_critique'),
|
||||
path('quiz/reorder/', views.reorder_questions, name='reorder_questions'),
|
||||
|
||||
path("quiz-names-json/", views.quiz_names_json, name="quiz_names_json"),
|
||||
path(
|
||||
"autocomplete/quiz",
|
||||
|
||||
@@ -94,6 +94,17 @@ def quiz_names_json(request):
|
||||
return JsonResponse(names, safe=False)
|
||||
|
||||
|
||||
|
||||
def reorder_questions(request):
|
||||
if request.method == "POST":
|
||||
data = json.loads(request.body)
|
||||
for item in data['order']:
|
||||
QivipQuestion.objects.filter(id=item['id']).update(order=item['position'])
|
||||
return JsonResponse({'status': 'ok'})
|
||||
return JsonResponse({'status': 'error'}, status=400)
|
||||
|
||||
|
||||
|
||||
def apply_quiz_filters(queryset, form):
|
||||
|
||||
if not form.is_valid():
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% load static %}
|
||||
<script src="{% static 'js/sortablejs/Sortable.min.js' %}"></script>
|
||||
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex flex-wrap space-y-2 items-center justify-between mb-6 dark:text-white">
|
||||
@@ -129,16 +131,16 @@
|
||||
|
||||
{% if questions %}
|
||||
|
||||
<div class="divide-y divide-gray-200">
|
||||
<div class="divide-y divide-gray-200" id="questions-list">
|
||||
{% for question in questions %}
|
||||
|
||||
|
||||
|
||||
<div class="w-full rounded-xl p-4 hover:bg-gray-50 dark:hover:bg-[#2a2f3a] dark:text-white">
|
||||
<p>{{ forloop.counter }}.</p>
|
||||
<div data-question-id="{{ question.id }}" class="question-item w-full rounded-xl p-4 hover:bg-gray-50 dark:hover:bg-[#2a2f3a] dark:text-white">
|
||||
|
||||
{% if quiz.user_id == request.user %} <a class="block flex h-full w-full" href="{% url 'library:edit_question' question.id %}" > {% endif %}
|
||||
<div class="flex justify-between items-start">
|
||||
|
||||
<p class="question-counter pr-4 ">{{ forloop.counter }}.</p>
|
||||
<div class="flex-grow">
|
||||
<p class="font-medium">{{ question.data.question }}</p>
|
||||
<div class="mt-1">
|
||||
@@ -593,4 +595,51 @@
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
|
||||
{% if quiz.user_id == request.user %}
|
||||
|
||||
<script>
|
||||
Sortable.create(document.getElementById('questions-list'), {
|
||||
animation: 300,
|
||||
swapThreshold: 0.65,
|
||||
delay: 100, // wie lange gedrückt halten in ms
|
||||
delayOnTouchOnly: true, // nur auf Touch-Geräten anwenden
|
||||
touchStartThreshold: 5,
|
||||
|
||||
onStart: () => {
|
||||
if (navigator.vibrate) {
|
||||
navigator.vibrate(75);
|
||||
}
|
||||
},
|
||||
|
||||
onEnd: () => {
|
||||
|
||||
const items = Array.from(document.querySelectorAll('#questions-list .question-item'));
|
||||
|
||||
// Counter im Browser updaten
|
||||
items.forEach((el, i) => {
|
||||
const counterEl = el.querySelector('.question-counter');
|
||||
if (counterEl) counterEl.textContent = `${i+1}.`;
|
||||
});
|
||||
// Reihenfolge sammeln
|
||||
const order = Array.from(document.querySelectorAll('#questions-list .question-item'))
|
||||
.map((el, i) => ({id: el.dataset.questionId, position: i+1}));
|
||||
|
||||
|
||||
// an Django senden
|
||||
fetch("{% url 'library:reorder_questions' %}", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': '{{ csrf_token }}'
|
||||
},
|
||||
body: JSON.stringify({order})
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user