From 1620fc15d1d21989fb38d9f3596cdf03f8535ff5 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Willms Date: Sun, 22 Mar 2026 16:13:59 +0100 Subject: implement logic that may collapse list, fixes #6380 --- app/controllers/course/overview.php | 4 +- lib/classes/CourseDateList.php | 4 +- resources/assets/javascripts/bootstrap/lists.js | 57 +++++++++++++++++++++++++ resources/assets/javascripts/entry-base.js | 1 + templates/dates/course_date_list.php | 13 +++++- 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 resources/assets/javascripts/bootstrap/lists.js diff --git a/app/controllers/course/overview.php b/app/controllers/course/overview.php index 4325de8..e87417e 100644 --- a/app/controllers/course/overview.php +++ b/app/controllers/course/overview.php @@ -67,7 +67,9 @@ class Course_OverviewController extends AuthenticatedController $this->next_date = $this->course->getNextDate(); $this->first_date = $this->course->getFirstDate(); $show_link = $GLOBALS["perm"]->have_studip_perm('autor', $this->course_id) && $this->course->isToolActive('schedule'); - $this->times_rooms = $this->course->getAllDatesInSemester()->toHtml(); + $this->times_rooms = $this->course->getAllDatesInSemester()->toHtml( + as_collapsible_list: true + ); //Load lecturers: $lecturers = $this->course->getMembersWithStatus('dozent'); diff --git a/lib/classes/CourseDateList.php b/lib/classes/CourseDateList.php index cb1c504..02261e0 100644 --- a/lib/classes/CourseDateList.php +++ b/lib/classes/CourseDateList.php @@ -180,7 +180,8 @@ class CourseDateList implements Stringable public function toHtml( bool $group_by_rooms = false, bool $with_room_names = false, - bool $with_cancelled_dates = false + bool $with_cancelled_dates = false, + bool $as_collapsible_list = false ) : string { if ($this->isEmpty()) { return _('Die Zeiten der Veranstaltung stehen nicht fest.'); @@ -230,6 +231,7 @@ class CourseDateList implements Stringable } else { $template = $GLOBALS['template_factory']->open('dates/course_date_list'); $template->with_room_names = $with_room_names; + $template->as_collapsible_list = $as_collapsible_list; $template->collection = $this; } $template->with_cancelled_dates = $with_cancelled_dates; diff --git a/resources/assets/javascripts/bootstrap/lists.js b/resources/assets/javascripts/bootstrap/lists.js new file mode 100644 index 0000000..ac7b85c --- /dev/null +++ b/resources/assets/javascripts/bootstrap/lists.js @@ -0,0 +1,57 @@ +import {$gettext} from "@/assets/javascripts/lib/gettext"; + +(() => { + let uniqueId = 0; + + STUDIP.ready(() => { + document.querySelectorAll('.collapsible-list').forEach(list => { + if (!list.matches('ol,ul')) { + console.error('Not applicable for anything else than ol/ul lists'); + } + + const data = list.dataset; + + if (data.collapsibleListInitialized !== undefined) { + return; + } + + data.collapsibleListInitialized = true; + + const label = data.label ?? $gettext('Einträge'); + const max = Number.parseInt(data.collapseAfter ?? 5, 10); + const items = Array.from(list.children); + const hiddenItems = items.slice(max); + const hiddenCount = hiddenItems.length; + + if (hiddenCount === 0) { + return; + } + + const id = list.getAttribute('id') ?? `collapsable-list-${uniqueId++}`; + list.setAttribute('id', id); + + const button = Object.assign(document.createElement('button'), { + className: 'as-link', + textContent: '', + type: 'button', + }); + button.setAttribute('aria-controls', id); + + const update = (collapsed) => { + button.textContent = collapsed + ? $gettext('%{count} weitere %{label} anzeigen', {count: hiddenCount, label}) + : $gettext('weniger %{label} anzeigen', {label}); + button.setAttribute('aria-expanded', collapsed ? 'false' : 'true'); + hiddenItems.forEach(li => li.toggleAttribute('hidden', collapsed)); + }; + + update(true); + + button.addEventListener('click', () => { + update(button.getAttribute('aria-expanded') === 'true'); + }); + + list.after(button); + }); + }); +})(); diff --git a/resources/assets/javascripts/entry-base.js b/resources/assets/javascripts/entry-base.js index ad114f1..b4f807c 100644 --- a/resources/assets/javascripts/entry-base.js +++ b/resources/assets/javascripts/entry-base.js @@ -15,6 +15,7 @@ import "./jquery-bundle.js" import "./init.js" import "./bootstrap/responsive.js" import "./bootstrap/vue.js" +import "./bootstrap/lists.js" import "./studip-ui.js" import "./bootstrap/fullscreen.js" diff --git a/templates/dates/course_date_list.php b/templates/dates/course_date_list.php index bcc9eb7..5f2fd56 100644 --- a/templates/dates/course_date_list.php +++ b/templates/dates/course_date_list.php @@ -3,14 +3,25 @@ * @var CourseDateList $collection * @var bool $with_room_names * @var bool $with_cancelled_dates + * @var bool $as_collapsible_list * * @var SeminarCycleDate $regular_date * @var CourseDate $single_date * @var CourseExDate $cancelled_date */ ?> + 'list-unstyled', +]); + +if ($as_collapsible_list) { + $html_attributes['class'] = 'collapsible-list'; + $html_attributes['data-label'] = _('Termine'); +} +?> isEmpty()) : ?> -