Refactors drag and drop column detection

Improves drag and drop functionality by refactoring column detection to use column bounds instead of dates.
This change enhances the accuracy and efficiency of determining the target column during drag operations.
It also removes redundant code and simplifies the logic in both the DragDropManager and AllDayManager.
This commit is contained in:
Janus C. H. Knudsen 2025-09-28 13:25:09 +02:00
parent 4141bffca4
commit 6ccc071587
8 changed files with 262 additions and 377 deletions

View file

@ -9,6 +9,8 @@ import { SwpEventElement } from '../elements/SwpEventElement';
import { TimeFormatter } from '../utils/TimeFormatter';
import { PositionUtils } from '../utils/PositionUtils';
import { DragOffset, StackLinkData } from '../types/DragDropTypes';
import { ColumnBounds } from '../utils/ColumnDetectionUtils';
import { DragColumnChangeEventPayload, DragMoveEventPayload, DragStartEventPayload } from '../types/EventTypes';
/**
* Interface for event rendering strategies
@ -16,12 +18,12 @@ import { DragOffset, StackLinkData } from '../types/DragDropTypes';
export interface EventRendererStrategy {
renderEvents(events: CalendarEvent[], container: HTMLElement): void;
clearEvents(container?: HTMLElement): void;
handleDragStart?(payload: import('../types/EventTypes').DragStartEventPayload): void;
handleDragMove?(eventId: string, snappedY: number, column: string, mouseOffset: DragOffset): void;
handleDragStart?(payload: DragStartEventPayload): void;
handleDragMove?(payload: DragMoveEventPayload): void;
handleDragAutoScroll?(eventId: string, snappedY: number): void;
handleDragEnd?(eventId: string, originalElement: HTMLElement, draggedClone: HTMLElement, finalColumn: string, finalY: number): void;
handleDragEnd?(eventId: string, originalElement: HTMLElement, draggedClone: HTMLElement, finalColumn: ColumnBounds, finalY: number): void;
handleEventClick?(eventId: string, originalElement: HTMLElement): void;
handleColumnChange?(eventId: string, newColumn: string): void;
handleColumnChange?(payload: DragColumnChangeEventPayload): void;
handleNavigationCompleted?(): void;
}
@ -160,13 +162,9 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
/**
* Handle drag start event
*/
public handleDragStart(payload: import('../types/EventTypes').DragStartEventPayload): void {
const originalElement = payload.draggedElement;
const eventId = originalElement.dataset.eventId || '';
const mouseOffset = payload.mouseOffset;
const column = payload.column || '';
this.originalEvent = originalElement;
public handleDragStart(payload: DragStartEventPayload): void {
this.originalEvent = payload.draggedElement;;
// Use the clone from the payload instead of creating a new one
this.draggedClone = payload.draggedClone;
@ -176,35 +174,29 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
this.applyDragStyling(this.draggedClone);
// Add to current column's events layer (not directly to column)
const columnElement = document.querySelector(`swp-day-column[data-date="${column}"]`);
if (columnElement) {
const eventsLayer = columnElement.querySelector('swp-events-layer');
if (eventsLayer) {
eventsLayer.appendChild(this.draggedClone);
} else {
// Fallback to column if events layer not found
columnElement.appendChild(this.draggedClone);
}
const eventsLayer = payload.columnBounds?.element.querySelector('swp-events-layer');
if (eventsLayer) {
eventsLayer.appendChild(this.draggedClone);
}
}
// Make original semi-transparent
originalElement.style.opacity = '0.3';
originalElement.style.userSelect = 'none';
this.originalEvent.style.opacity = '0.3';
this.originalEvent.style.userSelect = 'none';
}
/**
* Handle drag move event
*/
public handleDragMove(eventId: string, snappedY: number, column: string, mouseOffset: DragOffset): void {
public handleDragMove(payload: DragMoveEventPayload): void {
if (!this.draggedClone) return;
// Update position
this.draggedClone.style.top = snappedY + 'px';
this.draggedClone.style.top = payload.snappedY + 'px';
// Update timestamp display
this.updateCloneTimestamp(this.draggedClone, snappedY);
this.updateCloneTimestamp(this.draggedClone, payload.snappedY);
}
@ -224,26 +216,20 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
/**
* Handle column change during drag
*/
public handleColumnChange(eventId: string, newColumn: string): void {
public handleColumnChange(dragColumnChangeEvent: DragColumnChangeEventPayload): void {
if (!this.draggedClone) return;
// Move clone to new column's events layer
const newColumnElement = document.querySelector(`swp-day-column[data-date="${newColumn}"]`);
if (newColumnElement) {
const eventsLayer = newColumnElement.querySelector('swp-events-layer');
if (eventsLayer && this.draggedClone.parentElement !== eventsLayer) {
eventsLayer.appendChild(this.draggedClone);
} else if (!eventsLayer && this.draggedClone.parentElement !== newColumnElement) {
// Fallback to column if events layer not found
newColumnElement.appendChild(this.draggedClone);
}
const eventsLayer = dragColumnChangeEvent.newColumn.element.querySelector('swp-events-layer');
if (eventsLayer && this.draggedClone.parentElement !== eventsLayer) {
eventsLayer.appendChild(this.draggedClone);
}
}
/**
* Handle drag end event
*/
public handleDragEnd(eventId: string, originalElement: HTMLElement, draggedClone: HTMLElement, finalColumn: string, finalY: number): void {
public handleDragEnd(eventId: string, originalElement: HTMLElement, draggedClone: HTMLElement, finalColumn: ColumnBounds, finalY: number): void {
if (!draggedClone || !originalElement) {
console.warn('Missing draggedClone or originalElement');
@ -398,11 +384,9 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
/**
* Handle overlap detection and re-rendering after drag-drop
*/
private handleDragDropOverlaps(droppedElement: HTMLElement, targetColumn: string): void {
const targetColumnElement = document.querySelector(`swp-day-column[data-date="${targetColumn}"]`);
if (!targetColumnElement) return;
private handleDragDropOverlaps(droppedElement: HTMLElement, targetColumn: ColumnBounds): void {
const eventsLayer = targetColumnElement.querySelector('swp-events-layer') as HTMLElement;
const eventsLayer = targetColumn.element.querySelector('swp-events-layer') as HTMLElement;
if (!eventsLayer) return;
// Convert dropped element to CalendarEvent with new position
@ -543,16 +527,16 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
renderEvents(events: CalendarEvent[], container: HTMLElement): void {
// Filter out all-day events - they should be handled by AllDayEventRenderer
const timedEvents = events.filter(event => !event.allDay);
console.log('🎯 EventRenderer: Filtering events', {
totalEvents: events.length,
timedEvents: timedEvents.length,
filteredOutAllDay: events.length - timedEvents.length
});
// Find columns in the specific container for regular events
const columns = this.getColumns(container);
@ -561,7 +545,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
const eventsLayer = column.querySelector('swp-events-layer');
if (eventsLayer) {
this.handleEventOverlaps(columnEvents, eventsLayer as HTMLElement);
}
});