Enhances drag and drop functionality

Improves drag and drop event handling, including conversion between all-day and timed events.

Introduces HeaderManager to handle header-related event logic and
centralizes header event handling for better code organization and
separation of concerns.

Optimizes event listeners and throttles events for improved performance.
Removes redundant code and improves the overall drag and drop
experience.
This commit is contained in:
Janus Knudsen 2025-09-10 22:07:40 +02:00
parent d087e333fe
commit 3bd74d6f4e
6 changed files with 418 additions and 170 deletions

View file

@ -22,7 +22,6 @@ export class DragDropManager {
private eventBus: IEventBus;
// Mouse tracking with optimized state
private isMouseDown = false;
private lastMousePosition: Position = { x: 0, y: 0 };
private lastLoggedPosition: Position = { x: 0, y: 0 };
private currentMouseY = 0;
@ -96,7 +95,7 @@ export class DragDropManager {
this.eventBus.on('header:mouseover', (event) => {
const { element, targetDate, headerRenderer } = (event as CustomEvent).detail;
if (this.isMouseDown && this.draggedEventId && targetDate) {
if (this.draggedEventId && targetDate) {
// Emit event to convert to all-day
this.eventBus.emit('drag:convert-to-allday', {
eventId: this.draggedEventId,
@ -106,10 +105,48 @@ export class DragDropManager {
});
}
});
// Listen for column mouseover events (for all-day to timed conversion)
this.eventBus.on('column:mouseover', (event) => {
const { targetColumn, targetY } = (event as CustomEvent).detail;
if ((event as any).buttons === 1 && this.draggedEventId && this.isAllDayEventBeingDragged()) {
// Emit event to convert to timed
this.eventBus.emit('drag:convert-to-timed', {
eventId: this.draggedEventId,
targetColumn,
targetY
});
}
});
// Listen for header mouseleave events (for all-day to timed conversion when leaving header)
this.eventBus.on('header:mouseleave', (event) => {
// Check if we're dragging an all-day event
if ((event as any).buttons === 1 && this.draggedEventId && this.isAllDayEventBeingDragged()) {
// Get current mouse position to determine target column and Y
const currentColumn = this.detectColumn(this.lastMousePosition.x, this.lastMousePosition.y);
if (currentColumn) {
// Calculate Y position relative to the column
const columnElement = this.getCachedColumnElement(currentColumn);
if (columnElement) {
const columnRect = columnElement.getBoundingClientRect();
const targetY = this.lastMousePosition.y - columnRect.top - this.mouseOffset.y;
// Emit event to convert to timed
this.eventBus.emit('drag:convert-to-timed', {
eventId: this.draggedEventId,
targetColumn: currentColumn,
targetY: Math.max(0, targetY)
});
}
}
}
});
}
private handleMouseDown(event: MouseEvent): void {
this.isMouseDown = true;
this.isDragStarted = false;
this.lastMousePosition = { x: event.clientX, y: event.clientY };
this.lastLoggedPosition = { x: event.clientX, y: event.clientY };
@ -160,7 +197,7 @@ export class DragDropManager {
private handleMouseMove(event: MouseEvent): void {
this.currentMouseY = event.clientY;
if (this.isMouseDown && this.draggedEventId) {
if (event.buttons === 1 && this.draggedEventId) {
const currentPosition: Position = { x: event.clientX, y: event.clientY };
// Check if we need to start drag (movement threshold)
@ -230,23 +267,27 @@ export class DragDropManager {
* Optimized mouse up handler with consolidated cleanup
*/
private handleMouseUp(event: MouseEvent): void {
if (!this.isMouseDown) return;
this.isMouseDown = false;
this.stopAutoScroll();
if (this.draggedEventId && this.originalElement) {
// Store variables locally before cleanup
const eventId = this.draggedEventId;
const originalElement = this.originalElement;
const isDragStarted = this.isDragStarted;
// Clean up drag state first
this.cleanupDragState();
// Only emit drag:end if drag was actually started
if (this.isDragStarted) {
if (isDragStarted) {
const finalPosition: Position = { x: event.clientX, y: event.clientY };
// Use consolidated position calculation
const positionData = this.calculateDragPosition(finalPosition);
// Emit drag end event
this.eventBus.emit('drag:end', {
eventId: this.draggedEventId,
originalElement: this.originalElement,
eventId: eventId,
originalElement: originalElement,
finalPosition,
finalColumn: positionData.column,
finalY: positionData.snappedY
@ -254,14 +295,11 @@ export class DragDropManager {
} else {
// This was just a click - emit click event instead
this.eventBus.emit('event:click', {
eventId: this.draggedEventId,
originalElement: this.originalElement,
eventId: eventId,
originalElement: originalElement,
mousePosition: { x: event.clientX, y: event.clientY }
});
}
// Clean up drag state
this.cleanupDragState();
}
}
@ -409,7 +447,7 @@ export class DragDropManager {
if (this.autoScrollAnimationId !== null) return;
const scroll = () => {
if (!this.cachedElements.scrollContainer || !this.isMouseDown) {
if (!this.cachedElements.scrollContainer || !this.draggedEventId) {
this.stopAutoScroll();
return;
}
@ -466,6 +504,14 @@ export class DragDropManager {
this.cachedElements.lastColumnDate = null;
}
/**
* Check if an all-day event is currently being dragged
*/
private isAllDayEventBeingDragged(): boolean {
if (!this.originalElement) return false;
return this.originalElement.tagName === 'SWP-ALLDAY-EVENT';
}
/**
* Clean up all resources and event listeners
*/