From 71dd7f9e383b3c2a02766259e591ae01430086c6 Mon Sep 17 00:00:00 2001 From: Ivymaster Date: Thu, 10 Sep 2026 14:16:12 +0200 Subject: [PATCH] BUG: Some random issue --- public/css/Cis4/CoreCalendarEvents.css | 6 ++- public/js/components/Calendar/Mode/Range.js | 6 ++- public/js/directives/Calendar/Click.js | 41 +++++++++++++++++---- public/js/directives/draggable.js | 15 +++++++- public/js/directives/drop.js | 28 ++++++++++++-- public/js/helpers/DragAndDrop.js | 30 ++++++++++++--- 6 files changed, 103 insertions(+), 23 deletions(-) diff --git a/public/css/Cis4/CoreCalendarEvents.css b/public/css/Cis4/CoreCalendarEvents.css index c2420cdf7..d2d067b43 100644 --- a/public/css/Cis4/CoreCalendarEvents.css +++ b/public/css/Cis4/CoreCalendarEvents.css @@ -1,7 +1,9 @@ /* All */ .weekPageContainer, -.dayPageContainer { +.dayPageContainer, +.rangePageContainer { height: 100%; + width: 100%; } /* Feiertage */ @@ -117,4 +119,4 @@ rgba(0, 0, 0, 0.3) 16px, rgba(0, 0, 0, 0.3) 32px ); -} \ No newline at end of file +} diff --git a/public/js/components/Calendar/Mode/Range.js b/public/js/components/Calendar/Mode/Range.js index 0a4df902f..29693aa0d 100644 --- a/public/js/components/Calendar/Mode/Range.js +++ b/public/js/components/Calendar/Mode/Range.js @@ -44,8 +44,10 @@ export default { ); }, range() { - let first = this.$props.currentDate; - let last = first.plus({ days: this.rangeLength }); + const first = this.$props.currentDate.startOf("day"); + const last = first + .plus({ days: Math.max(Number(this.rangeLength) - 1, 0) }) + .endOf("day"); return luxon.Interval.fromDateTimes(first, last); }, diff --git a/public/js/directives/Calendar/Click.js b/public/js/directives/Calendar/Click.js index e5de31f1a..e8ace013a 100644 --- a/public/js/directives/Calendar/Click.js +++ b/public/js/directives/Calendar/Click.js @@ -1,11 +1,27 @@ const clickListeners = []; +const containerListeners = new WeakMap(); + +function removeClickListener(el) { + const index = clickListeners.findIndex(data => data.el == el); + if (index < 0) + return; + + el.removeEventListener('click', clickListeners[index].listener); + clickListeners.splice(index, 1); +} + +function removeContainerListener(el) { + const listener = containerListeners.get(el); + if (!listener) + return; + + el.removeEventListener('cal-click', listener); + containerListeners.delete(el); +} function saveAddClickListener(el, source, value) { - const index = clickListeners.findIndex(data => data.el == el); - if (index >= 0) { - el.removeEventListener('click', clickListeners[index].listener); - clickListeners.splice(index, 1); - } + removeClickListener(el); + const listener = evt => { evt.preventDefault(); evt.stopPropagation(); @@ -23,7 +39,8 @@ function saveAddClickListener(el, source, value) { export default { mounted(el, binding, vnode) { if (binding.arg == 'container') { - el.addEventListener('cal-click', evt => { + removeContainerListener(el); + const listener = evt => { const customEvent = new Event('click:' + evt.detail.source, { cancelable: true }); @@ -36,7 +53,9 @@ export default { }); evt.target.dispatchEvent(finalEvent); } - }); + }; + containerListeners.set(el, listener); + el.addEventListener('cal-click', listener); } else { saveAddClickListener(el, binding.arg, binding.value); } @@ -45,5 +64,11 @@ export default { if (binding.arg != 'container') { saveAddClickListener(el, binding.arg, binding.value); } + }, + beforeUnmount(el, binding) { + if (binding.arg == 'container') + removeContainerListener(el); + else + removeClickListener(el); } -} \ No newline at end of file +} diff --git a/public/js/directives/draggable.js b/public/js/directives/draggable.js index 9bd8bc244..2ff8dfc81 100644 --- a/public/js/directives/draggable.js +++ b/public/js/directives/draggable.js @@ -21,6 +21,11 @@ const EFFECTS = [ export default { mounted(el, binding) { + // A DOM node can be reused while Vue replaces directive bindings. Tear + // down a stale binding before installing the new one. + if (typeof el.fhcDraggableCleanup === 'function') + el.fhcDraggableCleanup(); + updateValue(el, binding.value); updateEffectAllowed(el, binding.arg); @@ -33,6 +38,7 @@ export default { const bcc = new BroadcastChannel('fhc-dnd'); let blocked = false; + let cleanedUp = false; function onStart(evt) { const value = el.dataset.fhcDraggableValue; @@ -77,8 +83,14 @@ export default { el.addEventListener('dragend', onEnd, true); el.fhcDraggableCleanup = () => { + if (cleanedUp) + return; + cleanedUp = true; + el.removeEventListener('dragstart', onStart, binding.modifiers.capture); el.removeEventListener('dragend', onEnd, true); + bcc.onmessage = null; + bcc.close?.(); if (el.dataset.fhcDraggableValue) { delete el.dataset.fhcDraggableValue; } @@ -96,7 +108,8 @@ export default { } }, beforeUnmount(el) { - el.fhcDraggableCleanup(); + if (typeof el.fhcDraggableCleanup === 'function') + el.fhcDraggableCleanup(); delete el.fhcDraggableCleanup; } } diff --git a/public/js/directives/drop.js b/public/js/directives/drop.js index 7c1672ead..6080b44be 100644 --- a/public/js/directives/drop.js +++ b/public/js/directives/drop.js @@ -16,6 +16,11 @@ const EFFECTS = [ export default { mounted(el, binding) { + // A DOM node can be reused while Vue replaces directive bindings. Tear + // down a stale binding before installing the new one. + if (typeof el.fhcDropCleanup === 'function') + el.fhcDropCleanup(); + if (!binding.arg) { binding.arg = 'none'; } else if (typeof binding.arg === 'object' && !Array.isArray(binding.arg)) { @@ -51,6 +56,11 @@ export default { const bcc = new BroadcastChannel('fhc-dnd'); let allowed = false; + let cleanedUp = false; + const release = () => { + if (!cleanedUp) + bcc.postMessage('release'); + }; function onEnter(evt) { allowed = eventHasTypes(evt, allowedTypes, strict); @@ -61,7 +71,7 @@ export default { } function onLeave(evt, wasDropped) { if (allowed && !wasDropped) { - bcc.postMessage('release'); + release(); } } function onOver(evt) { @@ -80,11 +90,11 @@ export default { if (res instanceof Promise) { res.then(r => { - bcc.postMessage('release'); + release(); return r; }); } else { - bcc.postMessage('release'); + release(); } } @@ -92,13 +102,23 @@ export default { el.addEventListener('dragover', onOver); el.addEventListener('drop', onDrop); el.fhcDropCleanup = () => { + if (cleanedUp) + return; + if (allowed) + bcc.postMessage('release'); + cleanedUp = true; + allowed = false; + cleanupEnterLeave(); el.removeEventListener('dragover', onOver); el.removeEventListener('drop', onDrop); + bcc.onmessage = null; + bcc.close?.(); }; }, beforeUnmount(el) { - el.fhcDropCleanup(); + if (typeof el.fhcDropCleanup === 'function') + el.fhcDropCleanup(); delete el.fhcDropCleanup; } } diff --git a/public/js/helpers/DragAndDrop.js b/public/js/helpers/DragAndDrop.js index 414e68917..3833b7abc 100644 --- a/public/js/helpers/DragAndDrop.js +++ b/public/js/helpers/DragAndDrop.js @@ -298,8 +298,20 @@ function bindDragEnterLeave(el, onEnter, onLeave) { let skipLeave = false; let skipLeaveParent = true; + let active = false; + let disposed = false; + + function removeGlobalListeners() { + window.removeEventListener('dragenter', globalDragenter, true); + window.removeEventListener('dragleave', globalDragleave, true); + window.removeEventListener('drop', globalDrop, true); + } function init(evt) { + if (disposed || active) + return; + + active = true; skipLeave = false; skipLeaveParent = true; // add global listeners @@ -313,14 +325,18 @@ function bindDragEnterLeave(el, onEnter, onLeave) { } function cleanup(evt, wasDropped) { + if (!active) + return; + + active = false; // remove global listeners - window.removeEventListener('dragenter', globalDragenter, true); - window.removeEventListener('dragleave', globalDragleave, true); - window.removeEventListener('drop', globalDrop, true); + removeGlobalListeners(); // call leave - onLeave(evt, wasDropped); + if (!disposed) + onLeave(evt, wasDropped); // add init - el.addEventListener('dragenter', init); + if (!disposed) + el.addEventListener('dragenter', init); } function globalDragenter(evt) { @@ -352,8 +368,10 @@ function bindDragEnterLeave(el, onEnter, onLeave) { el.addEventListener('dragenter', init); return () => { - // cleanup + disposed = true; + active = false; el.removeEventListener('dragenter', init); + removeGlobalListeners(); } }