From 83e01f9cb7d06a7f19e402275d6274a5b8c720a9 Mon Sep 17 00:00:00 2001 From: "Janus C. H. Knudsen" Date: Mon, 29 Sep 2025 20:50:52 +0200 Subject: [PATCH] Improves all-day event drag and drop Refactors all-day event conversion during drag and drop to use the event payload, improving code clarity and reducing redundancy. Removes unnecessary style settings and fixes column detection logic. Addresses an issue where event removal occurred before successful placement. --- src/elements/SwpEventElement.ts | 1 - src/managers/AllDayManager.ts | 37 +++++++++++++---------------- src/managers/DragDropManager.ts | 2 +- src/renderers/EventRenderer.ts | 5 ++-- src/types/EventTypes.ts | 2 +- src/utils/ColumnDetectionUtils.ts | 2 +- wwwroot/css/calendar-layout-css.css | 29 +++++----------------- 7 files changed, 29 insertions(+), 49 deletions(-) diff --git a/src/elements/SwpEventElement.ts b/src/elements/SwpEventElement.ts index 991ec32..1ea565e 100644 --- a/src/elements/SwpEventElement.ts +++ b/src/elements/SwpEventElement.ts @@ -88,7 +88,6 @@ export class SwpEventElement extends BaseEventElement { */ private applyPositioning(): void { const position = this.calculateEventPosition(); - this.element.style.position = 'absolute'; this.element.style.top = `${position.top + 1}px`; this.element.style.height = `${position.height - 3}px`; this.element.style.left = '2px'; diff --git a/src/managers/AllDayManager.ts b/src/managers/AllDayManager.ts index 2c6cb0c..aea47d9 100644 --- a/src/managers/AllDayManager.ts +++ b/src/managers/AllDayManager.ts @@ -38,18 +38,15 @@ export class AllDayManager { */ private setupEventListeners(): void { eventBus.on('drag:mouseenter-header', (event) => { - const { targetColumn: targetColumnBounds, mousePosition, originalElement, cloneElement } = (event as CustomEvent).detail; + const payload = (event as CustomEvent).detail; console.log('🔄 AllDayManager: Received drag:mouseenter-header', { - targetDate: targetColumnBounds, - originalElementId: originalElement?.dataset?.eventId, - originalElementTag: originalElement?.tagName + targetDate: payload.targetColumn, + originalElementId: payload.originalElement?.dataset?.eventId, + originalElementTag: payload.originalElement?.tagName }); - if (targetColumnBounds && cloneElement) { - this.handleConvertToAllDay(targetColumnBounds, cloneElement); - } - + this.handleConvertToAllDay(payload); this.checkAndAnimateAllDayHeight(); }); @@ -101,7 +98,7 @@ export class AllDayManager { if (draggedElement.target != 'swp-day-header') // we are not inside the swp-day-header, so just ignore. return; - this.handleDragEnd(draggedElement); + this.handleDragEnd(draggedElement); }); // Listen for drag cancellation to recalculate height @@ -318,28 +315,28 @@ export class AllDayManager { * Handle conversion of timed event to all-day event - SIMPLIFIED * During drag: Place in row 1 only, calculate column from targetDate */ - private handleConvertToAllDay(targetColumnBounds: ColumnBounds, cloneElement: HTMLElement): void { + private handleConvertToAllDay(payload: DragMouseEnterHeaderEventPayload): void { console.log('🔄 AllDayManager: Converting to all-day (row 1 only during drag)', { - eventId: cloneElement.dataset.eventId, - targetDate: targetColumnBounds + eventId: payload.cloneElement.dataset.eventId, + targetDate: payload.targetColumn }); // Get all-day container, request creation if needed let allDayContainer = this.getAllDayContainer(); - cloneElement.removeAttribute('style'); - cloneElement.classList.add('all-day-style'); - cloneElement.style.gridRow = '1'; - cloneElement.style.gridColumn = targetColumnBounds.index.toString(); - cloneElement.dataset.allday = 'true'; // Set the all-day attribute for filtering + payload.cloneElement.removeAttribute('style'); + payload.cloneElement.classList.add('all-day-style'); + payload.cloneElement.style.gridRow = '1'; + payload.cloneElement.style.gridColumn = payload.targetColumn.index.toString(); + payload.cloneElement.dataset.allday = 'true'; // Set the all-day attribute for filtering // Add to container - allDayContainer?.appendChild(cloneElement); + allDayContainer?.appendChild(payload.cloneElement); console.log('✅ AllDayManager: Converted to all-day style (simple row 1)', { - eventId: cloneElement.dataset.eventId, - gridColumn: targetColumnBounds, + eventId: payload.cloneElement.dataset.eventId, + gridColumn: payload.targetColumn, gridRow: 1 }); } diff --git a/src/managers/DragDropManager.ts b/src/managers/DragDropManager.ts index f694b75..556933a 100644 --- a/src/managers/DragDropManager.ts +++ b/src/managers/DragDropManager.ts @@ -292,7 +292,7 @@ export class DragDropManager { target: dropTarget }; this.eventBus.emit('drag:end', dragEndPayload); - + this.draggedElement.remove(); // TODO: this should be changed into a subscriber which only after a succesful placement is fired, not just mouseup as this can remove elements that are not placed. } else { diff --git a/src/renderers/EventRenderer.ts b/src/renderers/EventRenderer.ts index a04354c..e337aca 100644 --- a/src/renderers/EventRenderer.ts +++ b/src/renderers/EventRenderer.ts @@ -304,7 +304,8 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { this.removeEventFromExistingGroups(originalElement); // Fade out original - this.fadeOutAndRemove(originalElement); + // TODO: this should be changed into a subscriber which only after a succesful placement is fired, not just mouseup as this can remove elements that are not placed. + this.fadeOutAndRemove(originalElement); // Remove clone prefix and normalize clone to be a regular event const cloneId = draggedClone.dataset.eventId; @@ -450,7 +451,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { */ /** - * Fade out and remove element + * Fade out and remove element */ private fadeOutAndRemove(element: HTMLElement): void { element.style.transition = 'opacity 0.3s ease-out'; diff --git a/src/types/EventTypes.ts b/src/types/EventTypes.ts index fe95845..0ceb180 100644 --- a/src/types/EventTypes.ts +++ b/src/types/EventTypes.ts @@ -80,7 +80,7 @@ export interface DragMouseEnterHeaderEventPayload { targetColumn: ColumnBounds; mousePosition: MousePosition; originalElement: HTMLElement | null; - cloneElement: HTMLElement | null; + cloneElement: HTMLElement; } // Drag mouse leave header event payload diff --git a/src/utils/ColumnDetectionUtils.ts b/src/utils/ColumnDetectionUtils.ts index ec79ad6..a7c488a 100644 --- a/src/utils/ColumnDetectionUtils.ts +++ b/src/utils/ColumnDetectionUtils.ts @@ -27,7 +27,7 @@ export class ColumnDetectionUtils { // Find alle kolonner const columns = document.querySelectorAll('swp-day-column'); - let index = 0; + let index = 1; // Cache hver kolonnes x-grænser columns.forEach(column => { const rect = column.getBoundingClientRect(); diff --git a/wwwroot/css/calendar-layout-css.css b/wwwroot/css/calendar-layout-css.css index 9e32e74..905790e 100644 --- a/wwwroot/css/calendar-layout-css.css +++ b/wwwroot/css/calendar-layout-css.css @@ -274,20 +274,6 @@ swp-day-header[data-today="true"] swp-day-date { margin: 4px auto 0; } - -/* All-day container - initially hidden, animated in when first event is dragged */ -swp-allday-container { - grid-column: 1 / -1; /* Span all columns */ - grid-row: 2; /* Second row of calendar header */ - display: grid; - grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr)); - grid-template-rows: repeat(1, auto); /* Default to 1 row, dynamically updated by JS */ - gap: 2px; - padding: 2px; - align-items: center; - overflow: hidden; -} - /* Ghost columns for mouseenter events */ swp-allday-column { position: relative; @@ -299,8 +285,7 @@ swp-allday-column { } /* All-day events in containers */ -swp-allday-container swp-event, -swp-event.all-day-style { +swp-allday-container swp-event { height: 22px !important; /* Fixed height for consistent stacking */ position: relative !important; width: auto !important; @@ -308,13 +293,11 @@ swp-event.all-day-style { right: auto !important; top: auto !important; padding: 2px 4px; - margin-bottom: 2px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; - background: #ff9800; /* Default orange background */ + background: hsl(208, 100%, 50%); display: flex; - position: relative; z-index: 2; /* Above ghost columns */ align-items: center; justify-content: flex-start; @@ -326,11 +309,11 @@ swp-event.all-day-style { text-overflow: ellipsis; white-space: nowrap; border-left: 3px solid rgba(0, 0, 0, 0.2); -} -swp-allday-container swp-event:last-child, -swp-event.all-day-style:last-child { - margin-bottom: 0; + &.dragging { + background: lab(70.24% -13.38 -46.17); + } + } /* Hide time element for all-day styled events */