From 0e51c62880714479e1f742602a8fd5e54ee7a5e0 Mon Sep 17 00:00:00 2001
From: Elmar Ludwig <elmar.ludwig@uni-osnabrueck.de>
Date: Thu, 2 May 2024 17:35:04 +0200
Subject: [PATCH] allow reordering of answers in seq_exercise, fixes #245

---
 css/vips.css                          |  4 ++++
 js/vips.js                            | 21 ++++++++++++++++++++-
 views/exercises/seq_exercise/edit.php | 12 ++++++------
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/css/vips.css b/css/vips.css
index d4215df..b3b7e96 100644
--- a/css/vips.css
+++ b/css/vips.css
@@ -232,6 +232,10 @@ button.vips_file_upload:hover {
     white-space: nowrap;
 }
 
+.sortable_item {
+    padding-left: 2ex;
+}
+
 .vips_drag {
     background-image: url('../../../../assets/images/anfasser_24.png');
     background-position: 2px center;
diff --git a/js/vips.js b/js/vips.js
index 0e324b3..98a3235 100644
--- a/js/vips.js
+++ b/js/vips.js
@@ -168,6 +168,26 @@ $(function() {
         event.preventDefault();
     });
 
+    $('.sortable_list').sortable({
+        axis: 'y',
+        containment: 'parent',
+        items: '> .sortable_item',
+        tolerance: 'pointer'
+    });
+
+    $(document).on('keydown', '.sortable_item', function(event) {
+        if (event.key === 'ArrowUp' && event.target === this) {
+            $(this).prev('.sortable_item:visible').before(this);
+        } else if (event.key === 'ArrowDown' && event.target === this) {
+            $(this).next('.sortable_item:visible').after(this);
+        } else {
+            return;
+        }
+
+        $(this).focus();
+        event.preventDefault();
+    });
+
     $(document).on('click', '.textarea_toggle', function(event) {
         var toggle = $(this).closest('.size_toggle');
         var items  = toggle.find('.character_input');
@@ -347,7 +367,6 @@ $(function() {
 
 function vips_post_render(element) {
     $(element).find('.rh_list').sortable({
-        item: '> .rh_item',
         tolerance: 'pointer',
         connectWith: '.rh_list',
         update: function(event, ui) {
diff --git a/views/exercises/seq_exercise/edit.php b/views/exercises/seq_exercise/edit.php
index b446bc5..08d27cb 100644
--- a/views/exercises/seq_exercise/edit.php
+++ b/views/exercises/seq_exercise/edit.php
@@ -2,13 +2,13 @@
     <?= _vips('Anzuordnende Antworten') ?>
 </div>
 
-<div class="dynamic_list">
-    <? foreach ($exercise->task['answers'] as $i => $answer): ?>
+<div class="dynamic_list sortable_list">
+    <? foreach ($exercise->task['answers'] as $answer): ?>
         <? $size = vips_flexible_input_size($answer['text']); ?>
 
-        <div class="dynamic_row mc_row">
+        <div class="dynamic_row mc_row sortable_item vips_drag" tabindex="0">
             <label class="dynamic_counter size_toggle size_<?= $size ?> undecorated">
-                <?= $this->render_partial('exercises/flexible_input', ['name' => "answer[$i]", 'value' => $answer['text'], 'size' => $size]) ?>
+                <?= $this->render_partial('exercises/flexible_input', ['name' => 'answer[]', 'value' => $answer['text'], 'size' => $size]) ?>
                 <input type="hidden" name="id[]" value="<?= $answer['id'] ?>">
             </label>
 
@@ -18,9 +18,9 @@
         </div>
     <? endforeach ?>
 
-    <div class="dynamic_row mc_row template">
+    <div class="dynamic_row mc_row sortable_item vips_drag template" tabindex="0">
         <label class="dynamic_counter size_toggle size_small undecorated">
-            <?= $this->render_partial('exercises/flexible_input', ['data_name' => 'answer', 'size' => 'small']) ?>
+            <?= $this->render_partial('exercises/flexible_input', ['data_name' => '', 'name' => 'answer[]', 'size' => 'small']) ?>
             <input type="hidden" name="id[]">
         </label>
 
-- 
GitLab