diff --git a/application/controllers/Tempus.php b/application/controllers/Tempus.php index 2b72bece5..bdb3c4f25 100644 --- a/application/controllers/Tempus.php +++ b/application/controllers/Tempus.php @@ -19,8 +19,6 @@ class Tempus extends Auth_Controller // Load Config $this->load->config('calendar'); - - $this->load->helper('hlp_header_helper'); } public function index() diff --git a/application/libraries/CollisionChecker.php b/application/libraries/CollisionChecker.php index f3ffb056e..1644ced3a 100644 --- a/application/libraries/CollisionChecker.php +++ b/application/libraries/CollisionChecker.php @@ -58,7 +58,7 @@ class CollisionChecker foreach ($this->_checks as $check) { if (empty($remaining_ids)) break; - log_message('error', 'CollisionChecker: Running check ' . $check->getName() . ' for ' . count($remaining_ids) . ' remaining kalender_ids'); + $batchResult = $check->checkAll($remaining_ids); foreach ($batchResult as $kalender_id => $errors) { diff --git a/public/css/Cis4/CoreCalendarEvents.css b/public/css/Cis4/CoreCalendarEvents.css index bbaad2b49..29163ddc8 100644 --- a/public/css/Cis4/CoreCalendarEvents.css +++ b/public/css/Cis4/CoreCalendarEvents.css @@ -110,20 +110,6 @@ display: none; } -.weekPageContainer .calendar-event-collisions, -.rangePageContainer .calendar-event-collisions -{ - display: grid; - grid-template-columns: auto 1fr; - background: repeating-linear-gradient( - 135deg, - transparent, - transparent 16px, - rgba(0, 0, 0, 0.3) 16px, - rgba(0, 0, 0, 0.3) 32px - ); -} - .tag-row-cell { width: 100%; max-width: 0; diff --git a/public/js/components/Calendar/Base/Grid/Line/Event.js b/public/js/components/Calendar/Base/Grid/Line/Event.js index 910af9966..d63fa6d94 100644 --- a/public/js/components/Calendar/Base/Grid/Line/Event.js +++ b/public/js/components/Calendar/Base/Grid/Line/Event.js @@ -101,7 +101,6 @@ export default { this.$emit('resize-start', { edge, evt, - horizontal: false, el: this.$refs.eventEl, event: this.event, }); @@ -176,7 +175,6 @@ export default { > -
1+k); + return [...Array(this.extrasAfter)].map((i, k) => 1 + k); }, itemsBefore() { - return [...Array(this.extrasBefore)].map((i, k) => k-this.extrasBefore); + return [...Array(this.extrasBefore)].map((i, k) => k - this.extrasBefore); }, styleSlider() { const style = { @@ -40,10 +38,10 @@ export default { top: 0, left: 0, width: '100%', - height: '100%' + height: '100%', }; if (this.running) { - style.left = (-this.target * 100) + '%'; + style.left = -this.target * 100 + '%'; style.transition = 'left ' + this.time + ' ease-in-out'; } return style; @@ -55,7 +53,7 @@ export default { height: '100%', display: 'flex', right: '100%', - width: (this.extrasBefore * 100) + '%' + width: this.extrasBefore * 100 + '%', }; }, styleAfter() { @@ -65,96 +63,104 @@ export default { height: '100%', display: 'flex', left: '100%', - width: (this.extrasAfter * 100) + '%' + width: this.extrasAfter * 100 + '%', }; - } + }, }, methods: { startVisibilityTracking() { - if (!this.onVisibleDatesChanged || typeof IntersectionObserver === 'undefined') + if ( + !this.onVisibleDatesChanged || + typeof IntersectionObserver === 'undefined' + ) return; - this.intersectionObserver = Vue.markRaw(new IntersectionObserver(entries => { - let changed = false; + this.intersectionObserver = Vue.markRaw( + new IntersectionObserver( + (entries) => { + let changed = false; - entries.forEach(entry => { - if (entry.isIntersecting && entry.intersectionRatio > 0) { - if (!this.visibleGrids.has(entry.target)) { - this.visibleGrids.add(entry.target); - changed = true; + entries.forEach((entry) => { + if (entry.isIntersecting && entry.intersectionRatio > 0) { + if (!this.visibleGrids.has(entry.target)) { + this.visibleGrids.add(entry.target); + changed = true; + } + } else if (this.visibleGrids.delete(entry.target)) { + changed = true; + } + }); + + if (changed) this.scheduleVisibleDatesUpdate(); + }, + { + root: this.$el, + threshold: 0, + }, + ), + ); + + this.mutationObserver = Vue.markRaw( + new MutationObserver((mutations) => { + let changed = false; + + mutations.forEach((mutation) => { + if (mutation.type === 'attributes') { + if ( + this.visibleGrids.has(this.getContainingGrid(mutation.target)) + ) + changed = true; + return; } - } else if (this.visibleGrids.delete(entry.target)) { - changed = true; - } - }); - if (changed) - this.scheduleVisibleDatesUpdate(); - }, { - root: this.$el, - threshold: 0 - })); + mutation.addedNodes.forEach((node) => this.observeGrids(node)); + mutation.removedNodes.forEach((node) => { + this.getGrids(node).forEach((grid) => { + this.intersectionObserver.unobserve(grid); + if (this.visibleGrids.delete(grid)) changed = true; + }); + }); - this.mutationObserver = Vue.markRaw(new MutationObserver(mutations => { - let changed = false; - - mutations.forEach(mutation => { - if (mutation.type === 'attributes') { if (this.visibleGrids.has(this.getContainingGrid(mutation.target))) changed = true; - return; - } - - mutation.addedNodes.forEach(node => this.observeGrids(node)); - mutation.removedNodes.forEach(node => { - this.getGrids(node).forEach(grid => { - this.intersectionObserver.unobserve(grid); - if (this.visibleGrids.delete(grid)) - changed = true; - }); }); - if (this.visibleGrids.has(this.getContainingGrid(mutation.target))) - changed = true; - }); - - if (changed) - { - this.scheduleVisibleDatesUpdate(); - } - })); + if (changed) { + this.scheduleVisibleDatesUpdate(); + } + }), + ); this.observeGrids(this.$el); this.mutationObserver.observe(this.$el, { subtree: true, childList: true, attributes: true, - attributeFilter: ['data-visible-start', 'data-visible-end'] + attributeFilter: ['data-visible-start', 'data-visible-end'], }); }, getGrids(node) { - if (!(node instanceof Element)) - return []; + if (!(node instanceof Element)) return []; const grids = node.matches('.fhc-calendar-base-grid') ? [node] : []; - return grids.concat([...node.querySelectorAll('.fhc-calendar-base-grid')]); + return grids.concat([ + ...node.querySelectorAll('.fhc-calendar-base-grid'), + ]); }, observeGrids(node) { - this.getGrids(node).forEach(grid => { + this.getGrids(node).forEach((grid) => { this.intersectionObserver.observe(grid); }); }, getContainingGrid(node) { - if (!(node instanceof Element)) - return null; + if (!(node instanceof Element)) return null; return node.matches('.fhc-calendar-base-grid') ? node : node.closest('.fhc-calendar-base-grid'); }, scheduleVisibleDatesUpdate() { - if (this.visibilityUpdateScheduled) - return; + if (this.visibilityUpdateScheduled) return; this.visibilityUpdateScheduled = true; this.$nextTick(() => { @@ -165,41 +171,35 @@ export default { emitVisibleDates() { const datesByKey = new Map(); - this.visibleGrids.forEach(grid => { + this.visibleGrids.forEach((grid) => { const dates = this.getGridVisibleDates(grid); - if (dates) - datesByKey.set(dates.start + '/' + dates.end, dates); + if (dates) datesByKey.set(dates.start + '/' + dates.end, dates); }); - const dates = [...datesByKey.values()] - .sort((a, b) => a.start.localeCompare(b.start)); - if (!dates.length) - return; + const dates = [...datesByKey.values()].sort((a, b) => + a.start.localeCompare(b.start), + ); + if (!dates.length) return; - const key = dates.map(date => date.start + '/' + date.end).join('|'); + const key = dates.map((date) => date.start + '/' + date.end).join('|'); - if (key === this.lastVisibleDatesKey) - return; + if (key === this.lastVisibleDatesKey) return; this.lastVisibleDatesKey = key; this.onVisibleDatesChanged(dates); }, getGridVisibleDates(grid) { - if (!grid.isConnected) - return null; + if (!grid.isConnected) return null; let start = null; let end = null; - grid.querySelectorAll('.fhc-calendar-base-grid-line').forEach(line => { + grid.querySelectorAll('.fhc-calendar-base-grid-line').forEach((line) => { const lineStart = line.dataset.visibleStart; const lineEnd = line.dataset.visibleEnd; - if (!lineStart || !lineEnd) - return; + if (!lineStart || !lineEnd) return; - if (!start || lineStart.localeCompare(start) < 0) - start = lineStart; - if (!end || lineEnd.localeCompare(end) > 0) - end = lineEnd; + if (!start || lineStart.localeCompare(start) < 0) start = lineStart; + if (!end || lineEnd.localeCompare(end) > 0) end = lineEnd; }); return start && end ? { start, end } : null; @@ -225,16 +225,14 @@ export default { return this.slidePages(num); }, slidePages(dir) { - return new Promise(resolve => { + return new Promise((resolve) => { this.promiseResolve = resolve; this.running = true; const newTarget = this.target + dir; if (newTarget > 0) { - if (this.extrasAfter < newTarget) - this.extrasAfter = newTarget; + if (this.extrasAfter < newTarget) this.extrasAfter = newTarget; } else if (newTarget < 0) { - if (-this.extrasBefore > newTarget) - this.extrasBefore = -newTarget; + if (-this.extrasBefore > newTarget) this.extrasBefore = -newTarget; } this.target = newTarget; }); @@ -248,7 +246,7 @@ export default { this.running = false; this.target = 0; this.extrasAfter = this.extrasBefore = 0; - } + }, }, mounted() { this.startVisibilityTracking(); @@ -256,7 +254,7 @@ export default { beforeUnmount() { this.stopVisibilityTracking(); }, - template: /* html */` + template: /* html */ `
- ` -} + `, +}; diff --git a/public/js/components/Calendar/Base/test.html b/public/js/components/Calendar/Base/test.html deleted file mode 100644 index 6c073e814..000000000 --- a/public/js/components/Calendar/Base/test.html +++ /dev/null @@ -1,103 +0,0 @@ -
-
- -
-
- -
-
-
-
- -
- -
- - - -
-
-
-
\ No newline at end of file diff --git a/public/js/components/Calendar/Mode/Range/View.js b/public/js/components/Calendar/Mode/Range/View.js index fc19194b5..589c8e1bd 100644 --- a/public/js/components/Calendar/Mode/Range/View.js +++ b/public/js/components/Calendar/Mode/Range/View.js @@ -102,7 +102,6 @@ export default { start: luxon.Duration.fromISOTime(tu.start), end: luxon.Duration.fromISOTime(tu.end), }; - scroll; }); } else if (this.hoursPlan) { const start = this.hoursPlan?.start ?? 7; diff --git a/public/js/components/Calendar/Tempus.js b/public/js/components/Calendar/Tempus.js index 9a6231561..3f81c47a9 100644 --- a/public/js/components/Calendar/Tempus.js +++ b/public/js/components/Calendar/Tempus.js @@ -27,11 +27,10 @@ export default { }, provide() { return { - rangeLength: Vue.computed(() => this.currentRangeLength), - rangeViewPresets: Vue.computed(() => this.semesterRangePresets), - rangeViewPreviewLink: Vue.computed(() => this.rangeViewPreviewLink), showRaster: Vue.computed(() => this.showRaster), teachingunits: Vue.computed(() => this.teachingunits), + rangeLength: Vue.computed(() => this.currentRangeLength), + rangeViewPreviewLink: Vue.computed(() => this.rangeViewPreviewLink), rangeViewPresetsConfig: Vue.computed(() => { return { label: this.$p.t('LvPlan/view_specific_semester'), @@ -42,10 +41,6 @@ export default { }, inject: { renderers: { from: 'renderers' }, - currentSemester: { - from: 'currentSemester', - default: null, - }, canToggleGrid: { from: 'canToggleGrid', default: false, @@ -178,7 +173,6 @@ export default { hoursplan: null, showRaster: true, currentRangeLength: getRangeLength(this.range) ?? this.rangeLength, - selectedRangePreset: null, //this.currentSemester, TODO: This is a hack to make the range mode work, but it should be fixed in the future semesterRangePresets: { label: null, presets: [], diff --git a/public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js b/public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js index 2dc81ae90..47dabae56 100644 --- a/public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js +++ b/public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js @@ -1,10 +1,4 @@ export default { - inject: { - mode: { - from: 'mode', - default: null, - }, - }, props: { event: { type: Object, @@ -168,31 +162,13 @@ export default {
{{ start }} {{ end }}
-
- {{ topicString }} -
- - - -
-
+ {{ topicString }} calendar.scrollTop; - const rect = eventEl.getBoundingClientRect(); if (!isInsideScrolledView) { eventEl.scrollIntoView({ behavior: 'smooth', diff --git a/public/js/helpers/Tempus/ResizeGhost.js b/public/js/helpers/Tempus/ResizeGhost.js index e555a3aed..ceb2e3876 100644 --- a/public/js/helpers/Tempus/ResizeGhost.js +++ b/public/js/helpers/Tempus/ResizeGhost.js @@ -59,9 +59,7 @@ export function useResizeGhost() { return { startTop: topInGrid, - startHeight: eventRect.height, - startLeft: leftInGrid, - startWidth: eventRect.width + startHeight: eventRect.height }; } @@ -71,7 +69,7 @@ export function useResizeGhost() { labelEl.textContent = text; } - function updatePosition(top, height, width, left) + function updatePosition(top, height) { if (!ghostEl) return; @@ -79,21 +77,15 @@ export function useResizeGhost() { ghostEl.style.top = `${top}px`; if (height !== null) ghostEl.style.height = `${height}px`; - if (width !== null) - ghostEl.style.width = `${width}px`; - if (left !== null) - ghostEl.style.left = `${left}px`; } function getPosition() { if (!ghostEl) - return { top: 0, height: 0, left: 0, width: 0 }; + return { top: 0, height: 0 }; return { top: parseFloat(ghostEl.style.top), - height: parseFloat(ghostEl.style.height), - left: parseFloat(ghostEl.style.left), - width: parseFloat(ghostEl.style.width) + height: parseFloat(ghostEl.style.height) }; } @@ -107,4 +99,4 @@ export function useResizeGhost() { } return { create, updateLabel, updatePosition, getPosition, remove }; -} +} \ No newline at end of file diff --git a/public/js/helpers/Tempus/ResizeHandler.js b/public/js/helpers/Tempus/ResizeHandler.js index ab627e274..a2896bf00 100644 --- a/public/js/helpers/Tempus/ResizeHandler.js +++ b/public/js/helpers/Tempus/ResizeHandler.js @@ -41,30 +41,20 @@ function getSnapTimes(timeGrid, dayISO, zoneName) function calculateNewTimes(activeResize, ghostPosition) { - const { edge, event, timeGrid, horizontal, startTop, startHeight, startLeft, startWidth } = activeResize; + const { edge, event, timeGrid, startTop, startHeight } = activeResize; const { start, end } = event; const durationMinutes = end.diff(start, 'minutes').minutes; if (!durationMinutes || durationMinutes <= 0) return null; - const startSize = horizontal ? startWidth : startHeight; - if (!Number.isFinite(startSize) || startSize <= 0) - return null; - - const pxPerMinute = startSize / durationMinutes; + const pxPerMinute = startHeight / durationMinutes; let draggedPx = 0; if (edge === 'end') - draggedPx = horizontal - ? ghostPosition.width - startWidth - : ghostPosition.height - startHeight; + draggedPx = ghostPosition.height - startHeight; if (edge === 'start') - draggedPx = horizontal - ? ghostPosition.left - startLeft - : ghostPosition.top - startTop; - if (!Number.isFinite(draggedPx)) - return null; + draggedPx = ghostPosition.top - startTop; const draggedMinutes = snapToGrid(draggedPx / pxPerMinute, edge); @@ -107,12 +97,6 @@ export function useResizeHandler() { return (evt.clientY - gridRect.top) + activeResize.gridEl.scrollTop; } - function getPointerXInGrid(evt) - { - const gridRect = activeResize.gridEl.getBoundingClientRect(); - return (evt.clientX - gridRect.left) + activeResize.gridEl.scrollLeft; - } - function updateGhostLabel() { const result = calculateNewTimes(activeResize, ghost.getPosition()); @@ -127,59 +111,36 @@ export function useResizeHandler() { return; evt.preventDefault(); - const maxEnd = activeResize.horizontal - ? activeResize.gridEl.scrollWidth - : activeResize.gridEl.scrollHeight; - const pointer = activeResize.horizontal - ? getPointerXInGrid(evt) - : getPointerYInGrid(evt); - const draggedPx = pointer - (activeResize.horizontal - ? activeResize.dragStartX - : activeResize.dragStartY); + const maxBottom = activeResize.gridEl.scrollHeight; + const pointerY = getPointerYInGrid(evt); + const draggedPx = pointerY - activeResize.dragStartY; if (activeResize.edge === 'end') { - const minSize = MIN_HEIGHT_PX; - const newSize = Math.max(minSize, (activeResize.horizontal - ? activeResize.startWidth - : activeResize.startHeight) + draggedPx); - const startPosition = activeResize.horizontal - ? activeResize.startLeft - : activeResize.startTop; - const constrainedSize = Math.min(newSize, maxEnd - startPosition); + let newHeight = Math.max(MIN_HEIGHT_PX, activeResize.startHeight + draggedPx); + if (activeResize.startTop + newHeight > maxBottom) + newHeight = maxBottom - activeResize.startTop; - if (activeResize.horizontal) - ghost.updatePosition(null, null, constrainedSize); - else - ghost.updatePosition(null, constrainedSize); + ghost.updatePosition(null, newHeight); } else if (activeResize.edge === 'start') { - const startPosition = activeResize.horizontal - ? activeResize.startLeft - : activeResize.startTop; - const startSize = activeResize.horizontal - ? activeResize.startWidth - : activeResize.startHeight; - let newPosition = startPosition + draggedPx; - let newSize = startSize - draggedPx; + let newTop = activeResize.startTop + draggedPx; + let newHeight = activeResize.startHeight - draggedPx; - if (newPosition < 0) + if (newTop < 0) { - newSize -= (0 - newPosition); - newPosition = 0; + newHeight -= (0 - newTop); + newTop = 0; } - if (newSize < MIN_HEIGHT_PX) + if (newHeight < MIN_HEIGHT_PX) { - newPosition = (startPosition + startSize) - MIN_HEIGHT_PX; - newSize = MIN_HEIGHT_PX; + newTop = (activeResize.startTop + activeResize.startHeight) - MIN_HEIGHT_PX; + newHeight = MIN_HEIGHT_PX; } - if (activeResize.horizontal) - ghost.updatePosition(null, null, newSize, newPosition); - else - ghost.updatePosition(newPosition, newSize); + ghost.updatePosition(newTop, newHeight); } updateGhostLabel(); @@ -197,6 +158,7 @@ export function useResizeHandler() { activeResize.eventEl.style.opacity = activeResize.originalOpacity ?? ''; const result = calculateNewTimes(activeResize, ghost.getPosition()); + ghost.remove(); if (result) @@ -211,13 +173,12 @@ export function useResizeHandler() { } } - activeResize.onFinish?.(); activeResize = null; } - function startResize(edge, evt, { el, gridEl, event, horizontal = false, timeGrid, onEnd, onFinish }) + function startResize(edge, evt, { el, gridEl, event, timeGrid, onEnd }) { - const { startTop, startHeight, startLeft, startWidth } = ghost.create(gridEl, el, edge); + const { startTop, startHeight } = ghost.create(gridEl, el, edge); activeResize = { edge, @@ -225,16 +186,11 @@ export function useResizeHandler() { eventEl: el, gridEl, event, - horizontal, timeGrid, onEnd, - onFinish, dragStartY: (evt.clientY - gridEl.getBoundingClientRect().top) + gridEl.scrollTop, - dragStartX: (evt.clientX - gridEl.getBoundingClientRect().left) + gridEl.scrollLeft, startTop, startHeight, - startLeft, - startWidth, originalOpacity: el.style.opacity, }; @@ -254,9 +210,8 @@ export function useResizeHandler() { window.removeEventListener('pointermove', onPointerMove); window.removeEventListener('pointerup', onPointerUp); ghost.remove(); - activeResize.onFinish?.(); activeResize = null; } return { startResize, cleanup }; -} +} \ No newline at end of file