diff options
| author | Moritz Strohm <strohm@data-quest.de> | 2026-01-16 09:36:16 +0000 |
|---|---|---|
| committer | Moritz Strohm <strohm@data-quest.de> | 2026-01-16 09:36:16 +0000 |
| commit | b58142fe5fa1ba1a99d850baa1465df6fa6e0d3b (patch) | |
| tree | d73956252dc17dd054d0db8e0f167a4103b7ba83 /lib | |
| parent | c3e07e221b0bef64d3ad4da48c6371c75ca12cc3 (diff) | |
updated Fullcalendar to version 6, closes #4887
Closes #4887
Merge request studip/studip!4438
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/classes/Fullcalendar.php | 88 | ||||
| -rw-r--r-- | lib/classes/InstituteCalendarHelper.php | 45 | ||||
| -rw-r--r-- | lib/classes/calendar/EventData.php | 2 | ||||
| -rw-r--r-- | lib/classes/calendar/Helper.php | 60 | ||||
| -rw-r--r-- | lib/models/calendar/CalendarDateAssignment.php | 8 | ||||
| -rw-r--r-- | lib/models/calendar/ScheduleEntry.php | 5 |
6 files changed, 153 insertions, 55 deletions
diff --git a/lib/classes/Fullcalendar.php b/lib/classes/Fullcalendar.php index 8674601..d3bc823 100644 --- a/lib/classes/Fullcalendar.php +++ b/lib/classes/Fullcalendar.php @@ -3,6 +3,32 @@ namespace Studip; class Fullcalendar { + /** + * The standard month view for Stud.IP calendars. + */ + const VIEW_MONTH = 'dayGridMonth'; + + /** + * The standard week view for Stud.IP calendars. + */ + const VIEW_WEEK = 'timeGridWeek'; + + /** + * The standard day view for Stud.IP calendars. + */ + const VIEW_DAY = 'timeGridDay'; + + /** + * The standard week view for Stud.IP group calendars. + */ + const GROUP_WEEK = 'resourceTimelineWeek'; + + /** + * The standard day view for Stud.IP group calendars. + */ + const GROUP_DAY = 'resourceTimelineDay'; + + protected $title; /** @@ -58,9 +84,9 @@ class Fullcalendar public function setDefaultView(?string $view): void { if ($view === null) { - unset($this->config['defaultView']); + unset($this->config['initialView']); } else { - $this->config['defaultView'] = $view; + $this->config['initialView'] = $view; } } @@ -78,16 +104,56 @@ class Fullcalendar $factory = new \Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/templates'); $template = $factory->open('studip-fullcalendar.php'); $real_data_name = sprintf('data-%s', $this->data_name); - return $template->render( - [ - 'title' => $this->title, - 'config' => $this->config, - 'attributes' => array_merge( - $this->attributes, - [$real_data_name => '1'] - ) - ] + + //Move the Stud.IP parts of the configuration out of the + //fullcalendar configuration: + $fullcalendar_config = $this->config; + $template_params = [ + 'title' => $this->title, + 'dialogSize' => 'auto', + 'actionUrls' => [], + 'displayHolidays' => true, + 'displayVacations' => true, + 'externalDroppableContainerId' => '', + 'externalDroppableEventSelector' => '', + 'eventColourPicker' => false + ]; + if (!empty($this->attributes['class'])) { + $template_params['extraClasses'] = $this->attributes['class']; + unset($this->attributes['class']); + } else { + $template_params['extraClasses'] = ''; + } + $template_params['attributes'] = array_merge( + $this->attributes, + [$real_data_name => '1'] ); + if (array_key_exists('studip_urls', $fullcalendar_config) + && is_array($fullcalendar_config['studip_urls']) + ) { + $template_params['actionUrls'] = $fullcalendar_config['studip_urls']; + unset($fullcalendar_config['studip_urls']); + } + + $studip_config_map = [ + 'dialog_size' => 'dialogSize', + 'display_holidays' => 'displayHolidays', + 'display_vacations' => 'displayVacations', + 'external_droppable_container_id' => 'externalDroppableContainerId', + 'external_droppable_event_selector' => 'externalDroppableEventSelector', + 'event_colour_picker' => 'eventColourPicker', + ]; + + foreach ($studip_config_map as $config_key => $param_key) { + if (array_key_exists($config_key, $fullcalendar_config)) { + $template_params[$param_key] = $fullcalendar_config[$config_key]; + unset($fullcalendar_config[$config_key]); + } + } + + $template_params['config'] = $fullcalendar_config; + + return $template->render($template_params); } /** diff --git a/lib/classes/InstituteCalendarHelper.php b/lib/classes/InstituteCalendarHelper.php index 54393fa..404ab6a 100644 --- a/lib/classes/InstituteCalendarHelper.php +++ b/lib/classes/InstituteCalendarHelper.php @@ -190,7 +190,7 @@ class InstituteCalendarHelper } $event_colors[$event_id][$institut_id] = $color; $df[0]->content = serialize($event_colors); - return $df[0]->store(); + return $df[0]->store() !== false; } return false; } @@ -395,7 +395,7 @@ class InstituteCalendarHelper $end_time[0] += 2; $end_time = implode(':', $end_time); - $move_url = URLHelper::getURL('dispatch.php/admin/courseplanning/move_event'); + $move_url = URLHelper::getURL('dispatch.php/admin/courseplanning/move_event/' . $cycle_date->id); $name = $course->getFullName('number-name'); if ($start_time != $cycle_date['start_time'] && $end_time != $cycle_date['end_time']) { @@ -451,7 +451,7 @@ class InstituteCalendarHelper $events[] = [ 'resourceId' => $resource_column, 'id' => $cycle_date->id, - 'title' => empty($fields) ? $name : '', + 'title' => '', 'start' => $start, 'end' => $end, 'textColor' => $textcolor, @@ -462,14 +462,23 @@ class InstituteCalendarHelper 'durationEditable' => $is_duration_editable, 'resourceEditable' => true, 'studip_api_urls' => ['move' => $move_url], - 'studip_view_urls' => ['edit' => URLHelper::getURL('dispatch.php/course/details/index/' . $cycle_date->seminar_id)], + 'studip_view_urls' => [ + 'show' =>URLHelper::getURL('dispatch.php/course/details/index/' . $cycle_date->seminar_id) + ], 'metadate_id' => $cycle_date->metadate_id, 'course_id' => $cycle_date->seminar_id, 'tooltip' => self::getCycleInfos($course, $cycle_date), 'icon' => $is_start_editable ? '' : 'lock-locked', 'conform' => $conform, // custom props (event.extendedProps) - 'content_fields' => $fields, + 'title-lines' => $fields, + 'action-icons' => [ + [ + 'url' => URLHelper::getURL('dispatch.php/admin/courseplanning/pick_color/' . $cycle_date->id . '/index'), + 'icon_name' => 'group4', + 'label' => _('Farbe wählen') + ] + ] ]; } }, array_keys($courses)); @@ -535,7 +544,7 @@ class InstituteCalendarHelper $event_columns = self::getCourseEventcolumns($course); $event_colors = self::getCourseEventcolors($course); - $move_url = URLHelper::getURL('dispatch.php/admin/courseplanning/move_event'); + $move_url = URLHelper::getURL('dispatch.php/admin/courseplanning/move_event/' . $cycle_date->id); $name = $course->getFullName('number-name'); if ($start_time != $cycle_date['start_time'] && $end_time != $cycle_date['end_time']) { @@ -574,6 +583,13 @@ class InstituteCalendarHelper } } + $fields = [ + 'course_number' => UserConfig::get($GLOBALS['user']->id)->TIMETABLE_COURSE_NUMBER_VISIBLE ? ($course->veranstaltungsnummer ?: _('(keine VA-Nummer)')) : null, + 'course_name' => UserConfig::get($GLOBALS['user']->id)->TIMETABLE_COURSE_NAME_VISIBLE ? $course->getFullName('name') : null, + 'lecturers' => UserConfig::get($GLOBALS['user']->id)->TIMETABLE_LECTURERS_VISIBLE ? self::getLecturers($course) : null, + 'room' => UserConfig::get($GLOBALS['user']->id)->TIMETABLE_ROOMS_VISIBLE ? '' : null + ]; + return [ 'resourceId' => $resource_column, 'id' => $cycle_date->id, @@ -592,7 +608,16 @@ class InstituteCalendarHelper 'metadate_id' => $cycle_date->metadate_id, 'course_id' => $cycle_date->seminar_id, 'tooltip' => self::getCycleInfos($course, $cycle_date), - 'icon' => $is_start_editable ? '' : 'lock-locked' + 'icon' => $is_start_editable ? '' : 'lock-locked', + // custom props (event.extendedProps) + 'title-lines' => $fields, + 'action-icons' => [ + [ + 'url' => URLHelper::getURL('dispatch.php/admin/courseplanning/pick_color/' . $cycle_date->id . '/index'), + 'icon_name' => 'group4', + 'label' => _('Farbe wählen') + ] + ] ]; } @@ -638,8 +663,8 @@ class InstituteCalendarHelper if (!$GLOBALS['MVV_MODUL']['STATUS']['values'][$modul->stat]['public']) { return false; } - $modul_start = Semester::find($modul->start)->beginn ?: 0; - $modul_end = Semester::find($modul->end)->ende ?: PHP_INT_MAX; + $modul_start = Semester::find($modul->start)->beginn ?? 0; + $modul_end = Semester::find($modul->end)->ende ?? PHP_INT_MAX; return $modul_end >= $course->start_semester->beginn && ( $course->isOpenEnded() @@ -718,7 +743,7 @@ class InstituteCalendarHelper return $info_string; } - private static function getLecturers(Course $course): array + private static function getLecturers(Course $course): string { $dozenten = []; $lecturers = ''; diff --git a/lib/classes/calendar/EventData.php b/lib/classes/calendar/EventData.php index db1e472..233f131 100644 --- a/lib/classes/calendar/EventData.php +++ b/lib/classes/calendar/EventData.php @@ -116,7 +116,7 @@ class EventData 'studip_range_id' => $this->range_id, 'studip_view_urls' => $this->view_urls, 'studip_api_urls' => $this->api_urls, - 'icon' => $this->icon + 'icons' => $this->icon ? explode(',', $this->icon) : [] //Backwards compatibility in case only one icon is set. ] + ($this->group_id ? ['groupId' => $this->group_id] : []); } } diff --git a/lib/classes/calendar/Helper.php b/lib/classes/calendar/Helper.php index 4bcd4f6..afcfbfd 100644 --- a/lib/classes/calendar/Helper.php +++ b/lib/classes/calendar/Helper.php @@ -159,15 +159,15 @@ class Helper } $available_views = [ - 'timeGridWeek' => [ - 'columnHeaderFormat' => ['weekday' => 'short'], + \Studip\Fullcalendar::VIEW_WEEK => [ + 'dayHeaderFormat' => ['weekday' => 'short'], 'slotDuration' => $slot_duration ] ]; if (!in_array(date('N'), $hidden_days)) { //The current day is visible: Allow a day view: - $available_views['timeGridDay'] = [ - 'columnHeaderFormat' => ['weekday' => 'short'], + $available_views[\Studip\Fullcalendar::VIEW_DAY] = [ + 'dayHeaderFormat' => ['weekday' => 'short'], 'slotDuration' => $slot_duration ]; } @@ -175,27 +175,28 @@ class Helper return new \Studip\Fullcalendar( _('Stundenplan'), [ - 'editable' => true, - 'selectable' => true, - 'dialog_size' => 'auto', - 'minTime' => $schedule_settings['start_time'] ?? '08:00', - 'maxTime' => $schedule_settings['end_time'] ?? '20:00', - 'allDaySlot' => false, - 'header' => [ - 'left' => count($available_views) > 1 ? implode(',', array_keys($available_views)) : '', - 'right' => 'prev,today,next' + 'editable' => true, + 'selectable' => true, + 'dialog_size' => 'auto', + 'slotMinTime' => $schedule_settings['start_time'] ?? '08:00', + 'slotMaxTime' => $schedule_settings['end_time'] ?? '20:00', + 'allDaySlot' => false, + 'headerToolbar' => [ + 'start' => count($available_views) > 1 ? implode(',', array_keys($available_views)) : '', + 'end' => 'prev,today,next' ], 'views' => $available_views, - 'columnHeaderFormat' => ['weekday' => 'short'], - 'defaultView' => 'timeGridWeek', - 'defaultDate' => date('Y-m-d'), + 'dayHeaderFormat' => ['weekday' => 'short'], + 'initialView' => \Studip\Fullcalendar::VIEW_WEEK, + 'initialDate' => date('Y-m-d'), 'slotLabelFormat' => [ 'hour' => 'numeric', 'minute' => '2-digit', 'omitZeroMinute' => false ], - 'weekends' => true, - 'hiddenDays' => $fullcalendar_hidden_days, + 'weekends' => true, + 'weekNumbers' => false, + 'hiddenDays' => $fullcalendar_hidden_days, 'timeGridEventMinHeight' => 20, 'eventSources' => [ [ @@ -230,12 +231,12 @@ class Helper $calendar_settings = $calendar_owner->getConfiguration()->CALENDAR_SETTINGS ?? []; //Map calendar settings to fullcalendar settings: - $default_view = 'timeGridWeek'; + $default_view = \Studip\Fullcalendar::VIEW_WEEK; if (!empty($calendar_settings['view'])) { if ($calendar_settings['view'] === 'day') { - $default_view = 'timeGridDay'; + $default_view = \Studip\Fullcalendar::VIEW_DAY; } elseif ($calendar_settings['view'] === 'month') { - $default_view = 'dayGridMonth'; + $default_view = \Studip\Fullcalendar::VIEW_MONTH; } } @@ -259,29 +260,32 @@ class Helper 'allDaySlot' => true, 'allDayText' => '', 'header' => [ - 'left' => 'dayGridYear,dayGridMonth,timeGridWeek,timeGridDay', + 'left' => implode( + ',', + [\Studip\Fullcalendar::VIEW_MONTH, \Studip\Fullcalendar::VIEW_WEEK, \Studip\Fullcalendar::VIEW_DAY] + ), 'right' => 'prev,today,next' ], 'weekNumbers' => true, 'views' => [ - 'dayGridMonth' => [ + \Studip\Fullcalendar::VIEW_MONTH => [ 'eventTimeFormat' => ['hour' => 'numeric', 'minute' => '2-digit'], 'titleFormat' => ['year' => 'numeric', 'month' => 'long'], 'displayEventEnd' => true ], - 'timeGridWeek' => [ - 'columnHeaderFormat' => ['weekday' => 'short', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true], + \Studip\Fullcalendar::VIEW_WEEK => [ + 'dayHeaderFormat' => ['weekday' => 'short', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true], 'weekends' => $calendar_settings['type_week'] === 'LONG', 'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'], 'slotDuration' => $slot_durations['week'] ], - 'timeGridDay' => [ - 'columnHeaderFormat' => ['weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true], + \Studip\Fullcalendar::VIEW_DAY => [ + 'dayHeaderFormat' => ['weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true], 'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'], 'slotDuration' => $slot_durations['day'] ] ], - 'defaultView' => $default_view, + 'initialView' => $default_view, 'eventSources' => [ [ 'url' => \URLHelper::getURL( diff --git a/lib/models/calendar/CalendarDateAssignment.php b/lib/models/calendar/CalendarDateAssignment.php index 515f26b..0e2f1e8 100644 --- a/lib/models/calendar/CalendarDateAssignment.php +++ b/lib/models/calendar/CalendarDateAssignment.php @@ -30,8 +30,8 @@ - "ACKNOWLEDGED": The calendar owner only acknowledged that the date exists but doesn't necessarily participate in it. * @property CalendarDate $calendar_date The associated calendar date object. - * @property User $user - * @property Course $course + * @property User $user + * @property Course $course */ class CalendarDateAssignment extends SimpleORMap implements Event { @@ -663,8 +663,8 @@ class CalendarDateAssignment extends SimpleORMap implements Event $studip_urls['show'] = URLHelper::getURL('dispatch.php/calendar/date/index/' . $this->calendar_date_id, $show_url_params); if ($this->isWritable($user_id)) { - $action_urls['resize_dialog'] = URLHelper::getURL('dispatch.php/calendar/date/move/' . $this->calendar_date_id); - $action_urls['move_dialog'] = URLHelper::getURL('dispatch.php/calendar/date/move/' . $this->calendar_date_id, ['original_date' => $begin->format('Y-m-d')]); + $action_urls['resize'] = URLHelper::getURL('dispatch.php/calendar/date/move/' . $this->calendar_date_id); + $action_urls['move'] = URLHelper::getURL('dispatch.php/calendar/date/move/' . $this->calendar_date_id, ['original_date' => $begin->format('Y-m-d')]); } } diff --git a/lib/models/calendar/ScheduleEntry.php b/lib/models/calendar/ScheduleEntry.php index ca72e99..c9eb13c 100644 --- a/lib/models/calendar/ScheduleEntry.php +++ b/lib/models/calendar/ScheduleEntry.php @@ -312,7 +312,10 @@ class ScheduleEntry extends SimpleORMap implements Event [ 'show' => URLHelper::getURL('dispatch.php/calendar/schedule/entry/' . $this->id) ], - [], + [ + 'resize' => URLHelper::getURL('dispatch.php/calendar/schedule/move_entry/' . $this->id), + 'move' => URLHelper::getURL('dispatch.php/calendar/schedule/move_entry/' . $this->id) + ], '', $GLOBALS['PERS_TERMIN_KAT'][$this->colour_id]['border_color'] ?? '#000000', $this->isAllDayEvent() |
