diff options
| author | Moritz Strohm <strohm@data-quest.de> | 2024-01-29 15:16:24 +0000 |
|---|---|---|
| committer | Moritz Strohm <strohm@data-quest.de> | 2024-01-29 15:16:24 +0000 |
| commit | 7c1df847d94d3956bc763b94b73cebfe108dc9a1 (patch) | |
| tree | e18e003bff65c5bf0748c644d6cd3d235cb1feca /resources/assets/javascripts | |
| parent | da0110d5e85279123e8dde392cb4c926397238bf (diff) | |
StEP 01354, closes #1354
Closes #1354
Merge request studip/studip!2116
Diffstat (limited to 'resources/assets/javascripts')
| -rw-r--r-- | resources/assets/javascripts/bootstrap/calendar_dialog.js | 11 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/forms.js | 18 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/fullcalendar.js | 1 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/resources.js | 64 | ||||
| -rw-r--r-- | resources/assets/javascripts/entry-base.js | 1 | ||||
| -rw-r--r-- | resources/assets/javascripts/init.js | 6 | ||||
| -rw-r--r-- | resources/assets/javascripts/lib/calendar_dialog.js | 64 | ||||
| -rw-r--r-- | resources/assets/javascripts/lib/dates.js | 4 | ||||
| -rw-r--r-- | resources/assets/javascripts/lib/datetime.js | 61 | ||||
| -rw-r--r-- | resources/assets/javascripts/lib/fullcalendar.js | 227 |
10 files changed, 277 insertions, 180 deletions
diff --git a/resources/assets/javascripts/bootstrap/calendar_dialog.js b/resources/assets/javascripts/bootstrap/calendar_dialog.js deleted file mode 100644 index ee5ab4c..0000000 --- a/resources/assets/javascripts/bootstrap/calendar_dialog.js +++ /dev/null @@ -1,11 +0,0 @@ -jQuery(document).on('click', 'td.calendar-day-edit, td.calendar-day-event', function(event) { - var elem = jQuery(this) - .find('a') - .first(); - if (_.isString(elem.attr('href'))) { - STUDIP.Dialog.fromURL(elem.attr('href'), { title: elem.attr('title') }); - event.preventDefault(); - } else { - return false; - } -}); diff --git a/resources/assets/javascripts/bootstrap/forms.js b/resources/assets/javascripts/bootstrap/forms.js index 1f4937d..8f9e5fc 100644 --- a/resources/assets/javascripts/bootstrap/forms.js +++ b/resources/assets/javascripts/bootstrap/forms.js @@ -427,6 +427,24 @@ STUDIP.ready(function () { }); } + /* + * Form elements with the "simplevue" class are meant for forms that just need some vue components + * to do something fancy inside the form but which do not need the full functionality of the form builder. + */ + let simple_vue_items = document.querySelectorAll('form .simplevue:not(.vueified)'); + if (simple_vue_items.length > 0) { + STUDIP.Vue.load().then(({createApp}) => { + simple_vue_items.forEach(f => { + createApp({ + el: f, + mounted() { + this.$el.classList.add('vueified'); + } + }); + }); + }); + } + // Well, this is really nasty: Select2 can't determine the select // element's width if it is hidden (by itself or by its parent). // This is due to the fact that elements are not rendered when hidden diff --git a/resources/assets/javascripts/bootstrap/fullcalendar.js b/resources/assets/javascripts/bootstrap/fullcalendar.js index 62beaa9..44786d9 100644 --- a/resources/assets/javascripts/bootstrap/fullcalendar.js +++ b/resources/assets/javascripts/bootstrap/fullcalendar.js @@ -44,4 +44,5 @@ STUDIP.ready(function () { }); } + jQuery(document).on('change', '#date_select[data-calendar-control]', STUDIP.Fullcalendar.submitDatePicker); }); diff --git a/resources/assets/javascripts/bootstrap/resources.js b/resources/assets/javascripts/bootstrap/resources.js index 25582d4..8c89b7f 100644 --- a/resources/assets/javascripts/bootstrap/resources.js +++ b/resources/assets/javascripts/bootstrap/resources.js @@ -483,7 +483,7 @@ STUDIP.ready(function () { } else if ($(this).hasClass('fc-today-button') || $(this).hasClass('fc-prev-button') || $(this).hasClass('fc-next-button')) { - updateDateURL(); + STUDIP.Fullcalendar.updateDateURL(); } } ); @@ -594,71 +594,11 @@ STUDIP.ready(function () { $('.booking-plan-allday_view').attr('href', url.toString()); } - function submitDatePicker() { - var picked = $('#booking-plan-jmpdate').val(); - var iso_date_string = ''; - if(picked) { - if (picked.includes('.')) { - let [day, month, year] = picked.split('.'); - iso_date_string = year.padStart(4, "20") + '-' + month.padStart(2, "0") + '-' + day.padStart(2, "0"); - } else if (picked.includes('/')) { - let [day, month, year] = picked.split('/'); - iso_date_string = year.padStart(4, "20") + '-' + month.padStart(2, "0") + '-' + day.padStart(2, "0"); - } else if (picked.includes('-')) { - iso_date_string = picked; - } - } - if (iso_date_string) { - $('*[data-resources-fullcalendar="1"]').each(function () { - this.calendar.gotoDate(iso_date_string); - }); - updateDateURL(); - } - } - - function updateDateURL() { - let changedMoment; - $('[data-resources-fullcalendar="1"]').each(function () { - changedMoment = $(this)[0].calendar.getDate(); - }); - if (changedMoment) { - let changedDate = STUDIP.Fullcalendar.toRFC3339String(changedMoment).split('T')[0]; - //Get the timestamp: - let timeStamp = changedMoment.getTime() / 1000; - - $('a.resource-bookings-actions').each(function () { - const url = new URL(this.href); - url.searchParams.set('timestamp', timeStamp) - url.searchParams.set('defaultDate', changedDate) - this.href = url.toString(); - }); - - // Now change the URL of the window. - const url = new URL(window.location.href); - url.searchParams.set('defaultDate', changedDate); - - // Update url in history - history.pushState({}, null, url.toString()); - - // Adjust links accordingly - url.searchParams.delete('allday'); - $('.booking-plan-std_view').attr('href', url.toString()); - - url.searchParams.set('allday', 1); - $('.booking-plan-allday_view').attr('href', url.toString()); - - // Update sidebar value - $('#booking-plan-jmpdate').val(changedMoment.toLocaleDateString('de-DE')); - - //Store the date in the sessionStorage: - sessionStorage.setItem('booking_plan_date', changedDate) - } - } jQuery('#booking-plan-jmpdate').datepicker( { dateFormat: 'dd.mm.yy', - onClose: submitDatePicker + onClose: STUDIP.Fullcalendar.submitDatePicker } ); jQuery('.resource-booking-time-fields input[type="date"]').datepicker( diff --git a/resources/assets/javascripts/entry-base.js b/resources/assets/javascripts/entry-base.js index 37bec89..bb03231 100644 --- a/resources/assets/javascripts/entry-base.js +++ b/resources/assets/javascripts/entry-base.js @@ -37,7 +37,6 @@ import "./bootstrap/multi_person_search.js" import "./bootstrap/skip_links.js" import "./bootstrap/i18n_input.js" import "./bootstrap/forms.js" -import "./bootstrap/calendar_dialog.js" import "./bootstrap/drag_and_drop_upload.js" import "./bootstrap/admin_sem_classes.js" import "./bootstrap/cronjobs.js" diff --git a/resources/assets/javascripts/init.js b/resources/assets/javascripts/init.js index 8981e95..2d592be 100644 --- a/resources/assets/javascripts/init.js +++ b/resources/assets/javascripts/init.js @@ -14,13 +14,13 @@ import Blubber from './lib/blubber.js'; import Browse from './lib/browse.js'; import Cache from './lib/cache.js'; import Calendar from './lib/calendar.js'; -import CalendarDialog from './lib/calendar_dialog.js'; import Clipboard from './lib/clipboard.js'; import Cookie from './lib/cookie.js'; import CourseWizard from './lib/course_wizard.js'; import { createURLHelper } from './lib/url_helper.ts'; import CSS from './lib/css.js'; import Dates from './lib/dates.js'; +import DateTime from './lib/datetime.js'; import Dialog from './lib/dialog.js'; import DragAndDropUpload from './lib/drag_and_drop_upload.js'; import enrollment from './lib/enrollment.js'; @@ -31,6 +31,7 @@ import FilesDashboard from './lib/files_dashboard.js'; import Folders from './lib/folders.js'; import Forms from './lib/forms.js'; import Forum from './lib/forum.js'; +import Fullcalendar from './lib/fullcalendar.js'; import Fullscreen from './lib/fullscreen.js'; import GlobalSearch from './lib/global_search.js'; import HeaderMagic from './lib/header_magic.js'; @@ -101,11 +102,11 @@ window.STUDIP = _.assign(window.STUDIP || {}, { Browse, Cache, Calendar, - CalendarDialog, Cookie, CourseWizard, CSS, Dates, + DateTime, Dialog, DragAndDropUpload, enrollment, @@ -116,6 +117,7 @@ window.STUDIP = _.assign(window.STUDIP || {}, { Folders, Forms, Forum, + Fullcalendar, Fullscreen, Gettext, GlobalSearch, diff --git a/resources/assets/javascripts/lib/calendar_dialog.js b/resources/assets/javascripts/lib/calendar_dialog.js deleted file mode 100644 index e42a149..0000000 --- a/resources/assets/javascripts/lib/calendar_dialog.js +++ /dev/null @@ -1,64 +0,0 @@ -import Dialog from './dialog.js'; - -const CalendarDialog = { - closeMps: function(form) { - var added_users = []; - jQuery('#calendar-manage_access_selectbox option:selected').each(function() { - added_users[added_users.length] = jQuery(this).attr('value'); - }); - jQuery.ajax({ - url: STUDIP.ABSOLUTE_URI_STUDIP + 'dispatch.php/calendar/single/add_users/', - data: { - added_users: added_users - }, - type: 'post' - }); - jQuery(form) - .closest('.ui-dialog-content') - .dialog('close'); - Dialog.fromURL(jQuery('#calendar-open-manageaccess').attr('href')); - return false; - }, - - removeUser: function(element) { - var url = jQuery(element).attr('href'); - jQuery(element).removeAttr('href'); - jQuery.ajax({ - url: url, - type: 'get', - success: function() { - var head_tr = jQuery(element) - .closest('tr') - .prev('.calendar-user-head'); - jQuery(element) - .closest('tr') - .remove(); - if (head_tr.nextUntil('.calendar-user-head').length === 0) { - head_tr.remove(); - } - } - }); - return false; - }, - - addException: function() { - var exc_date = jQuery('#exc-date').val(); - var exists = jQuery('#exc-dates input').is("input[value='" + exc_date + "']"); - if (!exists) { - var compiled = _.template( - '<li><label>' + - '<input type="checkbox" name="del_exc_dates[]" value="<%- excdate %>" style="display: none">' + - '<span><%- excdate %><img src="' + - STUDIP.ASSETS_URL + - 'images/icons/blue/trash.svg' + - '"></span></label>' + - '<input type="hidden" name="exc_dates[]" value="<%- excdate %>">' + - '</li>' - ); - jQuery('#exc-dates').append(compiled({ excdate: exc_date, link: '' })); - } - return false; - } -}; - -export default CalendarDialog; diff --git a/resources/assets/javascripts/lib/dates.js b/resources/assets/javascripts/lib/dates.js index 3be67c0..ccb67a8 100644 --- a/resources/assets/javascripts/lib/dates.js +++ b/resources/assets/javascripts/lib/dates.js @@ -4,6 +4,7 @@ const Dates = { termin_id = $('#new_topic') .closest('[data-termin-id]') .data().terminId; + let course_id = jQuery('#new_topic').closest('[data-course-id]').data().courseId; if (!topic_name) { $('#new_topic').focus(); @@ -12,7 +13,8 @@ const Dates = { $.post(STUDIP.URLHelper.getURL('dispatch.php/course/dates/add_topic'), { title: topic_name, - termin_id: termin_id + termin_id: termin_id, + cid: course_id }).done(function(response) { if (response.li !== undefined) { $('#new_topic') diff --git a/resources/assets/javascripts/lib/datetime.js b/resources/assets/javascripts/lib/datetime.js new file mode 100644 index 0000000..d58fac8 --- /dev/null +++ b/resources/assets/javascripts/lib/datetime.js @@ -0,0 +1,61 @@ +import { $gettext, $gettextInterpolate } from "./gettext.ts"; + + +const DateTime = { + /** + * A helper method for padding strings with leading zeros. + * @param what The date to pad. + * @param length The length of the string to output. + * @returns {string} A padded version of $what. + */ + pad(what, length = 2) { + return `00000000${what}`.substr(-length); + }, + + /** + * Returns an ISO representation of the specified Date object. + * in the format YYYY-MM-DD. + * + * @param date The Date object to format as ISO date. + * @returns {string} The ISO date string of the Date object. + */ + getISODate(date) { + return date.getFullYear() + '-' + this.pad(date.getMonth() + 1) + '-' + date.getDate(); + }, + + /** + * Returns a formatted version of the specified Date object + * in the Stud.IP date formatting. + * + * @param date The Date object to be formatted. + * @param relative_value Whether to return a relative time value (true) + * or an absolute one (false). Defaults to false. + * @param date_only Whether to return the date only (true) or date and time (false). + * Defaults to false. Only regarded when $relative_value is false. + * @returns {*|string} The date, formatted according to the Stud.IP format for dates. + */ + getStudipDate(date, relative_value = false, date_only = false) { + if (relative_value) { + let now = Date.now(); + if (now - date < 1 * 60 * 1000) { + return $gettext('Jetzt'); + } + if (now - date < 2 * 60 * 60 * 1000) { + return $gettextInterpolate( + $gettext('Vor %{ minutes } Minuten'), + {minutes: Math.floor((now - date) / (1000 * 60))} + ); + } + return this.pad(date.getHours()) + ':' + this.pad(date.getMinutes()); + } + + if (date_only) { + return this.pad(date.getDate()) + '.' + this.pad(date.getMonth() + 1) + '.' + date.getFullYear(); + } + + return this.pad(date.getDate()) + '.' + this.pad(date.getMonth() + 1) + '.' + date.getFullYear() + ' ' + this.pad(date.getHours()) + ':' + this.pad(date.getMinutes()); + } +}; + + +export default DateTime; diff --git a/resources/assets/javascripts/lib/fullcalendar.js b/resources/assets/javascripts/lib/fullcalendar.js index ef89150..b5bd78d 100644 --- a/resources/assets/javascripts/lib/fullcalendar.js +++ b/resources/assets/javascripts/lib/fullcalendar.js @@ -162,6 +162,16 @@ class Fullcalendar end: this.toRFC3339String(info.event.end) } }).fail(info.revert); + } else if (info.event.extendedProps.studip_api_urls.resize_dialog) { + STUDIP.Dialog.fromURL( + info.event.extendedProps.studip_api_urls.resize_dialog, + { + data: { + begin: this.toRFC3339String(info.event.start), + end: this.toRFC3339String(info.event.end) + } + } + ); } } @@ -242,40 +252,80 @@ class Fullcalendar var drop_resource_id = info.newResource ? info.newResource.id : info.event.extendedProps.studip_range_id; - if (info.event.extendedProps.studip_api_urls.move) { + if (info.event.extendedProps.studip_api_urls.move || info.event.extendedProps.studip_api_urls.move_dialog) { + let move_dialog = info.event.extendedProps.studip_api_urls.move_dialog; if (info.event.allDay) { - $.post({ - async: false, - url: info.event.extendedProps.studip_api_urls.move, - data: { - resource_id: drop_resource_id, - begin: this.toRFC3339String(info.event.start.setHours(0,0,0)), - end: this.toRFC3339String(info.event.start.setHours(23,59,59)) - } - }).fail(info.revert); + if (move_dialog) { + STUDIP.Dialog.fromURL( + move_dialog, + { + data: { + resource_id: drop_resource_id, + begin: this.toRFC3339String(info.event.start.setHours(0, 0, 0)), + end: this.toRFC3339String(info.event.start.setHours(23, 59, 59)) + } + } + ); + } else { + jQuery.post({ + async: false, + url: info.event.extendedProps.studip_api_urls.move, + data: { + resource_id: drop_resource_id, + begin: this.toRFC3339String(info.event.start.setHours(0, 0, 0)), + end: this.toRFC3339String(info.event.start.setHours(23, 59, 59)) + } + }).fail(info.revert); + } } else if (info.event.end === null) { - var real_end = new Date(); + let real_end = new Date(); real_end.setTime(info.event.start.getTime()); real_end.setHours(info.event.start.getHours()+2); - $.post({ - async: false, - url: info.event.extendedProps.studip_api_urls.move, - data: { - resource_id: drop_resource_id, - begin: this.toRFC3339String(info.event.start), - end: this.toRFC3339String(real_end) - } - }).fail(info.revert); + if (move_dialog) { + STUDIP.Dialog.fromURL( + move_dialog, + { + data: { + resource_id: drop_resource_id, + begin: this.toRFC3339String(info.event.start), + end: this.toRFC3339String(real_end) + } + } + ); + } else { + jQuery.post({ + async: false, + url: info.event.extendedProps.studip_api_urls.move, + data: { + resource_id: drop_resource_id, + begin: this.toRFC3339String(info.event.start), + end: this.toRFC3339String(real_end) + } + }).fail(info.revert); + } } else { - $.post({ - async: false, - url: info.event.extendedProps.studip_api_urls.move, - data: { - resource_id: drop_resource_id, - begin: this.toRFC3339String(info.event.start), - end: this.toRFC3339String(info.event.end) - } - }).fail(info.revert); + if (move_dialog) { + STUDIP.Dialog.fromURL( + move_dialog, + { + data: { + resource_id: drop_resource_id, + begin: this.toRFC3339String(info.event.start), + end: this.toRFC3339String(info.event.end) + } + } + ); + } else { + jQuery.post({ + async: false, + url: info.event.extendedProps.studip_api_urls.move, + data: { + resource_id: drop_resource_id, + begin: this.toRFC3339String(info.event.start), + end: this.toRFC3339String(info.event.end) + } + }).fail(info.revert); + } } } } @@ -370,6 +420,12 @@ class Fullcalendar studip_functions: [], resourceAreaWidth: '20%', select (selectionInfo) { + let calendar_config = JSON.parse(selectionInfo.view.context.calendar.el.dataset.config); + let dialog_size = 'auto'; + if (calendar_config.dialog_size !== undefined) { + dialog_size = calendar_config.dialog_size; + } + if (!selectionInfo.view.viewSpec.options.editable || !selectionInfo.view.viewSpec.options.studip_urls) { //The calendar isn't editable. return; @@ -380,15 +436,19 @@ class Fullcalendar data: { begin: selectionInfo.start.getTime()/1000, end: selectionInfo.end.getTime()/1000, - ressource_id: selectionInfo.resource.id - } + ressource_id: selectionInfo.resource.id, + all_day: selectionInfo.allDay ? '1' : '0' + }, + size: dialog_size }); } else { STUDIP.Dialog.fromURL(selectionInfo.view.viewSpec.options.studip_urls.add, { data: { begin: selectionInfo.start.getTime()/1000, - end: selectionInfo.end.getTime()/1000 - } + end: selectionInfo.end.getTime()/1000, + all_day: selectionInfo.allDay ? '1' : '0' + }, + size: dialog_size }); } } @@ -421,15 +481,33 @@ class Fullcalendar if (extended_props.studip_view_urls === undefined) { return; } + let calendar_config = JSON.parse(eventClickInfo.view.context.calendar.el.dataset.config); + let dialog_size = 'auto'; + if (calendar_config.dialog_size !== undefined) { + //Use the configured default dialog size for the fullcalendar instance: + dialog_size = calendar_config.dialog_size; + } + if (extended_props.dialog_size !== undefined) { + //Use the dialog size of the event: + dialog_size = extended_props.dialog_size; + } if (!event.startEditable && extended_props.studip_view_urls.show) { STUDIP.Dialog.fromURL( - STUDIP.URLHelper.getURL(extended_props.studip_view_urls.show) - ); - } else if (event.startEditable && extended_props.studip_view_urls.edit) { - STUDIP.Dialog.fromURL( - STUDIP.URLHelper.getURL(extended_props.studip_view_urls.edit), - {'size': 'big'} + STUDIP.URLHelper.getURL(extended_props.studip_view_urls.show), + {size: dialog_size} ); + } else if (event.startEditable) { + if (extended_props.studip_view_urls.edit) { + STUDIP.Dialog.fromURL( + STUDIP.URLHelper.getURL(extended_props.studip_view_urls.edit), + {size: dialog_size} + ); + } else if (extended_props.studip_view_urls.show) { + STUDIP.Dialog.fromURL( + STUDIP.URLHelper.getURL(extended_props.studip_view_urls.show), + {size: dialog_size} + ); + } } return false; }, @@ -612,6 +690,77 @@ class Fullcalendar return this.init(node, config); } + + static submitDatePicker() { + let picked_date = jQuery('#booking-plan-jmpdate').val(); + let booking_plan_datepicker = true; + if (!picked_date) { + //Not a booking plan date selector. + picked_date = jQuery('#date_select').val(); + booking_plan_datepicker = false; + } + let iso_date_string = ''; + if (picked_date) { + if (picked_date.includes('.')) { + let [day, month, year] = picked_date.split('.'); + iso_date_string = year.padStart(4, '20') + '-' + month.padStart(2, '0') + '-' + day.padStart(2, '0'); + } else if (picked_date.includes('/')) { + let [day, month, year] = picked_date.split('/'); + iso_date_string = year.padStart(4, '20') + '-' + month.padStart(2, '0') + '-' + day.padStart(2, '0'); + } else if (picked_date.includes('-')) { + iso_date_string = picked_date; + } + } + if (iso_date_string) { + jQuery('[data-fullcalendar="1"],[data-resources-fullcalendar="1"]').each(function () { + this.calendar.gotoDate(iso_date_string); + }); + if (booking_plan_datepicker) { + Fullcalendar.updateDateURL(); + } + } + } + + static updateDateURL() { + let changedMoment; + jQuery('[data-fullcalendar="1"],[data-resources-fullcalendar="1"]').each(function () { + changedMoment = this.calendar.getDate(); + }); + if (changedMoment) { + let changed_date = STUDIP.Fullcalendar.toRFC3339String(changedMoment).split('T')[0]; + //Get the timestamp: + let timestamp = changedMoment.getTime() / 1000; + + jQuery('a.resource-bookings-actions').each(function () { + const url = new URL(this.href); + url.searchParams.set('timestamp', timestamp) + url.searchParams.set('defaultDate', changed_date) + this.href = url.toString(); + }); + + // Now change the URL of the window. + const url = new URL(window.location.href); + url.searchParams.set('defaultDate', changed_date); + + // Update url in history + history.pushState({}, null, url.toString()); + + // Adjust links accordingly + url.searchParams.delete('allday'); + jQuery('.booking-plan-std_view').attr('href', url.toString()); + + url.searchParams.set('allday', 1); + jQuery('.booking-plan-allday_view').attr('href', url.toString()); + + // Update sidebar value + let element = jQuery('#booking-plan-jmpdate,#date_select').first(); + element.val(changedMoment.toLocaleDateString('de-DE')); + if (element.is('#booking-plan-jmpdate')) { + //Store the date in the sessionStorage: + sessionStorage.setItem('booking_plan_date', changed_date); + } + } + } } export default Fullcalendar; |
