Refactors all-day event conversion to timed events

Streamlines the conversion of all-day events to timed events during drag and drop operations. This change improves the event rendering process by ensuring proper handling of element replacement and position updates.

Removes redundant code and simplifies the logic for updating the dragged clone.
This commit is contained in:
Janus C. H. Knudsen 2025-10-11 01:30:41 +02:00
parent 0a3d274164
commit 9b073a15b7
3 changed files with 40 additions and 63 deletions

View file

@ -226,6 +226,7 @@ export class DragDropManager {
// Continue drag if started // Continue drag if started
if (this.isDragStarted && this.draggedElement && this.draggedClone) { if (this.isDragStarted && this.draggedElement && this.draggedClone) {
console.log("Continue drag if started", this.draggedClone);
this.continueDrag(currentPosition); this.continueDrag(currentPosition);
this.detectAndEmitColumnChange(currentPosition); this.detectAndEmitColumnChange(currentPosition);
} }
@ -280,9 +281,10 @@ export class DragDropManager {
* Continue drag movement - update position and auto-scroll * Continue drag movement - update position and auto-scroll
*/ */
private continueDrag(currentPosition: MousePosition): void { private continueDrag(currentPosition: MousePosition): void {
if (!this.draggedElement!.hasAttribute("data-allday")) { if (!this.draggedClone!.hasAttribute("data-allday")) {
// Calculate raw position from mouse (no snapping) // Calculate raw position from mouse (no snapping)
const column = ColumnDetectionUtils.getColumnBounds(currentPosition); const column = ColumnDetectionUtils.getColumnBounds(currentPosition);
console.log("continueDrag");
if (column) { if (column) {
// Calculate raw Y position relative to column (accounting for mouse offset) // Calculate raw Y position relative to column (accounting for mouse offset)
@ -296,11 +298,26 @@ export class DragDropManager {
this.currentY = parseFloat(this.draggedClone!.style.top) || 0; this.currentY = parseFloat(this.draggedClone!.style.top) || 0;
this.animateDrag(); this.animateDrag();
} }
// Emit drag:move event with current draggedClone reference
if (this.draggedClone) {
const dragMovePayload: DragMoveEventPayload = {
draggedElement: this.draggedElement!,
draggedClone: this.draggedClone,
mousePosition: currentPosition,
snappedY: this.currentY,
columnBounds: column,
mouseOffset: this.mouseOffset
};
this.eventBus.emit('drag:move', dragMovePayload);
}
} }
// Check for auto-scroll // Check for auto-scroll
this.checkAutoScroll(currentPosition); this.checkAutoScroll(currentPosition);
} }
else
console.log("hasAttribute(data-allday)");
} }
/** /**
@ -461,6 +478,7 @@ export class DragDropManager {
/** /**
* Smooth drag animation using requestAnimationFrame * Smooth drag animation using requestAnimationFrame
* Only interpolates currentY - events are emitted from continueDrag()
*/ */
private animateDrag(): void { private animateDrag(): void {
if (!this.isDragStarted || !this.draggedClone || !this.targetColumn) { if (!this.isDragStarted || !this.draggedClone || !this.targetColumn) {
@ -475,33 +493,10 @@ export class DragDropManager {
// Update if difference is significant // Update if difference is significant
if (Math.abs(diff) > 0.5) { if (Math.abs(diff) > 0.5) {
this.currentY += step; this.currentY += step;
// Emit drag move event with interpolated position
const dragMovePayload: DragMoveEventPayload = {
draggedElement: this.draggedElement!,
draggedClone: this.draggedClone,
mousePosition: this.lastMousePosition,
snappedY: this.currentY,
columnBounds: this.targetColumn,
mouseOffset: this.mouseOffset
};
this.eventBus.emit('drag:move', dragMovePayload);
this.dragAnimationId = requestAnimationFrame(() => this.animateDrag()); this.dragAnimationId = requestAnimationFrame(() => this.animateDrag());
} else { } else {
// Close enough - snap to target // Close enough - snap to target
this.currentY = this.targetY; this.currentY = this.targetY;
const dragMovePayload: DragMoveEventPayload = {
draggedElement: this.draggedElement!,
draggedClone: this.draggedClone,
mousePosition: this.lastMousePosition,
snappedY: this.currentY,
columnBounds: this.targetColumn,
mouseOffset: this.mouseOffset
};
this.eventBus.emit('drag:move', dragMovePayload);
this.dragAnimationId = null; this.dragAnimationId = null;
} }
} }
@ -649,6 +644,7 @@ export class DragDropManager {
// Delegate pattern - allows AllDayManager to replace the clone // Delegate pattern - allows AllDayManager to replace the clone
replaceClone: (newClone: HTMLElement) => { replaceClone: (newClone: HTMLElement) => {
this.draggedClone = newClone; this.draggedClone = newClone;
this.dragAnimationId === null;
} }
}; };
this.eventBus.emit('drag:mouseenter-header', dragMouseEnterPayload); this.eventBus.emit('drag:mouseenter-header', dragMouseEnterPayload);
@ -690,6 +686,9 @@ export class DragDropManager {
// Delegate pattern - allows EventRenderer to replace the clone // Delegate pattern - allows EventRenderer to replace the clone
replaceClone: (newClone: HTMLElement) => { replaceClone: (newClone: HTMLElement) => {
this.draggedClone = newClone; this.draggedClone = newClone;
this.dragAnimationId === null;
this.stopDragAnimation();
console.log("replacing clone with", newClone)
} }
}; };
this.eventBus.emit('drag:mouseenter-column', dragMouseEnterPayload); this.eventBus.emit('drag:mouseenter-column', dragMouseEnterPayload);

View file

@ -43,7 +43,7 @@ export class DateEventRenderer implements EventRendererStrategy {
this.stackManager = new EventStackManager(); this.stackManager = new EventStackManager();
this.layoutCoordinator = new EventLayoutCoordinator(); this.layoutCoordinator = new EventLayoutCoordinator();
} }
private applyDragStyling(element: HTMLElement): void { private applyDragStyling(element: HTMLElement): void {
element.classList.add('dragging'); element.classList.add('dragging');
element.style.removeProperty("margin-left"); element.style.removeProperty("margin-left");
@ -90,11 +90,10 @@ export class DateEventRenderer implements EventRendererStrategy {
* Handle drag move event * Handle drag move event
*/ */
public handleDragMove(payload: DragMoveEventPayload): void { public handleDragMove(payload: DragMoveEventPayload): void {
if (!this.draggedClone || !payload.columnBounds) return;
// Delegate to SwpEventElement to update position and timestamps // Delegate to SwpEventElement to update position and timestamps
const swpEvent = this.draggedClone as SwpEventElement; const swpEvent = payload.draggedClone as SwpEventElement;
const columnDate = this.dateService.parseISO(payload.columnBounds.date); const columnDate = this.dateService.parseISO(payload.columnBounds!!.date);
swpEvent.updatePosition(columnDate, payload.snappedY); swpEvent.updatePosition(columnDate, payload.snappedY);
} }
@ -133,27 +132,18 @@ export class DateEventRenderer implements EventRendererStrategy {
* Handle conversion of all-day event to timed event * Handle conversion of all-day event to timed event
*/ */
public handleConvertAllDayToTimed(payload: DragMouseEnterColumnEventPayload): void { public handleConvertAllDayToTimed(payload: DragMouseEnterColumnEventPayload): void {
const { calendarEvent, targetColumn, snappedY, replaceClone } = payload;
console.log('🎯 DateEventRenderer: Converting all-day to timed event', { console.log('🎯 DateEventRenderer: Converting all-day to timed event', {
eventId: calendarEvent.id, eventId: payload.calendarEvent.id,
targetColumn: targetColumn.date, targetColumn: payload.targetColumn.date,
snappedY snappedY: payload.snappedY
}); });
// Create timed event element from CalendarEvent let timedClone = SwpEventElement.fromCalendarEvent(payload.calendarEvent);
const timedClone = SwpEventElement.fromCalendarEvent(calendarEvent); let position = this.calculateEventPosition(payload.calendarEvent);
// Calculate proper height from event duration
const position = this.calculateEventPosition(calendarEvent);
// Calculate actual duration in minutes from CalendarEvent (important for all-day conversions)
const durationMinutes = (calendarEvent.end.getTime() - calendarEvent.start.getTime()) / (1000 * 60);
timedClone.dataset.duration = durationMinutes.toString();
timedClone.dataset.originalDuration = durationMinutes.toString();
// Set position at snapped Y // Set position at snapped Y
timedClone.style.top = `${snappedY}px`; //timedClone.style.top = `${snappedY}px`;
// Set complete styling for dragged clone (matching normal event rendering) // Set complete styling for dragged clone (matching normal event rendering)
timedClone.style.height = `${position.height - 3}px`; timedClone.style.height = `${position.height - 3}px`;
@ -166,25 +156,16 @@ export class DateEventRenderer implements EventRendererStrategy {
this.applyDragStyling(timedClone); this.applyDragStyling(timedClone);
// Find the events layer in the target column // Find the events layer in the target column
const eventsLayer = targetColumn.element.querySelector('swp-events-layer'); let eventsLayer = payload.targetColumn.element.querySelector('swp-events-layer');
if (!eventsLayer) {
console.warn('DateEventRenderer: Events layer not found in column');
return;
}
// Append new timed clone to events layer // Add "clone-" prefix to match clone ID pattern
eventsLayer.appendChild(timedClone); timedClone.dataset.eventId = payload.calendarEvent.id;
// Update instance state // Remove old all-day clone and replace with new timed clone
this.draggedClone = timedClone; payload.draggedClone.remove();
payload.replaceClone(timedClone);
eventsLayer!!.appendChild(timedClone);
// Update DragDropManager's reference to the new clone
replaceClone(timedClone);
console.log('✅ DateEventRenderer: Converted all-day to timed event', {
eventId: calendarEvent.id,
position: snappedY
});
} }
/** /**

View file

@ -153,7 +153,7 @@ export class EventRenderingService {
this.eventBus.on('drag:move', (event: Event) => { this.eventBus.on('drag:move', (event: Event) => {
let dragEvent = (event as CustomEvent<DragMoveEventPayload>).detail; let dragEvent = (event as CustomEvent<DragMoveEventPayload>).detail;
if (dragEvent.draggedElement.hasAttribute('data-allday')) { if (dragEvent.draggedClone.hasAttribute('data-allday')) {
return; return;
} }
if (this.strategy.handleDragMove) { if (this.strategy.handleDragMove) {
@ -266,9 +266,6 @@ export class EventRenderingService {
calendarEvent: payload.calendarEvent calendarEvent: payload.calendarEvent
}); });
// Remove the old all-day clone from header
payload.draggedClone.remove();
// Delegate to strategy for conversion // Delegate to strategy for conversion
if (this.strategy.handleConvertAllDayToTimed) { if (this.strategy.handleConvertAllDayToTimed) {
this.strategy.handleConvertAllDayToTimed(payload); this.strategy.handleConvertAllDayToTimed(payload);