From ddfcb68d627656b991c506763e27bf6902fa9b83 Mon Sep 17 00:00:00 2001 From: Ivymaster Date: Mon, 18 May 2026 17:45:08 +0200 Subject: [PATCH] BUG: Fixed issues with pointer event listeners on calendar selector --- .../models/organisation/Studienplan_model.php | 9 +- .../organisation/Studiensemester_model.php | 6 +- public/css/components/classSchedule.css | 23 + .../ClassScheduleCalendarSelector.js | 534 ++++++++++-------- .../ClassSchedule/ClassScheduleOverview.js | 5 +- .../ClassScheduleValidityPeriodForm.js | 2 +- .../ClassScheduleValidityPeriodModal.js | 5 +- public/js/directives/draggable.js | 2 +- public/js/helpers/DragAndDrop.js | 1 - ...031_unterrichtszeiten_der_studiengänge.php | 4 +- 10 files changed, 329 insertions(+), 262 deletions(-) diff --git a/application/models/organisation/Studienplan_model.php b/application/models/organisation/Studienplan_model.php index e7c2d49de..d2d06866c 100644 --- a/application/models/organisation/Studienplan_model.php +++ b/application/models/organisation/Studienplan_model.php @@ -189,9 +189,14 @@ class Studienplan_model extends DB_Model SELECT sps.studienplan_id FROM lehre.tbl_studienplan_semester sps JOIN public.tbl_studiensemester ss ON ss.studiensemester_kurzbz = sps.studiensemester_kurzbz - WHERE (ss.start >= ? AND ss.ende <= ?) OR (ss.start <= ? AND ss.ende >= ?) + WHERE ( + (ss.start >= ? AND ss.ende <= ?) OR + (ss.start <= ? AND ss.ende >= ?) OR + (ss.start <= ? AND ss.ende >= ? AND ss.ende <= ?) OR + (ss.start >= ? AND ss.start <= ? AND ss.ende >= ?) + ) )"; - return $this->execReadOnlyQuery($query, array($organizationalUnitShortCode, $startDate, $endDate, $startDate, $endDate)); + return $this->execReadOnlyQuery($query, array($organizationalUnitShortCode, $startDate, $endDate, $startDate, $endDate, $startDate, $startDate, $endDate, $startDate, $endDate, $endDate)); } } diff --git a/application/models/organisation/Studiensemester_model.php b/application/models/organisation/Studiensemester_model.php index db65a920f..b9f736e6b 100644 --- a/application/models/organisation/Studiensemester_model.php +++ b/application/models/organisation/Studiensemester_model.php @@ -362,9 +362,11 @@ class Studiensemester_model extends DB_Model JOIN lehre.tbl_studienplan_semester sp ON sp.studiensemester_kurzbz = s.studiensemester_kurzbz WHERE sp.studienplan_id IN ? AND ( (s.start >= ? AND s.ende <= ?) OR - (s.start <= ? AND s.ende >= ?) + (s.start <= ? AND s.ende >= ?) OR + (s.start <= ? AND s.ende >= ? AND s.ende <= ?) OR + (s.start >= ? AND s.start <= ? AND s.ende >= ?) )"; - return $this->execQuery($query, array($studyPlanIds, $studyPlanIds, $fromDate, $toDate, $fromDate, $toDate)); + return $this->execQuery($query, array($studyPlanIds, $studyPlanIds, $fromDate, $toDate, $fromDate, $toDate, $fromDate, $fromDate, $toDate, $fromDate, $toDate, $toDate)); } } diff --git a/public/css/components/classSchedule.css b/public/css/components/classSchedule.css index 759ab3e78..065313727 100644 --- a/public/css/components/classSchedule.css +++ b/public/css/components/classSchedule.css @@ -54,4 +54,27 @@ div[role="row"] { .v-enter-from, .v-leave-to { opacity: 0; +} + +.scrollable { + overflow: auto; + + /* Firefox */ + scrollbar-width: thin; + scrollbar-color: #888 transparent; +} + +/* Chrome / Edge / Safari */ +.scrollable::-webkit-scrollbar { + width: 6px; + height: 6px; +} + +.scrollable::-webkit-scrollbar-thumb { + background: #888; + border-radius: 999px; +} + +.scrollable::-webkit-scrollbar-track { + background: transparent; } \ No newline at end of file diff --git a/public/js/components/ClassSchedule/ClassScheduleCalendarSelector.js b/public/js/components/ClassSchedule/ClassScheduleCalendarSelector.js index 4cee2f2e7..7ab62d758 100644 --- a/public/js/components/ClassSchedule/ClassScheduleCalendarSelector.js +++ b/public/js/components/ClassSchedule/ClassScheduleCalendarSelector.js @@ -87,9 +87,7 @@ export default { await this.createOverlay(); this.resetPartBodiesBackgroundColor(); - - this.currentFirstSelectedElementNumber = null; - this.currentLastSelectedElementNumber = null; + this.resetCurrentSelectedElementsNumbers(); }); this.overlays = this.overlays.map((existingOverlay, index) => { @@ -121,6 +119,7 @@ export default { }, data() { return { + componentID: Math.random().toString(36).substring(2, 15), daysInWeek: [ this.$p.t("ui", "monday"), this.$p.t("ui", "tuesday"), @@ -139,6 +138,11 @@ export default { currentFirstSelectedElementNumber: null, currentLastSelectedElementNumber: null, selected: [], + currentlyActiveOverlayDropzoneItemDataNumber: null, + onOverlaySelectionPositionOffset: { + x: null, + y: null, + }, isTimeElementResizingInProgress: false, currentUpperResize: { id: null, @@ -159,9 +163,8 @@ export default { computed: { selectedDragObject() { return this.selected.map((item) => ({ - name: "test", type: "calendar_selector_overlay", - id: 2, + id: item.id, })); }, currentlySelectedTimeSlotSpan() { @@ -209,9 +212,7 @@ export default { } let closestXPartBody = - this.getXClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( - event.clientX, - ); + this.getXClosestPartBodyWithGridLineAdditionToMouseEvent(event.clientX); if (!closestXPartBody) return; let closestXPartBodyNumber = this.getElementDataNumber(closestXPartBody); @@ -226,7 +227,7 @@ export default { } let closestPartBody = - this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( + this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeekday( event.clientY, weekday, ); @@ -239,13 +240,12 @@ export default { handleMouseMove(event) { if (this.$props.isPreviewMode) return; if (!this.isTimeElementCreationInProgress) return; - let weekday = this.getWeekdayByElementDataNumber( this.currentFirstSelectedElementNumber, ); let closestPartBody = - this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( + this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeekday( event.clientY, weekday, ); @@ -276,7 +276,6 @@ export default { if (!isLeftMouseButton) return; if (!this.isTimeElementCreationInProgress) { - this.resetPointerEventsForDisplayedOverlays(); this.isTimeElementCreationInProgress = false; return; } @@ -292,7 +291,7 @@ export default { ); let closestPartBody = - this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( + this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeekday( event.clientY, weekday, ); @@ -319,10 +318,7 @@ export default { await this.createOverlay(); this.resetPartBodiesBackgroundColor(); - this.resetPointerEventsForDisplayedOverlays(); - - this.currentFirstSelectedElementNumber = null; - this.currentLastSelectedElementNumber = null; + this.resetCurrentSelectedElementsNumbers(); }, handleLeave(event) { if (this.$props.isPreviewMode) return; @@ -358,85 +354,46 @@ export default { let isLeftMouseButton = event.buttons === 1; if (!isLeftMouseButton) return; - this.getOverlayElementByOverlayId(overlayId).classList.remove( - "fhc-pointer-events-all", - ); - this.getOverlayElementByOverlayId(overlayId).classList.add( - "fhc-pointer-events-none", - ); + let overlay = this.overlays.find((overlay) => overlay.id === overlayId); + if (!overlay) return; + + let overlayElement = this.getOverlayElementByOverlayId(overlayId); + if (!overlayElement) return; + this.selected = [ { type: "calendar_selector_overlay", id: overlayId, }, ]; + + let startingElement = this.getElementByDataNumber( + overlay.startingTimeSlotElementNumber, + ); + if (!startingElement) return; + + let overlayElementRect = overlayElement.getBoundingClientRect(); + const calibrationOffset = 20; + this.onOverlaySelectionPositionOffset.x = + event.clientX - overlayElementRect.left - calibrationOffset; + this.onOverlaySelectionPositionOffset.y = + event.clientY - overlayElementRect.top - calibrationOffset; }, handleMouseUpOnOverlay(overlayId) { if (this.$props.isPreviewMode) return; - this.getOverlayElementByOverlayId(overlayId).classList.remove( - "fhc-pointer-events-none", - ); - this.getOverlayElementByOverlayId(overlayId).classList.add( - "fhc-pointer-events-all", - ); + let overlayElement = this.getOverlayElementByOverlayId(overlayId); + if (!overlayElement) return; + this.selected = []; }, handleOverlayDrop(event) { this.hideOverlayClassTimeTypePopover(); + this.resetCurrentSelectedElementsNumbers(); + this.currentlyActiveOverlayDropzoneItemDataNumber = null; + if (this.$props.isPreviewMode) return; - let dropzoneItem = event.target; - if (!dropzoneItem) return; - - if (!dropzoneItem.getAttribute("data-time")) { - let dropzoneOverlay = this.overlays.find( - (overlay) => overlay.id === dropzoneItem.id, - ); - if (!dropzoneOverlay) { - return; - } - - if (dropzoneOverlay.id !== this.selected[0].id) { - this.$fhcAlert.alertError( - this.$p.t("ui", "classTimeSlotOverlapErrorMessage"), - ); - return; - } - - let startElementNumber = dropzoneOverlay.startingTimeSlotElementNumber; - let startElement = this.getElementByDataNumber(startElementNumber); - - const mouseY = event.clientY; - - const dropzoneItemRect = dropzoneItem.getBoundingClientRect(); - const deltaY = mouseY - dropzoneItemRect.top; - - const startElementRect = startElement.getBoundingClientRect(); - const startElementTop = startElementRect.top; - - const newTop = startElementTop + deltaY; - - const partBodies = this.getPartBodiesElementByWeekday( - dropzoneOverlay.weekday, - ); - - let closestPartBody = null; - partBodies.forEach((partBody) => { - const rect = partBody.getBoundingClientRect(); - if (newTop >= rect.top && newTop <= rect.bottom) { - closestPartBody = partBody; - } - }); - if (!closestPartBody) return; - - dropzoneItem = closestPartBody; - } - - let newStartTimeSlot = this.getTimeSlotItemByDataNumber( - this.getElementDataNumber(dropzoneItem), - ); - const draggedItemId = this.selected.length > 0 ? this.selected[0].id : null; if (!draggedItemId) return; @@ -449,6 +406,116 @@ export default { ); if (!overlay) return; + let mouseX = event.clientX; + let mouseY = event.clientY; + + this.resetPartBodiesBackgroundColor(); + this.isTimeElementCreationInProgress = false; + + mouseX = mouseX - this.onOverlaySelectionPositionOffset.x; + mouseY = mouseY - this.onOverlaySelectionPositionOffset.y; + + let closestXPartBody = + this.getXClosestPartBodyWithGridLineAdditionToMouseEvent(mouseX); + if (!closestXPartBody) { + console.error("No closest X part body found"); + return; + } + let closestXPartBodyNumber = this.getElementDataNumber(closestXPartBody); + + let firstWeekday = this.getWeekdayByElementDataNumber( + closestXPartBodyNumber, + ); + if (!firstWeekday) { + this.$fhcAlert.alertError( + this.$p.t("ui", "classTimeSlotSelectionErrorMessage"), + ); + this.isTimeElementCreationInProgress = false; + return; + } + + let dropzoneItem = + this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeekday( + mouseY, + firstWeekday, + ); + if (!dropzoneItem) return; + + let weekday = this.getWeekdayByElementDataNumber( + this.getElementDataNumber(dropzoneItem), + ); + if (!weekday) { + return; + } + + let newStartTimeSlotItemNumber = this.getElementDataNumber(dropzoneItem); + let newStartTimeSlot = this.getTimeSlotItemByDataNumber( + newStartTimeSlotItemNumber, + ); + + let newEndingTimeSlotItemNumber = + newStartTimeSlotItemNumber + + overlay.endingTimeSlotElementNumber - + overlay.startingTimeSlotElementNumber; + + let maxTimeSlotItemNumber = weekday * this.timeSlotsInDay.length - 1; + if (newEndingTimeSlotItemNumber > maxTimeSlotItemNumber) { + newEndingTimeSlotItemNumber = maxTimeSlotItemNumber; + } + + let overlappedOverlay = this.overlays.find((overlay) => { + if (overlay.id === this.selected[0].id) return false; + if (overlay.weekday !== firstWeekday) return false; + + let isEnvelopingOtherOverlay = + newStartTimeSlotItemNumber <= overlay.startingTimeSlotElementNumber && + overlay.endingTimeSlotElementNumber <= newEndingTimeSlotItemNumber; + let isInsideOtherOverlay = + overlay.startingTimeSlotElementNumber <= newStartTimeSlotItemNumber && + newEndingTimeSlotItemNumber <= overlay.endingTimeSlotElementNumber; + let isIntersectingWithOtherOverlayFromTop = + newStartTimeSlotItemNumber <= overlay.startingTimeSlotElementNumber && + overlay.startingTimeSlotElementNumber <= + newEndingTimeSlotItemNumber && + newEndingTimeSlotItemNumber <= overlay.endingTimeSlotElementNumber; + let isIntersectingWithOtherOverlayFromBottom = + overlay.startingTimeSlotElementNumber <= newStartTimeSlotItemNumber && + newStartTimeSlotItemNumber <= overlay.endingTimeSlotElementNumber && + overlay.endingTimeSlotElementNumber <= newEndingTimeSlotItemNumber; + + return ( + isEnvelopingOtherOverlay || + isInsideOtherOverlay || + isIntersectingWithOtherOverlayFromTop || + isIntersectingWithOtherOverlayFromBottom + ); + }); + if (overlappedOverlay) { + this.$fhcAlert.alertError( + this.$p.t("ui", "classTimeSlotOverlapErrorMessage"), + ); + + let overlayElement = this.getOverlayElementByOverlayId(overlay.id); + if (!overlayElement) return; + + let originalStartingElement = this.getElementByDataNumber( + overlay.startingTimeSlotElementNumber, + ); + if (!originalStartingElement) return; + + let originalEndingElement = this.getElementByDataNumber( + overlay.endingTimeSlotElementNumber, + ); + if (!originalEndingElement) return; + + const startingRect = originalStartingElement.getBoundingClientRect(); + const endingRect = originalEndingElement.getBoundingClientRect(); + + overlayElement.style.top = startingRect.offsetTop + "px"; + + return; + } + let gridLineNumber; try { gridLineNumber = this.getLineNumberFromSelectedElementNumber( @@ -471,31 +538,24 @@ export default { gridLine.appendChild(overlayElement); draggedItem.style.top = dropzoneItem.offsetTop + "px"; - let draggedItemRectBottom = draggedItem.getBoundingClientRect().bottom; - let weekday = gridLineNumber + 1; - - let closestPartBody = - this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( - draggedItemRectBottom, - weekday, - ); - if (!closestPartBody) return; - - const closestPartBodyNumber = this.getElementDataNumber(closestPartBody); - - const rect = closestPartBody.getBoundingClientRect(); - const deltaY = rect.bottom - draggedItemRectBottom; + let newEndingTimeSlotElement = this.getElementByDataNumber( + newEndingTimeSlotItemNumber, + ); + if (!newEndingTimeSlotElement) return; draggedItem.style.height = - parseInt(draggedItem.style.height) + deltaY + "px"; + newEndingTimeSlotElement.offsetTop + + newEndingTimeSlotElement.getBoundingClientRect().height - + dropzoneItem.offsetTop + + "px"; this.overlays = this.overlays.map((overlay) => { if (overlay.id === draggedItemId) { const timeSlot = this.getTimeSlotItemByDataNumber( - closestPartBodyNumber, + newEndingTimeSlotItemNumber, ); - overlay.endingTimeSlotElementNumber = closestPartBodyNumber; + overlay.endingTimeSlotElementNumber = newEndingTimeSlotItemNumber; overlay.endingTimeSlot = timeSlot; overlay.weekday = gridLineNumber + 1; @@ -513,73 +573,6 @@ export default { } return overlay; }); - - let firstSkippedOverElement = this.overlays.find((innerOverlay) => { - if (innerOverlay.id === overlay.id) return false; - - if ( - overlay.startingTimeSlotElementNumber <= - innerOverlay.startingTimeSlotElementNumber && - overlay.endingTimeSlotElementNumber >= - innerOverlay.startingTimeSlotElementNumber - ) { - return true; - } - return false; - }); - - if (firstSkippedOverElement) { - this.$fhcAlert.alertError( - this.$p.t("ui", "classTimeSlotOverlapErrorMessage"), - ); - let elementBeforeFirstSkippedOverElement = this.getElementByDataNumber( - firstSkippedOverElement.startingTimeSlotElementNumber - 1, - ); - if (!elementBeforeFirstSkippedOverElement) return; - - let elementBeforeFirstSkippedOverElementNumber = - this.getElementDataNumber(elementBeforeFirstSkippedOverElement); - - const rect = - elementBeforeFirstSkippedOverElement.getBoundingClientRect(); - const overlayElementRect = overlayElement.getBoundingClientRect(); - const deltaY = rect.bottom - overlayElementRect.bottom; - - overlayElement.style.height = - parseInt(overlayElement.style.height) + deltaY + "px"; - - this.overlays = this.overlays.map((innerOverlay) => { - if (innerOverlay.id === overlay.id) { - innerOverlay.endingTimeSlotElementNumber = - elementBeforeFirstSkippedOverElementNumber; - innerOverlay.endingTimeSlot = this.getTimeSlotItemByDataNumber( - elementBeforeFirstSkippedOverElementNumber, - ); - } - return innerOverlay; - }); - - this.oldMousePosition.x = null; - this.oldMousePosition.y = null; - - this.overlays = this.overlays.map((overlay) => { - if (overlay.id === draggedItemId) { - const timeSlot = this.getTimeSlotItemByDataNumber( - elementBeforeFirstSkippedOverElementNumber, - ); - overlay.endingTimeSlotElementNumber = - elementBeforeFirstSkippedOverElementNumber; - overlay.endingTimeSlot = timeSlot; - - overlay.weekday = gridLineNumber + 1; - return overlay; - } - return overlay; - }); - } - - draggedItem.classList.remove("fhc-pointer-events-none"); - draggedItem.classList.add("fhc-pointer-events-all"); }, handleMouseDownOnUpperResize(event, resizeId, overlayId) { if (this.$props.isPreviewMode) return; @@ -625,7 +618,6 @@ export default { if (this.$props.isPreviewMode) return; if (!this.isTimeElementResizingInProgress) { - this.removeGridLinePointerEvents(); return; } @@ -724,8 +716,6 @@ export default { return; } - this.addGridLinePointerEvents(); - if (!this.oldMousePosition.x || !this.oldMousePosition.y) { this.oldMousePosition.x = event.clientX; this.oldMousePosition.y = event.clientY; @@ -777,7 +767,6 @@ export default { if (this.$props.isPreviewMode) return; if (!this.isTimeElementResizingInProgress) { - this.removeGridLinePointerEvents(); return; } @@ -785,7 +774,6 @@ export default { if (!isLeftMouseButton) return; this.isTimeElementResizingInProgress = false; - this.removeGridLinePointerEvents(); let isUpperResizeMoving = this.currentUpperResize.id !== null; @@ -819,7 +807,7 @@ export default { } let closestPartBody = - this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( + this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeekday( event.clientY, editedOverlay.weekday, ); @@ -982,19 +970,17 @@ export default { await this.createOverlay(); this.isTimeElementCreationInProgress = false; - this.resetPartBodiesBackgroundColor(); - this.currentFirstSelectedElementNumber = null; - this.currentLastSelectedElementNumber = null; + this.resetPartBodiesBackgroundColor(); + this.resetCurrentSelectedElementsNumbers(); }, handleMouseLeaveOnCalendar(event) { if (this.$props.isPreviewMode) return; if (this.isTimeElementCreationInProgress) { this.isTimeElementCreationInProgress = false; - this.currentFirstSelectedElementNumber = null; - this.currentLastSelectedElementNumber = null; + this.resetCurrentSelectedElementsNumbers(); this.resetPartBodiesBackgroundColor(); } @@ -1003,9 +989,6 @@ export default { this.currentLowerResize.overlayId, ); - this.isTimeElementResizingInProgress = false; - this.removeGridLinePointerEvents(); - this.isTimeElementResizingInProgress = false; this.oldMousePosition.x = null; @@ -1043,8 +1026,6 @@ export default { return overlay; }); - this.addGridLinePointerEvents(); - this.getOverlayElementByOverlayId( this.currentLowerResize.overlayId, ).setAttribute("draggable", "true"); @@ -1056,8 +1037,89 @@ export default { return; } + }, + onDragOver(event) { + const calendarContainerZone = document.getElementById( + "calendarContainer" + this.componentID, + ); + const rect = calendarContainerZone.getBoundingClientRect(); - this.resetPointerEventsForDisplayedOverlays(); + const inside = + event.clientX >= rect.left && + event.clientX <= rect.right && + event.clientY >= rect.top && + event.clientY <= rect.bottom; + + if (!inside) { + this.resetPartBodiesBackgroundColor(); + this.currentlyActiveOverlayDropzoneItemDataNumber = null; + + return; + } + + let mouseX = event.clientX - this.onOverlaySelectionPositionOffset.x; + let mouseY = event.clientY - this.onOverlaySelectionPositionOffset.y; + + let closestXPartBody = + this.getXClosestPartBodyWithGridLineAdditionToMouseEvent(mouseX); + if (!closestXPartBody) { + return; + } + + let closestPartBody = + this.getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeekday( + mouseY, + this.getWeekdayByElementDataNumber( + this.getElementDataNumber(closestXPartBody), + ), + ); + if (!closestPartBody) { + return; + } + + let dropzoneElementDataNumber = + this.getElementDataNumber(closestPartBody); + if (!dropzoneElementDataNumber) { + return; + } + + let weekday = this.getWeekdayByElementDataNumber( + dropzoneElementDataNumber, + ); + if (!weekday) { + return; + } + + let overlayItem = this.overlays.find( + (overlay) => overlay.id === this.selected[0].id, + ); + if (!overlayItem) { + return; + } + + if ( + this.currentlyActiveOverlayDropzoneItemDataNumber !== + dropzoneElementDataNumber + ) { + this.resetPartBodiesBackgroundColor(); + } + + let overlayItemSlotSpan = + overlayItem.endingTimeSlotElementNumber - + overlayItem.startingTimeSlotElementNumber; + this.currentlyActiveOverlayDropzoneItemDataNumber = + dropzoneElementDataNumber; + + this.getPartBodiesElementByWeekday(weekday).forEach((child) => { + let currentItemDataNumber = this.getElementDataNumber(child); + if ( + currentItemDataNumber >= dropzoneElementDataNumber && + currentItemDataNumber <= + dropzoneElementDataNumber + overlayItemSlotSpan + ) { + child.style.backgroundColor = this.selectedTimeSlotLabelColor; + } + }); }, async createOverlay() { this.hideOverlayClassTimeTypePopover(); @@ -1160,12 +1222,7 @@ export default { }); if (hasCollidingOverlays) { - this.$fhcAlert.alertError( - this.$p.t("ui", "classTimeSlotOverlapErrorMessage"), - ); - - this.currentFirstSelectedElementNumber = null; - this.currentLastSelectedElementNumber = null; + this.resetCurrentSelectedElementsNumbers(); return; } @@ -1386,16 +1443,6 @@ export default { getResizeElementById(resizeId) { return this.$refs.calendarSelectorContainer.querySelector(`#${resizeId}`); }, - removeGridLinePointerEvents() { - this.$refs.calendarSelectorContainer - .querySelector(".fhc-calendar-base-grid-line") - .classList.add("fhc-pointer-events-none"); - }, - addGridLinePointerEvents() { - this.$refs.calendarSelectorContainer - .querySelector(".fhc-calendar-base-grid-line") - .classList.remove("fhc-pointer-events-none"); - }, resetPartBodiesBackgroundColor() { this.$refs.calendarSelectorContainer ?.querySelectorAll("div[class*='part-body']") @@ -1403,14 +1450,6 @@ export default { child.style.backgroundColor = this.defaultTimeSlotLabelColor; }); }, - resetPointerEventsForDisplayedOverlays() { - this.$refs.calendarSelectorContainer - .querySelectorAll("div[id^='overlay-']") - .forEach((element) => { - element.classList.remove("fhc-pointer-events-none"); - element.classList.add("fhc-pointer-events-all"); - }); - }, getPartBodiesElement() { return this.$refs.calendarSelectorContainer.querySelectorAll( `div[class*='part-body']`, @@ -1421,7 +1460,7 @@ export default { `div[data-weekday='${weekday}']`, ); }, - getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( + getYClosestPartBodyWithGridLineAdditionToMouseEventPerWeekday( targetYLocation, weekday, ) { @@ -1452,9 +1491,7 @@ export default { return closestPartBody; }, - getXClosestPartBodyWithGridLineAdditionToMouseEventPerWeek( - targetXLocation, - ) { + getXClosestPartBodyWithGridLineAdditionToMouseEvent(targetXLocation) { let closestXPartBody = null; let closestXDistance = Infinity; @@ -1463,24 +1500,14 @@ export default { ); partBodies.forEach((partBody) => { const rect = partBody.getBoundingClientRect(); - const distanceX = Math.abs( - targetXLocation - rect.left - rect.width / 2, - ); + const distanceX = Math.abs(targetXLocation - rect.left); + const isLocationInPartBody = + targetXLocation >= rect.left - 5 && targetXLocation <= rect.right + 5; - let gridLineHeight = this.$refs.calendarSelectorContainer.querySelector( - ".fhc-calendar-base-grid-line", - ).style.height; - let seeIfAdjacentElementIsGridLine = - partBody.nextElementSibling.classList.contains( - "fhc-calendar-base-grid-line", - ); - if ( - distanceX < closestXDistance || - (distanceX + gridLineHeight === closestXDistance && - seeIfAdjacentElementIsGridLine) - ) { + if (isLocationInPartBody) { closestXDistance = distanceX; closestXPartBody = partBody; + return; } }); @@ -1495,6 +1522,10 @@ export default { element.remove(); }); }, + resetCurrentSelectedElementsNumbers() { + this.currentFirstSelectedElementNumber = null; + this.currentLastSelectedElementNumber = null; + }, resetCurrentUpperResize() { this.currentUpperResize = { id: null, @@ -1507,6 +1538,9 @@ export default { overlayId: null, }; }, + logError(error) { + console.error(error); + }, }, unmounted() { this.hideOverlayClassTimeTypePopover(); @@ -1515,10 +1549,12 @@ export default {
@@ -1529,7 +1565,7 @@ export default { display: grid; width: 100%; height: 100%; - overflow: auto; + overflow: visible; grid-template-rows: auto auto 1fr; grid-template-columns: auto repeat(7, 1fr); " @@ -1561,7 +1597,7 @@ export default {
unit.aktiv) .map((unit) => { return { - label: `${unit.bezeichnung} (${unit.organisationseinheittyp_kurzbz})`, + label: `[${unit.organisationseinheittyp_kurzbz}] ${unit.bezeichnung}`, value: unit.oe_kurzbz, }; - }); + }) + .sort((a, b) => a.label.localeCompare(b.label)); }, dropdownParsedSemesters() { return this.allSemesters.map((semester) => { diff --git a/public/js/components/ClassSchedule/ClassScheduleValidityPeriodForm.js b/public/js/components/ClassSchedule/ClassScheduleValidityPeriodForm.js index 0dfc2dfd1..1b4ca0239 100644 --- a/public/js/components/ClassSchedule/ClassScheduleValidityPeriodForm.js +++ b/public/js/components/ClassSchedule/ClassScheduleValidityPeriodForm.js @@ -154,7 +154,7 @@ export default {
unit.aktiv) .map((unit) => { return { - label: `${unit.bezeichnung} (${unit.organisationseinheittyp_kurzbz})`, + label: `[${unit.organisationseinheittyp_kurzbz}] ${unit.bezeichnung}`, value: unit.oe_kurzbz, }; - }); + }) + .sort((a, b) => a.label.localeCompare(b.label)); }, }, methods: { diff --git a/public/js/directives/draggable.js b/public/js/directives/draggable.js index 697bcbb26..39efeed13 100644 --- a/public/js/directives/draggable.js +++ b/public/js/directives/draggable.js @@ -30,7 +30,7 @@ export default { function onStart(evt) { const value = el.dataset.fhcDraggableValue; if (value) { - let disableImage = binding.modifiers?.noimage === true; + let disableImage = binding.modifiers?.noImage === true; setTransferData(evt, JSON.parse(value), !disableImage); if (el.dataset.fhcEffectAllowed) evt.dataTransfer.effectAllowed = el.dataset.fhcEffectAllowed; diff --git a/public/js/helpers/DragAndDrop.js b/public/js/helpers/DragAndDrop.js index 23155d551..088ec1bc1 100644 --- a/public/js/helpers/DragAndDrop.js +++ b/public/js/helpers/DragAndDrop.js @@ -33,7 +33,6 @@ const TYPE_DEFINITION = { }, calendar_selector_overlay: { id: "calendar_selector_overlay_id", - dragIcon: "fa-solid fa-calendar-plus" } // TODO: IMPLEMENT OTHER TYPES }; diff --git a/system/dbupdate_3.4/76031_unterrichtszeiten_der_studiengänge.php b/system/dbupdate_3.4/76031_unterrichtszeiten_der_studiengänge.php index 4382fd858..7e1c5281a 100644 --- a/system/dbupdate_3.4/76031_unterrichtszeiten_der_studiengänge.php +++ b/system/dbupdate_3.4/76031_unterrichtszeiten_der_studiengänge.php @@ -103,7 +103,7 @@ if(!$result = @$db->db_query("SELECT 1 FROM lehre.tbl_unterrichtszeiten_typ LIMI "bezeichnung_mehrsprachig" TEXT[] NOT NULL, "aktiv" BOOLEAN DEFAULT true, "hintergrundfarbe" VARCHAR(7), - "ist_standard" BOOLEAN DEFAULT false, + "is_default" BOOLEAN DEFAULT false, "insertamum" TIMESTAMP WITH TIME ZONE DEFAULT now(), "insertvon" VARCHAR(32), "updateamum" TIMESTAMP WITH TIME ZONE DEFAULT now(), @@ -156,7 +156,7 @@ if(!$result = @$db->db_query("SELECT 1 FROM lehre.tbl_unterrichtszeiten_typ LIMI $qry = " - INSERT INTO lehre.tbl_unterrichtszeiten_typ (unterrichtszeitentyp_kurzbz, bezeichnung_mehrsprachig, aktiv, hintergrundfarbe, ist_standard) VALUES + INSERT INTO lehre.tbl_unterrichtszeiten_typ (unterrichtszeitentyp_kurzbz, bezeichnung_mehrsprachig, aktiv, hintergrundfarbe, is_default) VALUES ('unterrichtszeiten', ARRAY['Unterrichtszeiten', 'Teaching Times'], 't', '#FFFFFF', 'f'), ('vorlesungen', ARRAY['Vorlesung', 'Lecture'], 't', '#FF8A8A', 't'), ('backuptage', ARRAY['Übung', 'Exercise'], 't', '#8AFF8A', 'f'),