Refactors event drag-drop and cloning logic

Centralizes drag event listener setup in `EventRendererManager` for better separation of concerns.

Introduces factory and cloning methods in `SwpEventElement` to simplify event cloning and data extraction from DOM elements during drag operations.

Enhances `DragDropManager` to pass the actual dragged element for conversion and accurately detect the drop target (day column or header).

Updates `EventRenderer` to expose drag-handling methods publicly, allowing the `EventRendererManager` to delegate event-specific drag operations based on drop target.
This commit is contained in:
Janus C. H. Knudsen 2025-09-20 09:40:56 +02:00
parent 0b7499521e
commit b4f5b29da3
6 changed files with 357 additions and 304 deletions

View file

@ -71,25 +71,18 @@ export class EventRenderingService {
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();
}
});
// Handle all drag events and delegate to appropriate renderer
this.setupDragEventListeners();
// 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;
const { draggedElement, mousePosition, column } = (event as CustomEvent).detail;
console.log('🔄 EventRendererManager: Received drag:convert-to-time_event', {
draggedEventId,
draggedElement: draggedElement?.dataset.eventId,
mousePosition,
column
});
this.handleConvertToTimeEvent(draggedEventId, mousePosition, column);
this.handleConvertToTimeEvent(draggedElement, mousePosition, column);
});
}
@ -153,18 +146,94 @@ export class EventRenderingService {
}
/**
* Setup all drag event listeners - moved from EventRenderer for better separation of concerns
*/
private setupDragEventListeners(): void {
// Handle drag start
this.eventBus.on('drag:start', (event: Event) => {
const { eventId, mouseOffset, column } = (event as CustomEvent).detail;
// Find element dynamically
const originalElement = document.querySelector(`swp-event[data-event-id="${eventId}"]`) as HTMLElement;
if (originalElement && this.strategy.handleDragStart) {
this.strategy.handleDragStart(originalElement, eventId, mouseOffset, column);
}
});
// Handle drag move
this.eventBus.on('drag:move', (event: Event) => {
const { eventId, snappedY, column, mouseOffset } = (event as CustomEvent).detail;
if (this.strategy.handleDragMove) {
this.strategy.handleDragMove(eventId, snappedY, column, mouseOffset);
}
});
// Handle drag auto-scroll
this.eventBus.on('drag:auto-scroll', (event: Event) => {
const { eventId, snappedY } = (event as CustomEvent).detail;
if (this.strategy.handleDragAutoScroll) {
this.strategy.handleDragAutoScroll(eventId, snappedY);
}
});
// Handle drag end events and delegate to appropriate renderer
this.eventBus.on('drag:end', (event: Event) => {
const { eventId, finalColumn, finalY, target } = (event as CustomEvent).detail;
// Only handle day column drops for EventRenderer
if (target === 'swp-day-column') {
// Find both original element and dragged clone
const originalElement = document.querySelector(`swp-day-column swp-event[data-event-id="${eventId}"]`) as HTMLElement;
const draggedClone = document.querySelector(`swp-day-column swp-event[data-event-id="clone-${eventId}"]`) as HTMLElement;
if (originalElement && draggedClone && this.strategy.handleDragEnd) {
this.strategy.handleDragEnd(eventId, originalElement, draggedClone, finalColumn, finalY);
}
}
// Clean up any remaining day event clones
const dayEventClone = document.querySelector(`swp-event[data-event-id="clone-${eventId}"]`);
if (dayEventClone) {
dayEventClone.remove();
}
});
// Handle click (when drag threshold not reached)
this.eventBus.on('event:click', (event: Event) => {
const { eventId } = (event as CustomEvent).detail;
// Find element dynamically
const originalElement = document.querySelector(`swp-event[data-event-id="${eventId}"]`) as HTMLElement;
if (originalElement && this.strategy.handleEventClick) {
this.strategy.handleEventClick(eventId, originalElement);
}
});
// Handle column change
this.eventBus.on('drag:column-change', (event: Event) => {
const { eventId, newColumn } = (event as CustomEvent).detail;
if (this.strategy.handleColumnChange) {
this.strategy.handleColumnChange(eventId, newColumn);
}
});
// Handle navigation period change
this.eventBus.on(CoreEvents.NAVIGATION_COMPLETED, () => {
// Delegate to strategy if it handles navigation
if (this.strategy.handleNavigationCompleted) {
this.strategy.handleNavigationCompleted();
}
});
}
/**
* 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;
}
private handleConvertToTimeEvent(draggedElement: HTMLElement, mousePosition: any, column: string): void {
// Use the provided draggedElement directly
const allDayClone = draggedElement;
const draggedEventId = draggedElement?.dataset.eventId?.replace('clone-', '') || '';
// Use SwpEventElement factory to create day event from all-day event
const dayEventElement = SwpEventElement.fromAllDayElement(allDayClone as HTMLElement);
const dayElement = dayEventElement.getElement();