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;
|
||||
const calendarContainer = document.querySelector('swp-calendar-container');
|
||||
|
||||
if (calendarContainer) {
|
||||
calendarContainer.addEventListener('mouseleave', () => {
|
||||
if (this.draggedElement && this.isDragStarted) {
|
||||
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
|
||||
|
|
@ -129,18 +145,14 @@ export class DragDropManager {
|
|||
const target = event.target as HTMLElement;
|
||||
let eventElement = target;
|
||||
|
||||
while (eventElement && eventElement.tagName !== 'SWP-EVENTS-LAYER') {
|
||||
if (eventElement.tagName === 'SWP-EVENT') {
|
||||
while (eventElement && eventElement.tagName !== 'SWP-GRID-CONTAINER') {
|
||||
if (eventElement.tagName === 'SWP-EVENT' || eventElement.tagName === 'SWP-ALLDAY-EVENT') {
|
||||
break;
|
||||
}
|
||||
eventElement = eventElement.parentElement as HTMLElement;
|
||||
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
|
||||
if (eventElement) {
|
||||
|
|
@ -165,12 +177,7 @@ export class DragDropManager {
|
|||
|
||||
|
||||
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
|
||||
|
||||
// Check for header enter/leave during drag
|
||||
if (this.draggedClone) {
|
||||
this.checkHeaderEnterLeave(event);
|
||||
}
|
||||
const currentPosition: MousePosition = { x: event.clientX, y: event.clientY };
|
||||
|
||||
// Check if we need to start drag (movement threshold)
|
||||
if (!this.isDragStarted && this.draggedElement) {
|
||||
|
|
@ -290,8 +297,7 @@ export class DragDropManager {
|
|||
};
|
||||
this.eventBus.emit('drag:end', dragEndPayload);
|
||||
|
||||
|
||||
this.draggedElement = null;
|
||||
this.cleanupDragState();
|
||||
|
||||
} else {
|
||||
// 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 {
|
||||
|
||||
let position: MousePosition = { x: event.clientX, y: event.clientY };
|
||||
const elementAtPosition = document.elementFromPoint(event.clientX, event.clientY);
|
||||
if (!elementAtPosition) return;
|
||||
|
||||
const headerElement = elementAtPosition.closest('swp-day-header, swp-calendar-header');
|
||||
const isCurrentlyInHeader = !!headerElement;
|
||||
|
||||
if (isCurrentlyInHeader && !this.draggedClone?.hasAttribute("data-allday")) {
|
||||
|
||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
||||
|
||||
if (targetColumn) {
|
||||
console.log('🎯 DragDropManager: Emitting drag:mouseenter-header', { targetDate: targetColumn });
|
||||
|
||||
// Extract CalendarEvent from the dragged clone
|
||||
const calendarEvent = SwpEventElement.extractCalendarEventFromElement(this.draggedClone!!);
|
||||
|
||||
const dragMouseEnterPayload: DragMouseEnterHeaderEventPayload = {
|
||||
targetColumn: targetColumn,
|
||||
mousePosition: { x: event.clientX, y: event.clientY },
|
||||
originalElement: this.draggedElement,
|
||||
draggedClone: this.draggedClone!!,
|
||||
calendarEvent: calendarEvent
|
||||
};
|
||||
this.eventBus.emit('drag:mouseenter-header', dragMouseEnterPayload);
|
||||
}
|
||||
private handleHeaderMouseEnter(event: MouseEvent): void {
|
||||
// Only handle if we're dragging a timed event (not all-day)
|
||||
if (!this.isDragStarted || !this.draggedClone) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect header leave
|
||||
if (isCurrentlyInHeader && this.draggedClone?.hasAttribute("data-allday")) {
|
||||
const position: MousePosition = { x: event.clientX, y: event.clientY };
|
||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
||||
|
||||
console.log('🚪 DragDropManager: Emitting drag:mouseleave-header');
|
||||
if (targetColumn) {
|
||||
console.log('🎯 DragDropManager: Mouse entered header', { targetDate: targetColumn });
|
||||
|
||||
// Calculate target date using existing method
|
||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
||||
if (!targetColumn) {
|
||||
console.warn("No column detected, unknown reason");
|
||||
return;
|
||||
// Extract CalendarEvent from the dragged clone
|
||||
const calendarEvent = SwpEventElement.extractCalendarEventFromElement(this.draggedClone);
|
||||
|
||||
}
|
||||
const allDayElement = SwpAllDayEventElement.fromCalendarEvent(payload.calendarEvent);
|
||||
|
||||
const dragMouseLeavePayload: DragMouseLeaveHeaderEventPayload = {
|
||||
targetDate: targetColumn.date,
|
||||
mousePosition: { x: event.clientX, y: event.clientY },
|
||||
const dragMouseEnterPayload: DragMouseEnterHeaderEventPayload = {
|
||||
targetColumn: targetColumn,
|
||||
mousePosition: position,
|
||||
originalElement: this.draggedElement,
|
||||
draggedClone: this.draggedClone
|
||||
draggedClone: this.draggedClone,
|
||||
calendarEvent: calendarEvent
|
||||
};
|
||||
this.eventBus.emit('drag:mouseleave-header', dragMouseLeavePayload);
|
||||
this.eventBus.emit('drag:mouseenter-header', dragMouseEnterPayload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse leave from calendar header - simplified using native events
|
||||
*/
|
||||
private handleHeaderMouseLeave(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 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 = {
|
||||
targetDate: targetColumn.date,
|
||||
mousePosition: position,
|
||||
originalElement: this.draggedElement,
|
||||
draggedClone: this.draggedClone
|
||||
};
|
||||
this.eventBus.emit('drag:mouseleave-header', dragMouseLeavePayload);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue