Enables all-day event conversion on column hover

Allows users to convert all-day events to timed events by dragging them over a day column.

This implementation adds logic to the DragDropManager to detect when an all-day event is dragged over a column.
It then emits a new event, 'drag:mouseenter-column', carrying the event data and target column information.

The event rendering service handles this event.
This commit is contained in:
Janus C. H. Knudsen 2025-10-10 16:41:48 +02:00
parent 7a79297854
commit 78ca23c07a
5 changed files with 69 additions and 125 deletions

View file

@ -14,6 +14,7 @@ import {
DragEndEventPayload,
DragMouseEnterHeaderEventPayload,
DragMouseLeaveHeaderEventPayload,
DragMouseEnterColumnEventPayload,
DragColumnChangeEventPayload
} from '../types/EventTypes';
import { MousePosition } from '../types/DragDropTypes';
@ -116,6 +117,8 @@ export class DragDropManager {
const target = e.target as HTMLElement;
if (target.closest('swp-calendar-header')) {
this.handleHeaderMouseEnter(e as MouseEvent);
} else if (target.closest('swp-day-column')) {
this.handleColumnMouseEnter(e as MouseEvent);
} else if (target.closest('swp-event')) {
// Entered an event - activate hover tracking and set color
const eventElement = target.closest<HTMLElement>('swp-event');
@ -652,6 +655,46 @@ export class DragDropManager {
}
}
/**
* Handle mouse enter on day column - for converting all-day to timed events
*/
private handleColumnMouseEnter(event: MouseEvent): void {
// Only handle if we're dragging an all-day event
if (!this.isDragStarted || !this.draggedClone || !this.draggedClone.hasAttribute('data-allday')) {
return;
}
console.log('🎯 DragDropManager: Mouse entered day column');
const position: MousePosition = { x: event.clientX, y: event.clientY };
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
if (!targetColumn) {
console.warn("No column detected when entering day column");
return;
}
// Calculate snapped Y position
const snappedY = this.calculateSnapPosition(position.y, targetColumn);
// Extract CalendarEvent from the dragged clone
const calendarEvent = SwpEventElement.extractCalendarEventFromElement(this.draggedClone);
const dragMouseEnterPayload: DragMouseEnterColumnEventPayload = {
targetColumn: targetColumn,
mousePosition: position,
snappedY: snappedY,
originalElement: this.draggedElement,
draggedClone: this.draggedClone,
calendarEvent: calendarEvent,
// Delegate pattern - allows EventRenderer to replace the clone
replaceClone: (newClone: HTMLElement) => {
this.draggedClone = newClone;
}
};
this.eventBus.emit('drag:mouseenter-column', dragMouseEnterPayload);
}
/**
* Handle mouse leave from calendar header - simplified using native events
*/

View file

@ -12,7 +12,7 @@ import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
* Separates event handling from rendering concerns
*/
export class HeaderManager {
// Event listeners for drag events
private dragMouseEnterHeaderListener: ((event: Event) => void) | null = null;
private dragMouseLeaveHeaderListener: ((event: Event) => void) | null = null;
@ -20,7 +20,7 @@ export class HeaderManager {
constructor() {
// Bind methods for event listeners
this.setupHeaderDragListeners = this.setupHeaderDragListeners.bind(this);
// Listen for navigation events to update header
this.setupNavigationListener();
}
@ -36,7 +36,7 @@ export class HeaderManager {
* Get cached calendar header element
*/
private getCalendarHeader(): HTMLElement | null {
return document.querySelector('swp-calendar-header');
return document.querySelector('swp-calendar-header');
}
/**
@ -48,42 +48,35 @@ export class HeaderManager {
// Create and store event listeners
this.dragMouseEnterHeaderListener = (event: Event) => {
const { targetColumn: targetDate, mousePosition, originalElement, draggedClone: cloneElement } = (event as CustomEvent<DragMouseEnterHeaderEventPayload>).detail;
console.log('🎯 HeaderManager: Received drag:mouseenter-header', {
targetDate,
originalElement: !!originalElement,
cloneElement: !!cloneElement
});
if (targetDate) {
const calendarType = calendarConfig.getCalendarMode();
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
}
};
this.dragMouseLeaveHeaderListener = (event: Event) => {
const { targetDate, mousePosition, originalElement, draggedClone: cloneElement } = (event as CustomEvent<DragMouseLeaveHeaderEventPayload>).detail;
console.log('🚪 HeaderManager: Received drag:mouseleave-header', {
targetDate,
originalElement: !!originalElement,
cloneElement: !!cloneElement
});
eventBus.emit('header:mouseleave', {
element: this.getCalendarHeader(),
targetDate,
originalElement,
cloneElement
});
};
// Listen for drag events from DragDropManager
eventBus.on('drag:mouseenter-header', this.dragMouseEnterHeaderListener);
eventBus.on('drag:mouseleave-header', this.dragMouseLeaveHeaderListener);
console.log('✅ HeaderManager: Drag event listeners attached');
}
@ -117,13 +110,13 @@ export class HeaderManager {
const calendarHeader = this.getOrCreateCalendarHeader();
if (!calendarHeader) return;
// Clear existing content
// Clear existing content
calendarHeader.innerHTML = '';
// Render new header content
const calendarType = calendarConfig.getCalendarMode();
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
const context: HeaderRenderContext = {
currentWeek: currentDate,
config: calendarConfig,
@ -147,12 +140,12 @@ export class HeaderManager {
*/
private getOrCreateCalendarHeader(): HTMLElement | null {
const calendarHeader = this.getCalendarHeader();
if (!calendarHeader) {
console.warn('HeaderManager: Calendar header not found - should always exist now!');
return null;
}
return calendarHeader;
}
}