Improves drag and drop for timed and all-day events
Refactors drag and drop handling to use a cloned event element, ensuring correct positioning and styling during drag operations for both regular timed events and all-day events. This change streamlines the drag and drop process by: - Creating a clone of the dragged event at the start of the drag. - Passing the clone through the drag events. - Handling all-day events with the AllDayManager - Handling regular timed events with the EventRendererManager This resolves issues with event positioning and styling during drag, especially when moving events across columns or between all-day and timed sections.
This commit is contained in:
parent
0553089085
commit
9dfd4574d8
5 changed files with 62 additions and 45 deletions
|
|
@ -65,7 +65,7 @@ export class AllDayManager {
|
||||||
|
|
||||||
// Listen for drag operations on all-day events
|
// Listen for drag operations on all-day events
|
||||||
eventBus.on('drag:start', (event) => {
|
eventBus.on('drag:start', (event) => {
|
||||||
const { draggedElement, mouseOffset } = (event as CustomEvent<DragStartEventPayload>).detail;
|
const { draggedElement, draggedClone, mouseOffset } = (event as CustomEvent<DragStartEventPayload>).detail;
|
||||||
|
|
||||||
// Check if this is an all-day event by checking if it's in all-day container
|
// Check if this is an all-day event by checking if it's in all-day container
|
||||||
const isAllDayEvent = draggedElement.closest('swp-allday-container');
|
const isAllDayEvent = draggedElement.closest('swp-allday-container');
|
||||||
|
|
@ -77,26 +77,22 @@ export class AllDayManager {
|
||||||
});
|
});
|
||||||
|
|
||||||
eventBus.on('drag:column-change', (event) => {
|
eventBus.on('drag:column-change', (event) => {
|
||||||
const { draggedElement, mousePosition } = (event as CustomEvent<DragColumnChangeEventPayload>).detail;
|
const { draggedElement, draggedClone, mousePosition } = (event as CustomEvent<DragColumnChangeEventPayload>).detail;
|
||||||
|
|
||||||
|
if(draggedClone == null)
|
||||||
// Check if there's an all-day clone for this event
|
|
||||||
const eventId = draggedElement.dataset.eventId;
|
|
||||||
const dragClone = document.querySelector(`swp-allday-container swp-event[data-event-id="clone-${eventId}"]`) as HTMLElement;
|
|
||||||
|
|
||||||
if (!dragClone.hasAttribute('data-allday')) {
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Filter: Only handle events where clone IS an all-day event
|
||||||
|
if (!draggedClone.hasAttribute('data-allday')) {
|
||||||
|
return; // This is not an all-day event, let EventRendererManager handle it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('🔄 AllDayManager: Handling drag:column-change for all-day event', {
|
||||||
// If we find an all-day clone, handle the drag move
|
eventId : draggedElement.dataset.eventId,
|
||||||
if (dragClone) {
|
cloneId: draggedClone.dataset.eventId
|
||||||
console.log('🔄 AllDayManager: Found all-day clone, handling drag:column-change', {
|
|
||||||
eventId,
|
|
||||||
cloneId: dragClone.dataset.eventId
|
|
||||||
});
|
});
|
||||||
this.handleColumnChange(dragClone, mousePosition);
|
|
||||||
}
|
this.handleColumnChange(draggedClone, mousePosition);
|
||||||
});
|
});
|
||||||
|
|
||||||
eventBus.on('drag:end', (event) => {
|
eventBus.on('drag:end', (event) => {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { IEventBus } from '../types/CalendarTypes';
|
||||||
import { calendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
import { PositionUtils } from '../utils/PositionUtils';
|
import { PositionUtils } from '../utils/PositionUtils';
|
||||||
import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
|
import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils';
|
||||||
|
import { SwpEventElement } from '../elements/SwpEventElement';
|
||||||
import {
|
import {
|
||||||
DragStartEventPayload,
|
DragStartEventPayload,
|
||||||
DragMoveEventPayload,
|
DragMoveEventPayload,
|
||||||
|
|
@ -40,6 +41,7 @@ export class DragDropManager {
|
||||||
|
|
||||||
// Drag state
|
// Drag state
|
||||||
private draggedElement!: HTMLElement | null;
|
private draggedElement!: HTMLElement | null;
|
||||||
|
private draggedClone!: HTMLElement | null;
|
||||||
private currentColumn: string | null = null;
|
private currentColumn: string | null = null;
|
||||||
private isDragStarted = false;
|
private isDragStarted = false;
|
||||||
|
|
||||||
|
|
@ -198,8 +200,17 @@ export class DragDropManager {
|
||||||
// Start drag - emit drag:start event
|
// Start drag - emit drag:start event
|
||||||
this.isDragStarted = true;
|
this.isDragStarted = true;
|
||||||
|
|
||||||
|
// Create SwpEventElement from existing DOM element and clone it
|
||||||
|
const originalSwpEvent = SwpEventElement.fromExistingElement(this.draggedElement);
|
||||||
|
const clonedSwpEvent = originalSwpEvent.createClone();
|
||||||
|
|
||||||
|
// Get the cloned DOM element
|
||||||
|
this.draggedClone = clonedSwpEvent.getElement();
|
||||||
|
|
||||||
|
|
||||||
const dragStartPayload: DragStartEventPayload = {
|
const dragStartPayload: DragStartEventPayload = {
|
||||||
draggedElement: this.draggedElement,
|
draggedElement: this.draggedElement,
|
||||||
|
draggedClone: this.draggedClone,
|
||||||
mousePosition: this.initialMousePosition,
|
mousePosition: this.initialMousePosition,
|
||||||
mouseOffset: this.mouseOffset,
|
mouseOffset: this.mouseOffset,
|
||||||
column: this.currentColumn
|
column: this.currentColumn
|
||||||
|
|
@ -244,6 +255,7 @@ export class DragDropManager {
|
||||||
|
|
||||||
const dragColumnChangePayload: DragColumnChangeEventPayload = {
|
const dragColumnChangePayload: DragColumnChangeEventPayload = {
|
||||||
draggedElement: this.draggedElement,
|
draggedElement: this.draggedElement,
|
||||||
|
draggedClone: this.draggedClone,
|
||||||
previousColumn,
|
previousColumn,
|
||||||
newColumn,
|
newColumn,
|
||||||
mousePosition: currentPosition
|
mousePosition: currentPosition
|
||||||
|
|
@ -514,6 +526,7 @@ export class DragDropManager {
|
||||||
*/
|
*/
|
||||||
private cleanupDragState(): void {
|
private cleanupDragState(): void {
|
||||||
this.draggedElement = null;
|
this.draggedElement = null;
|
||||||
|
this.draggedClone = null;
|
||||||
this.currentColumn = null;
|
this.currentColumn = null;
|
||||||
this.isDragStarted = false;
|
this.isDragStarted = false;
|
||||||
this.isInHeader = false;
|
this.isInHeader = false;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import { DragOffset, StackLinkData } from '../types/DragDropTypes';
|
||||||
export interface EventRendererStrategy {
|
export interface EventRendererStrategy {
|
||||||
renderEvents(events: CalendarEvent[], container: HTMLElement): void;
|
renderEvents(events: CalendarEvent[], container: HTMLElement): void;
|
||||||
clearEvents(container?: HTMLElement): void;
|
clearEvents(container?: HTMLElement): void;
|
||||||
handleDragStart?(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset, column: string): void;
|
handleDragStart?(payload: import('../types/EventTypes').DragStartEventPayload): void;
|
||||||
handleDragMove?(eventId: string, snappedY: number, column: string, mouseOffset: DragOffset): void;
|
handleDragMove?(eventId: string, snappedY: number, column: string, mouseOffset: DragOffset): void;
|
||||||
handleDragAutoScroll?(eventId: string, snappedY: number): 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: string, finalY: number): void;
|
||||||
|
|
@ -160,18 +160,18 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
/**
|
/**
|
||||||
* Handle drag start event
|
* Handle drag start event
|
||||||
*/
|
*/
|
||||||
public handleDragStart(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset, column: string): void {
|
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;
|
this.originalEvent = originalElement;
|
||||||
|
|
||||||
// Remove stacking styling during drag will be handled by new system
|
// Use the clone from the payload instead of creating a new one
|
||||||
|
this.draggedClone = payload.draggedClone;
|
||||||
// Create SwpEventElement from existing DOM element and clone it
|
|
||||||
const originalSwpEvent = SwpEventElement.fromExistingElement(originalElement);
|
|
||||||
const clonedSwpEvent = originalSwpEvent.createClone();
|
|
||||||
|
|
||||||
// Get the cloned DOM element
|
|
||||||
this.draggedClone = clonedSwpEvent.getElement();
|
|
||||||
|
|
||||||
|
if (this.draggedClone) {
|
||||||
// Apply drag styling
|
// Apply drag styling
|
||||||
this.applyDragStyling(this.draggedClone);
|
this.applyDragStyling(this.draggedClone);
|
||||||
|
|
||||||
|
|
@ -186,6 +186,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
columnElement.appendChild(this.draggedClone);
|
columnElement.appendChild(this.draggedClone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make original semi-transparent
|
// Make original semi-transparent
|
||||||
originalElement.style.opacity = '0.3';
|
originalElement.style.opacity = '0.3';
|
||||||
|
|
|
||||||
|
|
@ -179,11 +179,10 @@ export class EventRenderingService {
|
||||||
private setupDragEventListeners(): void {
|
private setupDragEventListeners(): void {
|
||||||
// Handle drag start
|
// Handle drag start
|
||||||
this.eventBus.on('drag:start', (event: Event) => {
|
this.eventBus.on('drag:start', (event: Event) => {
|
||||||
const { draggedElement, mouseOffset, column } = (event as CustomEvent<DragStartEventPayload>).detail;
|
const dragStartPayload = (event as CustomEvent<DragStartEventPayload>).detail;
|
||||||
// Use the draggedElement directly - no need for DOM query
|
// Use the draggedElement directly - no need for DOM query
|
||||||
if (draggedElement && this.strategy.handleDragStart && column) {
|
if (dragStartPayload.draggedElement && this.strategy.handleDragStart && dragStartPayload.column) {
|
||||||
const eventId = draggedElement.dataset.eventId || '';
|
this.strategy.handleDragStart(dragStartPayload);
|
||||||
this.strategy.handleDragStart(draggedElement, eventId, mouseOffset, column);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -246,10 +245,16 @@ export class EventRenderingService {
|
||||||
|
|
||||||
// Handle column change
|
// Handle column change
|
||||||
this.eventBus.on('drag:column-change', (event: Event) => {
|
this.eventBus.on('drag:column-change', (event: Event) => {
|
||||||
const { draggedElement, newColumn } = (event as CustomEvent<DragColumnChangeEventPayload>).detail;
|
const { draggedElement, draggedClone, newColumn } = (event as CustomEvent<DragColumnChangeEventPayload>).detail;
|
||||||
|
|
||||||
|
// Filter: Only handle events where clone is NOT an all-day event (normal timed events)
|
||||||
|
if (draggedClone && draggedClone.hasAttribute('data-allday')) {
|
||||||
|
return; // This is an all-day event, let AllDayManager handle it
|
||||||
|
}
|
||||||
|
|
||||||
if (this.strategy.handleColumnChange) {
|
if (this.strategy.handleColumnChange) {
|
||||||
const eventId = draggedElement.dataset.eventId || '';
|
const eventId = draggedElement.dataset.eventId || '';
|
||||||
this.strategy.handleColumnChange(eventId, newColumn);
|
this.strategy.handleColumnChange(eventId, newColumn); //TODO: Should be refactored to use payload, no need to lookup clone again inside
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ export interface MousePosition {
|
||||||
// Drag start event payload
|
// Drag start event payload
|
||||||
export interface DragStartEventPayload {
|
export interface DragStartEventPayload {
|
||||||
draggedElement: HTMLElement;
|
draggedElement: HTMLElement;
|
||||||
|
draggedClone: HTMLElement | null;
|
||||||
mousePosition: MousePosition;
|
mousePosition: MousePosition;
|
||||||
mouseOffset: MousePosition;
|
mouseOffset: MousePosition;
|
||||||
column: string | null;
|
column: string | null;
|
||||||
|
|
@ -90,6 +91,7 @@ export interface DragMouseLeaveHeaderEventPayload {
|
||||||
// Drag column change event payload
|
// Drag column change event payload
|
||||||
export interface DragColumnChangeEventPayload {
|
export interface DragColumnChangeEventPayload {
|
||||||
draggedElement: HTMLElement;
|
draggedElement: HTMLElement;
|
||||||
|
draggedClone: HTMLElement | null;
|
||||||
previousColumn: string | null;
|
previousColumn: string | null;
|
||||||
newColumn: string;
|
newColumn: string;
|
||||||
mousePosition: MousePosition;
|
mousePosition: MousePosition;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue