Enables all-day event drag and drop

Implements comprehensive drag and drop for all-day events, allowing movement within the header and conversion to timed events when dragged into the calendar grid.

Optimizes column detection with a cached bounding box strategy, improving performance and accuracy. Refactors event conversion logic and renames related event bus events for clarity.
This commit is contained in:
Janus C. H. Knudsen 2025-09-19 00:20:30 +02:00
parent f1d04ae12e
commit 0b7499521e
6 changed files with 338 additions and 106 deletions

View file

@ -5,6 +5,7 @@ import { calendarConfig } from '../core/CalendarConfig';
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
import { EventManager } from '../managers/EventManager';
import { EventRendererStrategy } from './EventRenderer';
import { SwpEventElement } from '../elements/SwpEventElement';
/**
* EventRenderingService - Render events i DOM med positionering using Strategy Pattern
@ -69,6 +70,28 @@ export class EventRenderingService {
this.eventBus.on(CoreEvents.VIEW_CHANGED, (event: Event) => {
this.handleViewChanged(event as CustomEvent);
});
// Simple drag:end listener to clean up day event clones
this.eventBus.on('drag:end', (event: Event) => {
const { eventId } = (event as CustomEvent).detail;
const dayEventClone = document.querySelector(`swp-event[data-event-id="clone-${eventId}"]`);
if (dayEventClone) {
dayEventClone.remove();
}
});
// Listen for conversion from all-day event to time event
this.eventBus.on('drag:convert-to-time_event', (event: Event) => {
const { draggedEventId, mousePosition, column } = (event as CustomEvent).detail;
console.log('🔄 EventRendererManager: Received drag:convert-to-time_event', {
draggedEventId,
mousePosition,
column
});
this.handleConvertToTimeEvent(draggedEventId, mousePosition, column);
});
}
@ -128,6 +151,66 @@ export class EventRenderingService {
// New rendering will be triggered by subsequent GRID_RENDERED event
}
/**
* Handle conversion from all-day event to time event
*/
private handleConvertToTimeEvent(draggedEventId: string, mousePosition: any, column: string): void {
// Find all-day event clone
const allDayClone = document.querySelector(`swp-allday-container swp-allday-event[data-event-id="clone-${draggedEventId}"]`);
if (!allDayClone) {
console.warn('EventRendererManager: All-day clone not found - drag may not have started properly', { draggedEventId });
return;
}
// Use SwpEventElement factory to create day event from all-day event
const dayEventElement = SwpEventElement.fromAllDayElement(allDayClone as HTMLElement);
const dayElement = dayEventElement.getElement();
// Remove the all-day clone - it's no longer needed since we're converting to day event
allDayClone.remove();
// Set clone ID
dayElement.dataset.eventId = `clone-${draggedEventId}`;
// Find target column
const columnElement = document.querySelector(`swp-day-column[data-date="${column}"]`);
if (!columnElement) {
console.warn('EventRendererManager: Target column not found', { column });
return;
}
// Find events layer in the column
const eventsLayer = columnElement.querySelector('swp-events-layer');
if (!eventsLayer) {
console.warn('EventRendererManager: Events layer not found in column');
return;
}
// Add to events layer
eventsLayer.appendChild(dayElement);
// Position based on mouse Y coordinate
const columnRect = columnElement.getBoundingClientRect();
const relativeY = Math.max(0, mousePosition.y - columnRect.top);
dayElement.style.top = `${relativeY}px`;
// Set drag styling
dayElement.style.zIndex = '1000';
dayElement.style.cursor = 'grabbing';
dayElement.style.opacity = '';
dayElement.style.transform = '';
console.log('✅ EventRendererManager: Converted all-day event to time event', {
draggedEventId,
column,
mousePosition,
relativeY
});
}
private clearEvents(container?: HTMLElement): void {
this.strategy.clearEvents(container);
}