Refactors drag header interaction logic
Improves efficiency and reliability of drag-and-drop operations involving calendar headers. Transitions from continuous polling within `handleMouseMove` to using native `mouseenter` and `mouseleave` events with delegation on `swp-calendar-header` elements. This change ensures more precise and performant detection of header interactions during a drag. Also enhances the initial event detection logic to correctly identify `SWP-ALLDAY-EVENT` elements when starting a drag.
This commit is contained in:
parent
420036d939
commit
125cd678a3
1 changed files with 68 additions and 59 deletions
|
|
@ -93,12 +93,28 @@ export class DragDropManager {
|
||||||
|
|
||||||
this.scrollContainer = document.querySelector('swp-scrollable-content') as HTMLElement;
|
this.scrollContainer = document.querySelector('swp-scrollable-content') as HTMLElement;
|
||||||
const calendarContainer = document.querySelector('swp-calendar-container');
|
const calendarContainer = document.querySelector('swp-calendar-container');
|
||||||
|
|
||||||
if (calendarContainer) {
|
if (calendarContainer) {
|
||||||
calendarContainer.addEventListener('mouseleave', () => {
|
calendarContainer.addEventListener('mouseleave', () => {
|
||||||
if (this.draggedElement && this.isDragStarted) {
|
if (this.draggedElement && this.isDragStarted) {
|
||||||
this.cancelDrag();
|
this.cancelDrag();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Event delegation for header enter/leave
|
||||||
|
calendarContainer.addEventListener('mouseenter', (e) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if (target.closest('swp-calendar-header')) {
|
||||||
|
this.handleHeaderMouseEnter(e as MouseEvent);
|
||||||
|
}
|
||||||
|
}, true); // Use capture phase
|
||||||
|
|
||||||
|
calendarContainer.addEventListener('mouseleave', (e) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if (target.closest('swp-calendar-header')) {
|
||||||
|
this.handleHeaderMouseLeave(e as MouseEvent);
|
||||||
|
}
|
||||||
|
}, true); // Use capture phase
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize column bounds cache
|
// Initialize column bounds cache
|
||||||
|
|
@ -129,18 +145,14 @@ export class DragDropManager {
|
||||||
const target = event.target as HTMLElement;
|
const target = event.target as HTMLElement;
|
||||||
let eventElement = target;
|
let eventElement = target;
|
||||||
|
|
||||||
while (eventElement && eventElement.tagName !== 'SWP-EVENTS-LAYER') {
|
while (eventElement && eventElement.tagName !== 'SWP-GRID-CONTAINER') {
|
||||||
if (eventElement.tagName === 'SWP-EVENT') {
|
if (eventElement.tagName === 'SWP-EVENT' || eventElement.tagName === 'SWP-ALLDAY-EVENT') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
eventElement = eventElement.parentElement as HTMLElement;
|
eventElement = eventElement.parentElement as HTMLElement;
|
||||||
if (!eventElement) return;
|
if (!eventElement) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we reached SWP-EVENTS-LAYER without finding an event, return
|
|
||||||
if (!eventElement || eventElement.tagName === 'SWP-EVENTS-LAYER') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found an event - prepare for potential dragging
|
// Found an event - prepare for potential dragging
|
||||||
if (eventElement) {
|
if (eventElement) {
|
||||||
|
|
@ -165,12 +177,7 @@ export class DragDropManager {
|
||||||
|
|
||||||
|
|
||||||
if (event.buttons === 1) {
|
if (event.buttons === 1) {
|
||||||
const currentPosition: MousePosition = { x: event.clientX, y: event.clientY }; //TODO: Is this really needed? why not just use event.clientX + Y directly
|
const currentPosition: MousePosition = { x: event.clientX, y: event.clientY };
|
||||||
|
|
||||||
// Check for header enter/leave during drag
|
|
||||||
if (this.draggedClone) {
|
|
||||||
this.checkHeaderEnterLeave(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we need to start drag (movement threshold)
|
// Check if we need to start drag (movement threshold)
|
||||||
if (!this.isDragStarted && this.draggedElement) {
|
if (!this.isDragStarted && this.draggedElement) {
|
||||||
|
|
@ -290,8 +297,7 @@ export class DragDropManager {
|
||||||
};
|
};
|
||||||
this.eventBus.emit('drag:end', dragEndPayload);
|
this.eventBus.emit('drag:end', dragEndPayload);
|
||||||
|
|
||||||
|
this.cleanupDragState();
|
||||||
this.draggedElement = null;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// This was just a click - emit click event instead
|
// This was just a click - emit click event instead
|
||||||
|
|
@ -477,58 +483,61 @@ export class DragDropManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for header enter/leave during drag operations
|
* Handle mouse enter on calendar header - simplified using native events
|
||||||
*/
|
*/
|
||||||
private checkHeaderEnterLeave(event: MouseEvent): void {
|
private handleHeaderMouseEnter(event: MouseEvent): void {
|
||||||
|
// Only handle if we're dragging a timed event (not all-day)
|
||||||
let position: MousePosition = { x: event.clientX, y: event.clientY };
|
if (!this.isDragStarted || !this.draggedClone) {
|
||||||
const elementAtPosition = document.elementFromPoint(event.clientX, event.clientY);
|
return;
|
||||||
if (!elementAtPosition) return;
|
}
|
||||||
|
|
||||||
const headerElement = elementAtPosition.closest('swp-day-header, swp-calendar-header');
|
|
||||||
const isCurrentlyInHeader = !!headerElement;
|
|
||||||
|
|
||||||
if (isCurrentlyInHeader && !this.draggedClone?.hasAttribute("data-allday")) {
|
|
||||||
|
|
||||||
|
const position: MousePosition = { x: event.clientX, y: event.clientY };
|
||||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
||||||
|
|
||||||
if (targetColumn) {
|
if (targetColumn) {
|
||||||
console.log('🎯 DragDropManager: Emitting drag:mouseenter-header', { targetDate: targetColumn });
|
console.log('🎯 DragDropManager: Mouse entered header', { targetDate: targetColumn });
|
||||||
|
|
||||||
// Extract CalendarEvent from the dragged clone
|
// Extract CalendarEvent from the dragged clone
|
||||||
const calendarEvent = SwpEventElement.extractCalendarEventFromElement(this.draggedClone!!);
|
const calendarEvent = SwpEventElement.extractCalendarEventFromElement(this.draggedClone);
|
||||||
|
|
||||||
|
const allDayElement = SwpAllDayEventElement.fromCalendarEvent(payload.calendarEvent);
|
||||||
|
|
||||||
const dragMouseEnterPayload: DragMouseEnterHeaderEventPayload = {
|
const dragMouseEnterPayload: DragMouseEnterHeaderEventPayload = {
|
||||||
targetColumn: targetColumn,
|
targetColumn: targetColumn,
|
||||||
mousePosition: { x: event.clientX, y: event.clientY },
|
mousePosition: position,
|
||||||
originalElement: this.draggedElement,
|
originalElement: this.draggedElement,
|
||||||
draggedClone: this.draggedClone!!,
|
draggedClone: this.draggedClone,
|
||||||
calendarEvent: calendarEvent
|
calendarEvent: calendarEvent
|
||||||
};
|
};
|
||||||
this.eventBus.emit('drag:mouseenter-header', dragMouseEnterPayload);
|
this.eventBus.emit('drag:mouseenter-header', dragMouseEnterPayload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect header leave
|
/**
|
||||||
if (isCurrentlyInHeader && this.draggedClone?.hasAttribute("data-allday")) {
|
* Handle mouse leave from calendar header - simplified using native events
|
||||||
|
*/
|
||||||
console.log('🚪 DragDropManager: Emitting drag:mouseleave-header');
|
private handleHeaderMouseLeave(event: MouseEvent): void {
|
||||||
|
// Only handle if we're dragging an all-day event
|
||||||
// Calculate target date using existing method
|
if (!this.isDragStarted || !this.draggedClone || !this.draggedClone.hasAttribute("data-allday")) {
|
||||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
|
||||||
if (!targetColumn) {
|
|
||||||
console.warn("No column detected, unknown reason");
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🚪 DragDropManager: Mouse left header');
|
||||||
|
|
||||||
|
const position: MousePosition = { x: event.clientX, y: event.clientY };
|
||||||
|
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
||||||
|
|
||||||
|
if (!targetColumn) {
|
||||||
|
console.warn("No column detected when leaving header");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragMouseLeavePayload: DragMouseLeaveHeaderEventPayload = {
|
const dragMouseLeavePayload: DragMouseLeaveHeaderEventPayload = {
|
||||||
targetDate: targetColumn.date,
|
targetDate: targetColumn.date,
|
||||||
mousePosition: { x: event.clientX, y: event.clientY },
|
mousePosition: position,
|
||||||
originalElement: this.draggedElement,
|
originalElement: this.draggedElement,
|
||||||
draggedClone: this.draggedClone
|
draggedClone: this.draggedClone
|
||||||
};
|
};
|
||||||
this.eventBus.emit('drag:mouseleave-header', dragMouseLeavePayload);
|
this.eventBus.emit('drag:mouseleave-header', dragMouseLeavePayload);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue