From fc3d718c6362c65ffc02135f16a5454ca919a7fb Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Willms <tleilax+studip@gmail.com> Date: Thu, 13 Jul 2023 07:26:03 +0000 Subject: [PATCH] always store the whole order of widgets, fixes #2821 Closes #2821 Merge request studip/studip!1902 --- app/controllers/start.php | 17 +++--- lib/classes/WidgetHelper.php | 59 +++++++++++-------- resources/assets/javascripts/lib/startpage.js | 33 +++++++---- 3 files changed, 65 insertions(+), 44 deletions(-) diff --git a/app/controllers/start.php b/app/controllers/start.php index f47520297c1..e48bc899a25 100644 --- a/app/controllers/start.php +++ b/app/controllers/start.php @@ -255,16 +255,17 @@ class StartController extends AuthenticatedController /** * Action to store the widget placements - * - * @return void */ - public function storeNewOrder_action() + public function storeNewOrder_action(): void { - WidgetHelper::storeNewPositions( - Request::get('widget'), - Request::get('position'), - Request::get('column') - ); + if (!Request::isPost()) { + throw new MethodNotAllowedException(); + } + + $lanes = Request::getArray('lanes'); + + WidgetHelper::storeNewPositions($lanes); + $this->render_nothing(); } diff --git a/lib/classes/WidgetHelper.php b/lib/classes/WidgetHelper.php index 2122a60c763..548184ebb6b 100644 --- a/lib/classes/WidgetHelper.php +++ b/lib/classes/WidgetHelper.php @@ -63,37 +63,48 @@ class WidgetHelper /** * storeNewPositions - stores new Widget positions for a given user * - * @param array ids of widgets to be stored + * @param array $lanes array with column as index and ids array as value * * @return void */ - public static function storeNewPositions($widget, $position, $column) + public static function storeNewPositions(array $lanes): void { - $db = DBManager::get(); - $oldWidget = $db->fetchOne("SELECT position,col FROM widget_user WHERE id = ? AND range_id = ?", [$widget, $GLOBALS['user']->id]); - if ($oldWidget) { - - if ($oldWidget['col'] == $column) { - // Insert element - $db->execute("UPDATE widget_user SET position = ? WHERE id = ? ", [$position, $widget]); - if ($oldWidget['position'] < $position) { - //Move back items BETWEEN old and new position - $db->execute("UPDATE widget_user SET position = position - 1 WHERE col = ? AND range_id = ? AND position > ? AND position <= ? AND id <> ?", [$oldWidget['col'], $GLOBALS['user']->id, $oldWidget['position'], $position, $widget]); - } else { - //Move forward items BETWEEN old and new position - $db->execute("UPDATE widget_user SET position = position + 1 WHERE col = ? AND range_id = ? AND position < ? AND position >= ? AND id <> ?", [$oldWidget['col'], $GLOBALS['user']->id, $oldWidget['position'], $position, $widget]); - } - } else { - // Push all entries in the new column one position away - $db->execute("UPDATE widget_user SET position = position + 1 WHERE range_id = ? AND col = ? AND position >= ?", [$GLOBALS['user']->id, $column, $position]); + // Query not displayed widgets to sort them to the bottom of a lane + $query = "SELECT `col`, `id` + FROM `widget_user` + WHERE `range_id` = ? + AND `id` NOT IN (?) + ORDER BY `col`, `position`"; + $undisplayed = DBManager::get()->fetchGrouped($query, [ + User::findCurrent()->id, + array_merge(...$lanes) + ], function ($row) { + return array_column($row, 'id'); + }); + + // Set new positions + $query = "UPDATE `widget_user` + SET `col` = :column, + `position` = :position + WHERE `id` = :id + AND `range_id` = :user_id"; + $statement = DBManager::get()->prepare($query); + $statement->bindValue(':user_id', User::findCurrent()->id); - // Insert element - $db->execute("UPDATE widget_user SET position = ?, col = ? WHERE id = ? ", [$position, $column, $widget]); + foreach ([0, 1] as $column) { + $statement->bindValue(':column', $column); - // Move positions in old column - $db->execute("UPDATE widget_user SET position = position - 1 WHERE col = ? AND range_id = ? AND position > ?", [$oldWidget['col'], $GLOBALS['user']->id, $oldWidget['position']]); - } + $ids = array_merge( + $lanes[$column] ?? [], + $undisplayed[$column] ?? [] + ); + $position = 0; + foreach ($ids as $id) { + $statement->bindValue(':position', $position++); + $statement->bindValue(':id', $id); + $statement->execute(); + } } } diff --git a/resources/assets/javascripts/lib/startpage.js b/resources/assets/javascripts/lib/startpage.js index 15b2c591ace..1d7de31fa82 100644 --- a/resources/assets/javascripts/lib/startpage.js +++ b/resources/assets/javascripts/lib/startpage.js @@ -1,22 +1,31 @@ const startpage = { - init: function() { + init() { $('.start-widgetcontainer .portal-widget-list').sortable({ handle: '.widget-header', connectWith: 'ul.portal-widget-list', - start: function() { + start() { $(this) .closest('.start-widgetcontainer') .find('.portal-widget-list') - .addClass('ui-sortable move'); + .addClass('move'); }, - stop: function(event, ui) { - $.get(STUDIP.ABSOLUTE_URI_STUDIP + 'dispatch.php/start/storeNewOrder', { - widget: $(ui.item).attr('id'), - position: $(ui.item).index(), - column: $(ui.item) - .parent() - .index() - }); + update(event, ui) { + let lanes = []; + $(this) + .closest('.start-widgetcontainer') + .children('.portal-widget-list') + .each((index, element) => { + lanes[index] = $('.studip-widget-wrapper', element) + .map((i, el) => el.getAttribute('id')) + .get(); // Ensure we have an array + }); + + $.post( + STUDIP.URLHelper.getURL('dispatch.php/start/storeNewOrder'), + {lanes} + ); + }, + stop() { $(this) .closest('.start-widgetcontainer') .find('.portal-widget-list') @@ -25,7 +34,7 @@ const startpage = { }); }, - init_edit: function(perm) { + init_edit(perm) { $('.edit-widgetcontainer .portal-widget-list').sortable({ handle: '.widget-header', connectWith: '.edit-widgetcontainer .portal-widget-list', -- GitLab